Internetwache CTF 2016 writeup
TSG (東京大学理論科学グループ) のメンバーに誘われたので、2月20日から22日にかけて、チームTSGの一員として Internetwache CTF 2016 に参加した。
参加して初めて知ったがどうやらガチ初心者向けのCTFであるらしく(CSAWよりも簡単な印象)、メンバーがほいほい解いていくので僕の出番はほとんどなかったと言っていい。が、この広いインターネットで誰かの役に立つかもしれないので、いちおう一通りWriteupを書いてみる。
すでに書かれた他のメンバーのWriteupは以下を参照。
ちなみにチームTSGは2問を残して全完し、1492チーム中45位だった。
以下、解いた順。
misc50
こんなテキストファイルが与えられる。
0000000 126 062 126 163 142 103 102 153 142 062 065 154 111 121 157 113 0000020 122 155 170 150 132 172 157 147 123 126 144 067 124 152 102 146 0000040 115 107 065 154 130 062 116 150 142 154 071 172 144 104 102 167 0000060 130 063 153 167 144 130 060 113 012 0000071
これを8進数としてデコードしたあとASCIIコードとして復号する。
V2VsbCBkb25lIQoKRmxhZzogSVd7TjBfMG5lX2Nhbl9zdDBwX3kwdX0K
これをBase64でデコードする。
Well done! Flag: IW{N0_0ne_can_st0p_y0u}
おしまい。
スクリプト
$ lsc -d ls> require \fs .read-file-sync \README.txt |> (.to-string! / /\s/) |> filter (.length is 3) |> map parse-int _, 8 |> map String.from-code-point |> join '' |> Buffer _, \base64 |> (.to-string!) |> console.log Well done! Flag: IW{N0_0ne_can_st0p_y0u}
misc90
こんな画像が与えられる。
この時点で既に殺意しか湧かない。
Photoshopでぐりぐりいじって元のバーコードを復元する。
スマホのバーコードリーダーで読み取ると、上から順に C0d3s}
, _B4r_
, IW{Bar
となる。
Flag: IW{Bar_B4r_C0d3s}
web80
こんな文章とURLが与えられる。
I stumbled across this kinda oldskool blog. I bet it is unhackable, I mean, there's only static HTML. https://0ldsk00lblog.ctf.internetwache.org/
static HTML と言われたら .git
を確認するしかない。 https://0ldsk00lblog.ctf.internetwache.org/.git/config にアクセスすると、
[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true
と表示されビンゴ。dvcs-ripper でまるっと落としてくる。
コミットログを見てみるとこの通り。
$ git show HEAD commit 8c46583a968da7955c13559693b3b8c5e5d5f510 Author: Sebastian Gehaxelt <github@gehaxelt.in> Date: Fri Jan 22 02:58:01 2016 +0100 My recent blogpost diff --git a/index.html b/index.html index 5508adb..25a3f35 100644 --- a/index.html +++ b/index.html @@ -3,9 +3,15 @@ <title>0ldsk00l</title> </head> <body> - <h2>2000</h2> + + <h1>Welcome to my 0ldsk00l blog.</h1> + <p> + Now this is some oldskool classic shit. Writing your blog manually without all this crappy bling-bling CSS / JS stuff. + </p> + + <h2>2016</h2> <p> - Oh, did I say that I like kittens? I like flags, too: IW{G1T_1S_4W3SOME} + It's 2016 now and I need to somehow keep track of my changes to this document as it grows and grows. All people are talking about a tool called 'Git'. I think I might give this a try. </p> <h2>1990-2015</h2>
Flag: IW{G1T_1S_4W3SOME}
cry60
こんな公開鍵が3つと、
-----BEGIN PUBLIC KEY----- MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdDVZLl4+dIzUElY7ti3RDcyge0UGLKfHs +oCT2M8CAwEAAQ== -----END PUBLIC KEY-----
こんな暗号文が与えられる。
DK9dt2MTybMqRz/N2RUMq2qauvqFIOnQ89mLjXY= AK/WPYsK5ECFsupuW98bCFKYUApgrQ6LTcm3KxY= CiLSeTUCCKkyNf8NVnifGKKS2FJ7VnWKnEdygXY=
公開鍵がえらく短い。中身を見てみると、
$ openssl pkey -in bob.pub -pubin -text -----BEGIN PUBLIC KEY----- MDgwDQYJKoZIhvcNAQEBBQADJwAwJAIdDVZLl4+dIzUElY7ti3RDcyge0UGLKfHs +oCT2M8CAwEAAQ== -----END PUBLIC KEY----- Public-Key: (228 bit) Modulus: 0d:56:4b:97:8f:9d:23:35:04:95:8e:ed:8b:74:43: 73:28:1e:d1:41:8b:29:f1:ec:fa:80:93:d8:cf Exponent: 65537 (0x10001)
鍵長 228bit である。これなら変なテクニックを使わずとも力技で因数分解できる。
$ sage ┌────────────────────────────────────────────────────────────────────┐ │ SageMath Version 7.0, Release Date: 2016-01-19 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ WARNING: Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv. sage: factor(0x0d564b978f9d233504958eed8b744373281ed1418b29f1ecfa8093d8cf) 17963604736595708916714953362445519 * 20016431322579245244930631426505729 sage: e = 0x10001 sage: p = 17963604736595708916714953362445519 sage: q = 20016431322579245244930631426505729 sage: from base64 import b64decode sage: c = int(b64decode('DK9dt2MTybMqRz/N2RUMq2qauvqFIOnQ89mLjXY=').encode('hex'), 16) sage: d = inverse_mod(e, (p - 1) * (q - 1)) sage: m = pow(c, d, p * q) sage: ('0' + format(int(m), 'x')).decode('hex') '\x02\x99\xa0\xc1\xe2I\x90~\x87z\xc9\xc0\x88\xda\xaf8\xd0\x00IW{WEAK_R\n'
フラグの一部が見える。同じようにbob2.pubとbob3.pubも因数分解して復号したが、bob.pubと違ってまともな文字列にならない。これでしばらく悩んだが、あれこれ試してみたところ、どうもbob2.pubが3番目の暗号文に、bob3.pubが2番目の暗号文に対応してるようだった。なんじゃそりゃ。
2番目と3番目の復号後の文字列は以下のとおり。
'\x02\xa1\x06\xc7\x8c\xeaa\x90\x9aNyj\xc0\xfaVa\x00SA_K3YS_4R\n' '\x02o\x03\x0e\xc9ba\x8e\xf65\x99\xbe\xe7\x80\x1a\xe3\x003_SO_BAD!}\n'
Flag: IW{WEAK_RSA_K3YS_4R3_SO_BAD!}
cry80
謎の踊る男のPV動画が与えられる。
とりあえず中身を見てみる。
$ ffprobe song.webm ffprobe version 2.5.2 Copyright (c) 2007-2014 the FFmpeg developers built on Dec 30 2014 17:29:04 with gcc 4.9.2 (GCC) configuration: --disable-static --enable-shared --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --enable-decklink --enable-zlib libavutil 54. 15.100 / 54. 15.100 libavcodec 56. 13.100 / 56. 13.100 libavformat 56. 15.102 / 56. 15.102 libavdevice 56. 3.100 / 56. 3.100 libavfilter 5. 2.103 / 5. 2.103 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 1.100 / 1. 1.100 libpostproc 53. 3.100 / 53. 3.100 Input #0, matroska,webm, from 'song.webm': Metadata: encoder : Lavf56.40.101 Duration: 00:00:36.04, start: 0.000000, bitrate: 520 kb/s Stream #0:0: Video: vp8, yuv420p, 320x240, SAR 1:1 DAR 4:3, 1k fps, 30 tbr, 1k tbn, 1k tbc (default) Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp (default) Stream #0:2: Audio: vorbis, 8000 Hz, mono, fltp
副音声があるので取り出して聞いてみる。
$ ffmpeg -i song.webm -map 0:2 out.wav ffmpeg version N-50911-g9efcfbe Copyright (c) 2000-2013 the FFmpeg developers built on Mar 13 2013 21:26:48 with gcc 4.7.2 (GCC) configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable-libgsm --enable-libilbc --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid --enable-zlib libavutil 52. 19.100 / 52. 19.100 libavcodec 55. 0.100 / 55. 0.100 libavformat 55. 0.100 / 55. 0.100 libavdevice 54. 4.100 / 54. 4.100 libavfilter 3. 45.103 / 3. 45.103 libswscale 2. 2.100 / 2. 2.100 libswresample 0. 17.102 / 0. 17.102 libpostproc 52. 2.100 / 52. 2.100 Input #0, matroska,webm, from 'song.webm': Duration: 00:00:36.04, start: 0.000000, bitrate: 520 kb/s Stream #0:0: Video: vp8, yuv420p, 320x240, SAR 1:1 DAR 4:3, 1k fps, 1k tbr, 1k tbn, 1k tbc (default) Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp (default) Stream #0:2: Audio: vorbis, 8000 Hz, mono, fltp Output #0, wav, to 'out.wav': Metadata: ISFT : Lavf55.0.100 Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 8000 Hz, mono, s16, 128 kb/s Stream mapping: Stream #0:2 -> #0:0 (vorbis -> pcm_s16le) Press [q] to stop, [?] for help size= 560kB time=00:00:35.84 bitrate= 127.9kbits/s video:0kB audio:560kB subtitle:0 global headers:0kB muxing overhead 0.013963%
ダイヤル音が聞こえる。DTMFである。Audacityでスペクトログラムを見ながら元の番号に復号する。
軽く苦行だ。元の番号に戻すとこうなる。
0111 0127 0173 0104 0122 060 0116 063 0123 0137 0127 061 0124 0110 0137 0120 0110 060 0116 063 0123 0175
また8進数だ。8進数としてデコードしたあとASCIIコードとして復号する。
IW{DR0N3S_W1TH_PH0N3S}
思うにこれはcryptoではなくstegoではないだろうか。
スクリプト
$ lsc -d ls> '0111 0127 0173 0104 0122 060 0116 063 0123 0137 0127 061 0124 0110 0137 0120 0110 060 0116 063 0123 0175' |> split ' ' |> map parse-int _, 8 |> map String.from-code-point |> join '' 'IW{DR0N3S_W1TH_PH0N3S}'
misc60
こんな感じのテキストファイルが降ってくる。
4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI 4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI4paI 4paI4paI4paI4paI4paI4paI4paI4paICuKWiOKWiCAgICAgICAgICAgICAg4paI4paIICDiloji loggIOKWiOKWiCAg4paI4paIICAgICAgICAgICAgICDilojilogK4paI4paIICDilojilojiloji lojilojilojilojilojilojiloggIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCAg4paI 4paIICDilojilojilojilojilojilojilojilojilojiloggIOKWiOKWiArilojiloggIOKWiOKW iCAgICAgIOKWiOKWiCAg4paI4paIICDilojilojilojiloggICAg4paI4paIICDilojiloggICAg ICDilojiloggIOKWiOKWiArilojiloggIOKWiOKWiCAgICAgIOKWiOKWiCAg4paI4paI4paI4paI 4paI4paI4paI4paI4paI4paIICDilojiloggIOKWiOKWiCAgICAgIOKWiOKWiCAg4paI4paICuKW iOKWiCAg4paI4paIICAgICAg4paI4paIICDilojiloggIOKWiOKWiOKWiOKWiCAg4paI4paI4paI (略)
アナログな方法だが、これを一枚ずつ根気よくスマホのバーコードリーダーで読み取っていく。するとこうなる。
Flagis:IW{QR_C0DES_RUL3}
スクリプト
$ lsc -d ls> require \fs .read-file-sync \README.txt |> (.to-string!) |> split '\n' |> map(-> if it.length is 76 then it else it + ',') |> join '' |> split ',' |> map Buffer _, \base64 |> map (.to-string!) |> each console.log ██████████████████████████████████████████████ ██ ██ ██ ██ ██ ██ ██ ██████████ ██████████ ██ ██████████ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██████████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██████████ ████ ██ ██ ██████████ ██ (略)