30C3 CTFに参加しました
30C3 CTF(https://30c3ctf.aachen.ccc.de/)にチーム0x0で参加しました。
個人的にはELFバイナリが全部64bitだったのがつらかったです。急遽VirtualboxにUbuntu Server(64bit)を突っ込みました。
以下Write upっぽいものです。
fourier(NUMBERS 200)
fourier.tar.gzを解凍するとfourierというELFと、flag.fourというテキストファイルがでてきます。flag.fourはフラグをfourierで暗号化したものです。ということでfourierの逆アセンブルを読んだところ、どうやらGMP(The GNU Multiple Precision Arithmetic Library)という多倍長演算のライブラリを使って書いてあるようでした。関数の内容はhttps://gmplib.org/manual/Function-Index.htmlとかを見ればOKです。アセンブリを読むとだいたい次のような内容でした。
v10 = 0; while(まだファイルが残っている) { v10 << 8;//多倍長演算 v10 += <ファイルから1バイト読む>; } while(24 <= v10) { v30 = 0; v40 = 0; v40 = v10 - 4; v40 *= 4; v40 -= 5; if(0x444 < v40) v40 = 0x444; v30 = <0〜v40までの乱数>; v30 += 5; //v30と同じ数だけ4を出力する v20 = 0; while(v20 != v30) { ++v20; <'4'をファイルに出力>; } <' 'をファイルに出力>; v50 = 0; v20 = 4; while(v20 <= v10) { <'4'をファイルに出力>; v20 <-> v50;//スワップ v20 = v50 * v30; v20 += 4; } v10 -= v50; <' 'をファイルに出力>; } //v10と同じ数だけ4を出力 while(v10 != 0) { --v10; <'4'をファイルに出力>; }
最初にv10にファイルの内容を読み込んでいます。つまり、最初のv10がわかればファイルが復元できるわけです。最後のv10の値は暗号文の最後の4の数を見ればわかります。メインループの中でv10が変更されているのはv50を引いているところだけなので、メインループの繰り返しごとのv50の値がわかればv10が復元できます。v50の値はv10とv30の値にのみ依存していますが、v30は上の方のループでの4の数と同じです。v30の値と、下の方のループの繰り返し回数(これは4の数と同じです)がわかれば、v50の値がわかるのでv10の値はわからなくてもよいです。
これでflagが復元できます。
以下rubyで書いたやつ。各行に4の数を書いたテキストを食わせるとフラグが出ます。
#!/usr/bin/ruby list = [] while line = STDIN.gets list.push(line.to_i) end list = list.reverse v10 = list.shift while list.length != 0 l = list.shift r = list.shift v50 = 0 l.times do v50 = 4 + v50 * r end v10 += v50 end res = [] while v10 != 0 res.push(v10 % 256) v10 /= 256 end res = res.reverse flag = [] res.length.times do |i| flag.push(res[i].chr) end puts flag.join
DOGE1(PWN 100)
犬に名前をつけて餌を与えたりするサーバです。
途中、同じディレクトリにあるascii_art_doge_color.txtを読むなどの動作をします。
手元で動かして犬の名前に長い文字列を突っ込んだら
No such file or directoryってなったので、
echo -en '12345678901234567890123456789012/etc/passwd\x00'
をncに渡して終了。ユーザーdogeのパスワードが答えです。
zshだとechoに-eオプション付けなくても動きます。
angler(NUMBERS 300)
これも暗号化プログラムと暗号文(バイナリ)がセットになってるやつでした。
暗号化プログラムはErlangで書かれていたのでソースコードを読むだけでOKでしたが、
Erlangは今まで触ったことがなかったのでそのへんの入門記事を読みながらやりました。
Erlangはバイナリパターンマッチングができるのが面白いです。
剰余のあたりが偶奇反転(バグ?)してるような気がしましたがよくわかりませんでした。
とりあえず動いたのでよしとします。
xxd -p sniffed_message | nkf -f2-0 | head -n -1 | xargs -I{} printf "%d\n" 0x{}
してから、以下のrubyで書いたやつに突っ込みました。
#!/usr/bin/ruby $prod = [] 256.times do |i| $prod.push((i * 0x41 + 7) % 256) end def prod2index(v) index = 0 for element in $prod if element == v return index end index += 1 end return -1 end def rotate(i) i.times do t = $prod.shift $prod.push(t) end end list = [] while line = STDIN.gets list.push(line.to_i) end output = [] (list.length / 2).times do i1 = list.shift; i2 = list.shift; output.unshift(i2); output.unshift(i1); end for o in output i = prod2index(o) print i.chr if i % 2 == 0 rotate(256 - i) elsif rotate(i) end end