この記事は rogy Advent Calendar 2016 の13日目の記事です。
こんにちは。rogyCTF部のやむどぅ(@ymduu)です。javaの伝道師ではないです。

早いもので、2016年のアドベントカレンダーも折り返し地点ですね。
rogyCTF部は今年もSECCONにSSR_CTF_BU(@shrcyan @ymduu @yosupot @z_kro(ツイッターアカウントは無い))で出ていました。
結果は1000点で83位(国内:20位)でした。

今回は前回のSECCONとは違い、バイナリ大盛りの大会でした(個人の感想です)

以下チーム全体で解いた問題のwriteup 

Vigenere

びじゅねる~
ヴィジュネル暗号の暗号文と平文の一部を与えるのでフラグを復号しろという問題。
与えられた平文の一部から鍵が8文字わかり、残りは4文字なので全探索ができる。
全探索に使ったコードは以下。

VoIP

パケットが与えられる。
z_kroさん「wiresharkで見れば音声が抜き出せるっぽいよ」
とのことなので、とりあえずwiresharkに入れてみる。
上のメニューバーから通話みたいなのがあったので
クリックすると音声が流れる。便利。
ここで流れてくるのがネイティヴっぽい英語音声。リスニング不可能。
とりあえずDislikeをしてから何度も聞くと、少しずつ聞き取れてくる。
よくわからないところは総当たりをしてたくさん提出をすると通った。

Memory Analysis

Volatility Frameworkというものを知る。
使い方がわからないのでググりまくる。
http://downloads.volatilityfoundation.org/releases/2.4/CheatSheet_v2.4.pdf
に行き着くとhostsファイルを抜き出せる。
http://dev.classmethod.jp/study_meeting/volatility-framework/
のブログに行き着くとフラグが取れる。

cheer msg

友利奈緒さんの問題。
ま~た友利奈緒か
”A"*大量とか %d とかを入れてみても怪しい挙動を示さないので真面目にreversingをする。
ここでどうでもいい話をすると、僕はテスターのアルバイトで金をもらっているので突然負の数をMessage lengthに入れてみたくなる。
負の数(以下n)をMessage Lengthに入れると怪しげな出力が起こるので、それっぽい部分を読むと、(n+30//16)*16バイトだけespをズラしてバッファを取っているので、負の数を入れるとespを減らせることがわかる。
実質espを任意場所に置けるので、リターンアドレスを書き換えられそうなところにespを置いて入力を行えばよい。
色々試すと、-150と入力したとき入力の先頭4バイトがEIPに入るので、後はROPするだけ。
なのだが、競技中はprintfによるアドレスのリークが上手くいかず、ブルートフォース解を投げてしまった。そのコードは以下。
競技後に検討したところ、__libc_start_mainが配置されるアドレスの下位1バイトが0x00であり、そこでprintfが止まってしまっていたということが分かる。
それを考えて1バイトずらしてアドレスをリークすると無事リークが上手くいき、ROPができる。
そのコードは以下。

Anti-Debugging

アンチデバッグ技術がふんだんに使われた贅沢なバイナリが与えられる。
起動するとパスワードを聞かれるが、パスワードは適当にデバッガで動かせば"I have a pen."だということが分かる。
アンチデバッギング技術はデバッガの上で実行させなければどうということはないので実行して"I have a pen."を与えればフラグが表示される。かと思いきや表示されないのでバイナリを流し読みすると、最後に
if(1 == 0) 終了;
みたいな事をしているので、バイナリエディタでパッチを当てて終了。

Backpacker's Capricious Cipher

読解が大変

秘密鍵

バイナリ変数 x_1, x_2, x_3, ..., x_N

公開鍵

a_1 * x_1 + a_2 * x_2 + ... + a_N * x_N = sum
となる変数a_1, a_2, ..., a_N と、sum

暗号化

バイナリ変数x_1, x_2, x_3, ..., x_Nについて、
f(x_1, x_2, x_3, ..., x_N) = 平文
となる多項式を作る。
もちろん自明な多項式として、値が平文の定数式が考えられる。
これだけだと何の暗号化にもならないが、
a_1 * x_1 + a_2 * x_2 + ... + a_N * x_N - sum = 0
を利用して、これに適当な多項式を掛けたものを足しまくると一見よくわからなくなりそう。
という暗号化。
今回は掛ける多項式が高々1次になっている。(つまりfは2次多項式)

復号化

代入
以上が暗号化の概要。なお、全部mod Pである(Pは素数)
ここまで整理できると簡単で、暗号化の時のrandの値を全部変数として
適当に連立方程式を立てれば解ける。
ただO(N^4)ぐらいになるのでかなり時間がかかりそうなので、
1次の項に注目するともっと早く解けたりする、O(N^2)。

checker

まず下調べでchecksecにかける。
$ checksec.sh --file checker
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Full RELRO Canary found NX enabled Not an ELF file No RPATH No RUNPATH checker

嫌な気持ちになる。
脆弱性自体はいたるところにBOFがある(getalineが文字列が終わるまで文字を取得するため)が、SSPが有効なため何もできない。
ただし、今回はフラグがあらかじめ固定アドレスに読み込まれているため、argv[0]リークで読みだせそうな気がしてくる。
argv[0]リークについてざっくりあっさり説明すると、SSPがバッファーオーバーフローを検知して落ちるときに、
"*** stack smashing detected ***: ./a.out terminated"
のような出力をするが、ここの"./a.out"というのはargv[0]を参照して出力する。
ここで、argv[0]とは普通に文字列のアドレスで、スタックの上に載っているので、BOFでこのアドレスを書き換えてしまえば任意のアドレスのデータを読み出せる、というものである。
この攻撃については以下のkatagaitai CTF勉強会のスライドが詳しい(今回のSECCONのwriteupで何回引用されているんだろう)
ただし、BOFで直接フラグのアドレス0x6010c0を該当場所に書き込むことはできない。
なぜなら、qwordの0x6010c0は0x00000000006010c0であり、今回のgetalineはヌル文字で止まってしまうからである。
今回はdo you know flag?に対してyesと答えるまで何度も入力を受け付けてくれるので、そのヌル終端を使って該当アドレスの上位バイトをnullで埋める。
以上のことを考慮してペイロードを出力するpythonコードは以下。
これの出力をnc で python o.py | nc checker.pwn.seccon.jp 14726 のようにして相手サーバーに流し込むと、確かに
*** stack smashing detected ***: SECCON{y0u_c4n'7_g37_4_5h3ll,H4h4h4} terminated のように、プログラム名の部分にフラグが入った出力が得られる。

最後に何か気の利いたことを言おうと考えていたらまた遅刻10分前になってしまった。
SSR_CTF_BUはいつでも部員募集中なので興味のある人はymduuまで。(ctfチャンネルに招待します)
明日は🍙さんの"LABはいいぞ"です。

javaの伝道師ではないです。