Slide 1

Slide 1 text

SECCON quals 2019 follow-me writeup @__Xcyba17her_

Slide 2

Slide 2 text

どんな問題?  計算を行えるcalcというelfバイナリと,branchtrace.cpp, calc.traceが与えられる.  calc.traceにはある計算式をcalcに与えて問題作成者が実 行したときにcalcがどのようなアドレスを通ったかとい うようなデータがならんでおり,これと同じトレース結 果を出すような計算式を導けという問題.  (最初calcの使い方がわからなかった) 2

Slide 3

Slide 3 text

branchtrace.cppの内容  calc.traceを出力するためのプログラム?  ソースコードを見ても何をしているかさっぱりわからな かったので無視してしまった… 3

Slide 4

Slide 4 text

calc.traceの内容  json形式のデータが並んでいる.  600行くらいあるので読むの嫌だな~と思ったが,この ファイルがキーだと思い読んでいくことにした.  inst_addrがcalc実行時のアドレスを指しており,この通り に追っていけば何かしらヒントが得られると推測した. 4

Slide 5

Slide 5 text

calc.traceのinst_addrを追う  IDAでcalcを開く.  アドレスの値が小さく,PIEが有効であるように見える.  inst_addrの値だけでは追うことができない 5

Slide 6

Slide 6 text

calc.traceのinst_addrを追う  calc.traceの2行目~5行目にcalc.traceが記録された当時の calcやlibcのベースアドレスと思しきデータがある.  {"event": "image_load", "image_name": "/home/tomori/follow-me/build/sample/calc", "image_id": 1, "base_addr": "0x55f6b4d44000", "image_size": "0x1377"}  calcのベースのアドレスは0x55f6b4d44000である.  IDA上のアドレスは,inst_addrから0x55f6b4d44000を引いたも のになる. 6

Slide 7

Slide 7 text

calc.traceのinst_addrを追う  1つ目のinst_addrについて調べる.  calc.traceの6行目にある{"event": "branch", "inst_addr": "0x55f6b4d445de", "next_inst_addr": "0", "branch_taken": true}  IDAで見るべきアドレスは0x5de  対応するアドレスの命令は,条件付きジャンプ命令jzで あった.  これとtrue,falseの2値があるbranch_takenというデータの 存在から,calc.traceの各行のinst_addrとbranch_takenは, 条件付きのジャンプ命令と,ジャンプの有無を表している のではないかと考えた. 7

Slide 8

Slide 8 text

calc.traceのinst_addrを追う  2つ目(calc.traceの7行目)のinst_addrをみる.  inst_addrは0x55f6b4d44f44であるから,IDAで見るべき アドレスは0xf44  対応する命令は,jz命令であった.  しかし0x5deのjz命令との関係は見えず.  でもこの調子で読んでいく. 8

Slide 9

Slide 9 text

calc.traceのinst_addrを追う  6つめ(calc.traceの11行目)以降のinst_addrである 0x55f6b4d44eae,0x55f6b4d44630,0x55f6b4d44620に注目.  0xeaeのjg short loc_ED5をtrue方向に進み,sub_B6E関数に入る と,mallocとcallocを呼ぶ流れになっているが,0x630,0x620は それぞれpltセクションでのjmp命令のアドレスになっている.  これで,calc.traceがcalcのジャンプ命令おきにジャンプの有無 を記録したものという確証がついた. 9

Slide 10

Slide 10 text

calc.traceのinst_addrを追う  この調子で600行読んでいくわけにもいかないので, calc.traceの中でよく通ってるinst_addrがないか探してみる.  やけに0x55f6b4d44e87のジャンプ命令を通っており,その後も 似たパターンのアドレスを通っている. 10

Slide 11

Slide 11 text

calc.traceのinst_addrを追う  0x55f6b4d44e87付近をグラフモードで見ると,sub_B6Eが このプログラムのメイン機能となっている部分であること がわかる.  ある文字列について1文字ずつ走査し,それが’,’であるか,数 字であるか,’+’であるか,’-’であるか,’*’であるか,’m’であ るか,’M’であるか,’C’であるかにより処理を分岐させている.  これはコマンドライン引数に指定する数式の計算を行う処理の ためのものであると予想. 11

Slide 12

Slide 12 text

calcの動作  IPAの試験でよく見る逆ポーランド記法の形の数式 をコマンドライン引数として指定すると計算してく れる.  mは2数のうち小さいものを,Mは2数のうち大きい ものを選ぶ演算子. 12

Slide 13

Slide 13 text

演算子ごとの通過パターン  数字,演算子ごとに分岐先は異なっており,それぞれで 決まった一連の命令が行われる.したがって,calc.trace 中に同じinst_addrの流れやパターンが見られるはず.  これらのパターンがわかれば,calc.traceに示された流れ と同じような流れで動かせる入力が見つかるはず. 13

Slide 14

Slide 14 text

