Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SECCON_quals_2019_follow_me.pdf

Xcyba17her
October 29, 2019
160

 SECCON_quals_2019_follow_me.pdf

an write-up of the problem "follow-me" from SECCON online CTF 2019

Xcyba17her

October 29, 2019
Tweet

Transcript

  1. 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
  2. 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
  3. ‘+’が入力された場合の流れ  最後のjmp loc_E79のアドレスは0xca6となっている.  これに合致するcalc.trace上のパターンは,0xe87 → 0xbe9 → 0xc1c

    → 0x8dc → 0x8dc → 0x8dc → 0xa0b → 0xa1f → → 0x93e → 0xca6である.  0xa1fを通る回数は2数により異なり,問題の肝.後で考える. 16
  4. パターンのまとめ  いずれの数字や演算子のパターンでも0x55f6b4d44e87で 始まる.  いずれの数字や演算子のパターンでも最後のjmp命令の アドレスで終わる. 1. ‘,’ →

    0x55f6b4d44c13 2. 数字 → 0x55f6b4d44e87 3. ‘+’ → 0x55f6b4d44ca6 4. ‘-’ → 0x55f6b4d44cfd 5. ‘*’ → 0x55f6b4d44d54 6. ‘m’ → 0x55f6b4d44dab 7. ‘M’ → 0x55f6b4d44e02  calc.traceにはこれらのパターンが連続しているため, 数字の特定を除けば入力文字列(数式)は求められる! 22
  5. ソルバ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
  6. 加算と乗算のまとめ  “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
  7. 数値部分の決定  ソルバ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
  8. 数値部分の決定  ここで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
  9. 数値部分の決定 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
  10. 数値部分の決定  前のページをまとめると…  つまり,入力すべき数式(の一例)は以下のようになる. 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
  11. フラグを出す  問題文にあった形式で問題サーバに送る.  フラグは 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