読者です 読者をやめる 読者になる 読者になる

ブログ未満のなにか

ブログなのか誰にも分からない

SECCON2016 大阪大会 writeup

はじめに

バイナリ早食い大会で、バイナリ総数が2万を超えていた。
SECCON最多らしいでの、歴史に立ち会えた感じがする。

今回は、tuat_mccで参加した。
結果は2位で、まぁまぁ良かったかなと。
しかし、2位でも1位の半分以下しか点数が取れなかったので、圧倒的実力差があった。辛い

f:id:hama7230:20161003154300j:plain

問題内容

問題サーバは、下記の4つ(競技説明のスライドから抜粋)。
バックドアを探せは、入力された文字列と内部で処理された文字列を比較していくもので、一致していればフラグを得られる。
スタックオーバーフローは、フラグを出力する関数があるので、BOFしてリターンアドレスをフラグ出力関数に書き換えれば良いというもの。
easyとhardの差は、難読化がされているかどうか。

– 10.0.1.2:10000
● バックドアを探せ(easy, 5分毎にバイナリ更新, 全36バイナリ)
– 10.0.1.2:20000
● バックドアを探せ(hard, 1秒毎にバイナリ更新, 全10,800バイナリ)
– 10.0.1.2:30000
● スタックバッファオーバーフローで制御を奪え(easy, 5分毎にバイナリ更新, 全36バイナリ)
– 10.0.1.2:40000
● スタックバッファオーバーフローで制御を奪え(hard, 1秒毎にバイナリ更新, 全10,800バイナリ

writeup

まず、10000番ポートのバイナリの解析に取り掛かった。このポートのバイナリは、ある固定の値でXORした文字列と、入力された文字列が一致していればフラグを得ることができる。その処理を行っているところが、以下の通りとなっている。
10000番ポートから降ってくるバイナリの1つから抜粋したので、バイナリごとにアドレスや値が異なっている。しかし、命令の並びは同じであるので、どのバイナリでも同じように解析可能だった。

最初のmov命令で、ecx(カウンタ)に、文字列同士を比較するときの長さを格納している。
movabs命令で、rsiにランダムな文字列を格納している。この文字列が、後でXORされて入力文字列と比較される。
続く2つのmov命令で、入力文字列と、ランダム文字列から1文字ずつ取り出している。
xor命令で、ランダム文字列側の1文字を固定値で、XORしている。
最後にcmpで比較しており、一致していない場合は、Hello World!を出力するようにジャンプしていく。
一致していた場合は、rcxをデクリメントし、2つ文字列から1文字取り出す処理にジャンプし、ループしていく。

以上のことから、excに格納される値、ランダム文字列が格納されているアドレス、xorする値の3つが分かればいいので、
それを抜き出してフラグをサブミットしてもらう処理を、他のメンバに自動化してもらった。
https://t.co/EMSyXzO4TX


  400153:       b9 0f 00 00 00          mov    ecx,0xf
  400158:       48 8d 7d f1             lea    rdi,[rbp-0xf]
  40015c:       48 be 35 02 40 00 00    movabs rsi,0x400235
  400163:       00 00 00 
  400166:       8a 44 0f ff             mov    al,BYTE PTR [rdi+rcx*1-0x1]
  40016a:       8a 5c 0e ff             mov    bl,BYTE PTR [rsi+rcx*1-0x1]
  40016e:       34 e8                   xor    al,0xe8
  400170:       38 d8                   cmp    al,bl
  400172:       75 11                   jne    0x400185
  400174:       48 ff c9                dec    rcx
  400177:       75 ed                   jne    0x400166


20000番ポートだが、難読化がキツくて読み進めるのが辛かった。
途中で、これを人力でやるのは無理だと感じ、秘密兵器のangrを使おうと思ったが、使い方が分からなかった。
Hello World!が出力されないパスとか求められないかなー」と考えていたが、やり方が分からなかった。

30000番と40000番ポートの問題はノータッチで、他のメンバが取り組んでくれていた。
30000番は、バッファサイズと、カナリア、secretを出力する関数のアドレスが求めて、exploitを組み立てていたみたいで、フラグのsubmitも含めて自動化していた。
40000番は、まったく知らない。他のメンバが、バッファサイズとカナリアを求めることができたそうなので、あともう少しだったらしい。

さいごに

競技時間中にメンバーと、「angr使う余地ある?」みたいな会話をしていた。優勝チームは、angrを使ってhardの問題を解いていたので、もう辛い。findとavoidのアドレスを設定して回す、みたいな使い方しか知らなかったので、angrをもっと知っておけば良かったと後悔している。

自動化を競う大会なのに、まったく自動化しようとしなかったので、その点は反省したい。
そもそも競技中に書いたコードが、フラグをsubmitするシェルスクリプトぐらいだった。

せっかく大阪に来たのでゲーセンに行こうとしたら客引きに、こんなことを言われてしまい辛かった。