‘,’が入力された場合の流れ  最初のjnz short loc_C0Cのアドレスは, 0xbefになっている.また,最後のjmp loc_E79のアドレスは,0xC13になっている.  どの数値や演算子による分岐についても最後 にjmp命令があるのでそれとcalc.traceを組 み合わせて考えればよい.  これに合致するcalc.trace上のパターンは, 0xe87 → 0xbe9→ 0xbef→0x93e →0xc13で ある. 14

Slide 15

Slide 15 text

数字が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xc4fとなっ ている.  これに合致するcalc.trace上のパターンは, 0xe87 → 0xbe9→ 0xc1c→0xc22 →0xc4fであ る. 15

Slide 16

Slide 16 text

‘+’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xca6となっている.  これに合致するcalc.trace上のパターンは,0xe87 → 0xbe9 → 0xc1c → 0x8dc → 0x8dc → 0x8dc → 0xa0b → 0xa1f → → 0x93e → 0xca6である.  0xa1fを通る回数は2数により異なり,問題の肝.後で考える. 16

Slide 17

Slide 17 text

‘-’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xcfdとなっ ている.  これに合致するcalc.trace上のパターンは, 0xe87 → 0xbe9→ 0xc1c → 0xc58 → 0xcaf → 0x8dc → 0x8dc → 0x93e → 0xcfdである. 17

Slide 18

Slide 18 text

‘*’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xd54となっている.  これに合致するcalc.trace上のパターンは,0xe87 → 0xbe9 → 0xc1c → … → 0xd54である.  0xa1fを通る回数は2数により異なり,問題の肝.後で考える. 18

Slide 19

Slide 19 text

‘m’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xdabとなっている.  これに合致するcalc.trace上のパターンは,0xe87 → 0xbe9 → … → 0xdabである. 19

Slide 20

Slide 20 text

‘M’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xe02となっている.  これに合致するcalc.trace上のパターンは,0xe87 → 0xbe9 → … → 0xe02である. 20

Slide 21

Slide 21 text

‘C’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xe56となっている.  calc.traceにないので,いまは無視してよい! 21

Slide 22

Slide 22 text

パターンのまとめ  いずれの数字や演算子のパターンでも0x55f6b4d44e87で 始まる.  いずれの数字や演算子のパターンでも最後のjmp命令の アドレスで終わる. 1. ‘,’ → 0x55f6b4d44c13 2. 数字 → 0x55f6b4d44e87 3. ‘+’ → 0x55f6b4d44ca6 4. ‘-’ → 0x55f6b4d44cfd 5. ‘*’ → 0x55f6b4d44d54 6. ‘m’ → 0x55f6b4d44dab 7. ‘M’ → 0x55f6b4d44e02  calc.traceにはこれらのパターンが連続しているため, 数字の特定を除けば入力文字列(数式)は求められる! 22

Slide 23

Slide 23 text

ソルバ1  Pythonプログラムにcalc.traceを読ませ, パターンを読ませて入力文字列(数式)を 特定させる.  現時点で数値は特定していないため一律 で’1’を出力させている.  https://github.com/Ciruela- Xcyba17her/CTF/blob/master/SECCONq uals2019/follow_me/follow_me_solver_ 01.py  出力: 111,111,111,111,111,1111,111,mm-mM- 111,111,111,mm-111,111,111,111,111,- +-M+111,111,111,mm* import json f = open('calc.trace') json_data = json.load(f) inst_addr_list = [] for i in range(len(json_data)): try: inst_addr_list.append(json_data[i]['inst_addr']) except: continue answer = '' for i in range(len(inst_addr_list)): if inst_addr_list[i] == '0x55f6b4d44e87': ia = inst_addr_list[i - 1] if ia == '0x55f6b4d44c4f': answer += '1' elif ia == '0x55f6b4d44c13': answer += ',' elif ia == '0x55f6b4d44dab': answer += 'm' elif ia == '0x55f6b4d44e02': answer += 'M' elif ia == '0x55f6b4d44cfd': answer += '-' elif ia == '0x55f6b4d44ca6': answer += '+' elif ia == '0x55f6b4d44d54': answer += '*' print(answer) input('[END OF PROGRAM]') 23

Slide 24

Slide 24 text

数値の特定  読み込み文字が’+’または’*’のとき,0xa1fを通る回数が 毎回変わっている.この回数を揃えないとフラグは得ら れない.  ソルバの結果から加算は2回,乗算は1回行われるが, calc.traceによると,1回目の加算では4回,2回目の加算 では9回,乗算では7回0xa1fを通っている. 24

Slide 25

Slide 25 text

加算の仕組み  sub_98Cに2つの数値を渡し,一方が0になるまでデクリメント し,もう一方をインクリメントしていくことで和を求める.  関数の第一引数rsiをnum1,第二引数rdiをnum2と呼ぶ.  問題は,数式に”a,b,+”を指定したときに,図のnum1は一体a とbのどちらになるのか.num1に1を足したものが0xa1fを通る 回数となるので解決しなければならない. 25

Slide 26

Slide 26 text

加算の仕組み  減算ではどうなるか確認する.”a,b,-”を入力数式とする と結果はa-bとなるが,バイナリ内で前ページにおける num1とnum2についてnum1-num2が行われればnum1=a でnum2=bになるし,そうでなければnum1=bでnum2=a であるといえる.  減算を行うsub_A27では,num2-num1が行われている. したがって, num2=aでnum1=bである.もっといえ ば,”a,b,+”を入力数式とするとき,加算の過程で0xa1f を通る回数は(b+1)回となる. 26

Slide 27

Slide 27 text

乗算の仕組み  “a,b,*”が入力数式であるとする.sub_98Cを利用して0にaを b回足すことで積を表現している.  jg short loc_A5D(at 0xa81)を通過する回数は(b+1)回である. 1回aを結果に足し合わせていく中で,sub_98C中の0xa1fを 通過する回数は(a+1)回である. 27

Slide 28

Slide 28 text

加算と乗算のまとめ  “a,b,+”を実行すると,0xa1fは(b+1)回通る.  “a,b,*”を実行すると,0xa81を(a+1)回通り,その1回1回 で0xa1fを(b+1)回通る.  calc.traceによると,正解の入力数式を指定すると, 1回 目の加算では4回,2回目の加算では9回,乗算では7回 0xa1fを通っている.また,乗算では2回0xa81を通って いる.  再現するには,xを任意の自然数として,1回目の加算で は”x,3,+”が,2回目の加算では”x,8,+”が,乗算で は”6,1,*”という演算が行われていなければならない. 28

Slide 29

Slide 29 text

数値部分の決定  ソルバ1の出力”111,111,111,111,111,1111,111,mm- mM-111,111,111,mm-111,111,111,111,111,-+- M+111,111,111,mm*”の数値部分をa,b,c,…,rで表し, どのように計算されるか整理する.  a,b,c,d,e,f,g,mm-mM-h,i,j,mm-k,l,m,n,o,-+- M+p,q,r,mm*  xとyのうち小さい方を選択する関数をmin(x,y),大きい方 を選択する関数をmaxとする.  また,長くなるので中間の結果を格納する変数をx,y,z, 結果をresultとする. x = a - max(b, min(c, d - min(e, min(f, g))))) y = x - min(h, min(i, j)) z = y + max(k, (l - (m + (n - o)))) result = z * min(p, min(q, r)) 29

Slide 30

Slide 30 text

数値部分の決定  ここで2ページ前の条件を考えると,a,b,…,rは次の条件 を満たさなければならない. 1. n – o = 3 [1つ目の加算に関する条件] 2. max(k, (l - (m + (n - o)))) = 8 [2つ目の加算に関する条件] 3. z = 6 かつ min(p, min(q, r)) = 1 [1つの乗算に関する条件]  これだけ満たしていれば,あとはどうでもいい! x = a - max(b, min(c, d - min(e, min(f, g))))) y = x - min(h, min(i, j)) z = y + max(k, (l - (m + (n - o)))) result = z * min(p, min(q, r)) 30

Slide 31

Slide 31 text

数値部分の決定 1. n – o = 3  n = 003,o = 000で解決.(桁数を合わせないといけないことに 注意.また,上位桁のゼロ埋めができる) 2. max(k, (l - (m + (n - o)))) = 8  k=008とし,(l - (m + (n - o)))が8より大きくならないように, n = 003,o = 000に加え,l=000,m=000などとして解決. 3. z = 6 かつ min(p, min(q, r)) = 1  まず後ろはp=q=r=001で解決.z=6は少し難しいが, max(k, (l – (m + (n – o)))) = 8を考慮し,y = -2であればよい.  y = -2にするために,まずa=b=c=d=f=g=000,e=0000にすれば x = 0となり,min(h, min(I, j)) = 2とするためにh=i=j=2とすれ ば y = -2となり,z = 6を満たすことができる. x = a - max(b, min(c, d - min(e, min(f, g))))) y = x - min(h, min(i, j)) z = y + max(k, (l - (m + (n - o)))) result = z * min(p, min(q, r)) 31

Slide 32

Slide 32 text

数値部分の決定  前のページをまとめると…  つまり,入力すべき数式(の一例)は以下のようになる. a=000, b=000, c=000, d=000, e=0000, f=000, g=000, h=002, i=002, j=002, k=008, l=000, m=000, n=003, o=000, p=001, q=001, r=001 000,000,000,000,000,0000,000,mm-mM-002,002,002,mm- 008,000,000,003,000,-+-M+001,001,001,mm* 32

Slide 33

Slide 33 text

フラグを出す  問題文にあった形式で問題サーバに送る.  フラグは SECCON{Is it easy for you to recovery input from execution trace? Keep hacking:)} curl -q -H 'Content-Type:application/json' -d "{¥"input¥": ¥"000,000,000,000,000,0000,000,mm-mM-002,002,002,mm- 008,000,000,003,000,-+-M+001,001,001,mm*¥"}" http://follow- me.chal.seccon.jp/submit/quals/0 33

Slide 34

Slide 34 text

以上 34