Reversing-Challenges-List/Baby Writeup #1
Reversing-Challenges-List/Baby
Reversing-Challenges-Listの内容を解いていくことにする。
まずはBabyから
ASIS_CTF_2018_Quals_Warm_up
ファイル一覧を見る
$ ls README.md Warm_up.7z writeup.md
7zで圧縮されたファイルがあるので解凍するとwarmup
というファイルが見える。
中身を確認
$ cat warmup #define M 37 #define q (2+M/M) #define v (q/q) #define ef ((v+q)/2) #define f (q-v-ef) #define k (8-ef) struct b{int64_t y[13];}S;int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]=(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}l(){while(e/=2){N*=2;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a%10,a/=10;}}z(n){int y=3,j,c;for(j=2;j<=n;){l();for(c=2;c<=y-1;c++){l();if(y%c==0)break;}if(c==y){l();j++;}y++;}l();return y-1;}main(a, pq) char* pq;{int b=sizeof(S),y=b,j=M;l();int x[M]={b-M-sizeof((short int) a),(b>>v)+(k<<v)+ (v<<(q|ef)) + z(v+(ef<<v)),(z(k*ef)<<v)-pow(ef,f), z(( (j-ef*k)|(ef<<k>>v)/k-ef<<v)-ef),(((y+M)&b)<<(k/q+ef))-z(ef+v),((ef<<k)-v)&y,y*v+v,(ef<<(q*ef-v-(k>>ef)))*q-v,(f<<q)|(ef<<(q*f+k))-j+k,(z(z(z(z(z(v)))))*q)&(((j/q)-(ef<<v))<<q)|(j+(q|(ef<<v))),y|(q+v),(ef<<ef)-v+ef*(((j>>ef)|j)-v+ef-q+v),(z(j&(b<<ef))&(z(v<<v)<<k))-(q<<v)-q,(k<<q)+q,(z(y)>>(ef<<v))+(z(k+v))-q,(z(z(k&ef|j))&b|ef|v<<f<<q<<v&ef>>k|q<<ef<<v|k|q)+z(v<<v)+v,(ef>>v)*q*z(k-v)+z(ef<<ef&q|k)+ef,z(k<<k)&v&k|y+k-v,z(f>>ef|k>>ef|v|k)*(ef>>v)*q,(ef<<k-ef<<v>>q<<ef*ef)-j+(ef<<v),z(ef*k)*z(v<<v)+k-v,z((z(k)<<z(v)))&y|k|v,z(ef<<ef<<v<<v)/ef+z(v<<ef|k|(b>>q)&y-f)-(ef<<q)+(k-v)-ef,k<<(ef+q)/z(ef)*z(q)&z(k<<k)|v,((z(y|j>>k*ef))%ef<<z(v<<v<<v)>>q<<q|j)/ef+v,(j-ef<<ef<<v*z(v>>v<<v)>>ef)/ef%z(k<<j)+q,z(k-v)+k|z(ef<<k>>v<<f)-z(q<<q)*ef>>v,(z(ef|y&j|k)%q|j+ef<<z(k|ef)%k<<q|ef|k<<ef<<q/ef|y/ef+j>>q)&k<<j|ef+v,84,z(v*ef<<ef<<q)*q%ef<<k|k|q-v,((z(20)*v)|(f>>q)|(k<<k))/ef-(ef<<(v*q+ef))-(k<<q)+z(k)-q};while(j--){putchar(x[M-v-j]);}printf(" From ASIS With Love <3\n");return 0;}
難読化されているがCのsource codeっぽいので拡張子.c
をつけ、コンパイルするとたくさんのwarningが出る。
warningは存在してもコンパイルできるはずなのでどこかでerrorが出てるはず。
errorを探す、すると
error: unknown type name ‘int64_t’
が表示されていた。
int64_t
が定義されていないとのことなので定義してやる
#define M 37 #define q (2+M/M) #define v (q/q) #define ef ((v+q)/2) #define f (q-v-ef) #define k (8-ef) typedef long int int64_t; // ここ ...
実行すると、かなり待たされる。
ちらっと見た感じだとeという変数に少し長めの数値を入れていたので暗号に関する処理をしていたのかな...?
変数名は適当につけてる可能性が高いのであまり気にしないことにした
$ ./warmup ASIS{hi_all_w31c0m3_to_ASISCTF} From ASIS With Love <3
Nuit_du_Hack_CTF_Quals_2016_Matriochka-Step_1
渡されたファイルを実行してみる。
$ ./stage1.bin Usage: ./stage1.bin <pass>
引数を渡して再び実行すると...
$ ./stage1.bin test Try again...
と出てくる。
おそらく引数にフラグを渡してやればよいのだと思う。
まずはmain関数の中を見る
gdb-peda$ disass main Dump of assembler code for function main: 0x000000000040064d <+0>: push rbp 0x000000000040064e <+1>: mov rbp,rsp 0x0000000000400651 <+4>: sub rsp,0x20 0x0000000000400655 <+8>: mov DWORD PTR [rbp-0x14],edi 0x0000000000400658 <+11>: mov QWORD PTR [rbp-0x20],rsi 0x000000000040065c <+15>: cmp DWORD PTR [rbp-0x14],0x2 0x0000000000400660 <+19>: je 0x400687 <main+58>
コマンドライン引数の数が0x2
と同値が比べており、そうでなければ使い方を表示して終了する。
2
というのは./stage.bin
と<pass>
のことだ。
次の処理を見ていく
0x0000000000400687 <+58>: mov rax,QWORD PTR [rbp-0x20] 0x000000000040068b <+62>: add rax,0x8 0x000000000040068f <+66>: mov rax,QWORD PTR [rax] 0x0000000000400692 <+69>: mov esi,0x40e079 0x0000000000400697 <+74>: mov rdi,rax 0x000000000040069a <+77>: call 0x400520 <strcmp@plt> 0x000000000040069f <+82>: test eax,eax 0x00000000004006a1 <+84>: jne 0x400773 <main+294>
strcmp関数を呼び出ししているところがある。
ここで文字列を比較してflagの判断をしているのではと考えたので、breakpointを設定する。
gdb-peda$ b *0x40069a
もう一度プログラムを走らせてレジスタの値を見てみると
RSI: 0x40e079 ("Much_secure__So_safe__Wow")
が見える。
この文字をコマンドライン引数に渡して実行するとgoodgood
と共にとてつもなく長い文字列が表示されるが、末尾が==
なのでBase64でdecodeできるのではないかと考え試してやる
$ cat strings | base64 -d > flag $ file flag flag: POSIX tar archive (GNU)
アーカイブなので解凍してやる
$ tar -vxf flag stage2.bin
問題がまた出てきた
Nuit_du_Hack_CTF_Quals_2016_Matriochka-Step_2
stage2.bin
という実行ファイルが見つかる。
実行してみる
$ file stage2.bin stage2.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=7b2fd52d0de50c9e575793a0fd17fdd2574c5c53, stripped $ ./stage2.bin Usage: ./stage2.bin <pass>
step1と同様コマンドライン引数をflagにして実行するプログラムっぽい
gdbで処理を追っていくと以下のような処理に出会う
gdb-peda$ x/5 0x400742: call 0x400510 <strlen@plt> 0x400747: lea rdx,[rax+0x1] 0x40074b: mov rax,rdx 0x40074e: shl rax,0x2 0x400752: add rax,rdx gdb-peda$ 0x400755: shl rax,0x2 0x400759: add rax,rdx 0x40075c: add rax,rax 0x40075f: cmp rax,0x1f8 0x400765: jne 0x40099a
これはコマンドライン引数の長さを調べ、flagの長さと同じかどうかの確認をしている処理だ
しかし、受け取った長さをただ使用せずに何かしらの処理をして比較している
最終的に比較する値は0x1f8
なので10進数に直すと504
になる
処理を見ていくと
0x400747: lea rdx,[rax+0x1] ; 文字列長+1をrdxに移動 0x40074b: mov rax,rdx ; raxにrdx(文字列長)を移動 0x40074e: shl rax,0x2 ; 左に2シフト(4倍) 0x400752: add rax,rdx ; 4倍された文字列長に元の文字列長を足す(5倍) 0x400755: shl rax,0x2 ; 左に2シフト(20倍) 0x400759: add rax,rdx ; 20倍された文字列長に元の文字列長を足す(21倍) 0x40075c: add rax,rax ; 20倍された文字列長に20倍された文字列長を足す(42倍) 0x40075f: cmp rax,0x1f8 ; `0x1f8`と比較 0x400765: jne 0x40099a
というわけで42倍された文字列長と0x1f8
を比較していることがわかる。
つまりflagとなる文字列は
0x1f8 / 42 - 1 11
となる
set AAAAABBBBBC
を引数としてセットしておき再実行。
ここからは文字列を1文字ずつ比較していくことになる
0x400776: add rax,0x8 0x40077a: mov rax,QWORD PTR [rax] 0x40077d: movzx eax,BYTE PTR [rax] 0x400780: cmp al,0x50 0x400782: je 0x40078b
0文字目と0x50
を比較しているので1文字目はP
0x400796: add rax,0x3 0x40079a: movzx eax,BYTE PTR [rax] 0x40079d: movsx eax,al 0x4007a0: add eax,eax 0x4007a2: cmp eax,0xc8
3文字目は0xc8 / 2
をしてd
だとわかる
0x4007be: movsx eax,al ; eaxに0文字目の値を代入 0x4007c1: lea edx,[rax+0x10] ; edxにrax(0x50)と0x10を足し算した値(0x60)を代入 0x4007c4: mov rax,QWORD PTR [rbp-0x30] 0x4007c8: add rax,0x8 0x4007cc: mov rax,QWORD PTR [rax] 0x4007cf: add rax,0x6 0x4007d3: movzx eax,BYTE PTR [rax] 0x4007d6: movsx eax,al 0x4007d9: sub eax,0x10 ; 6文字目から0x10を引いて 0x4007dc: cmp edx,eax
6文字目は0文字目の0x50
に0x10
を足した値と6文字目から0x10
を引いた値を比較しているので0x70 = 'p'
0x4007ef: mov rax,QWORD PTR [rax] 0x4007f2: add rax,0x5 0x4007f6: movzx eax,BYTE PTR [rax] 0x4007f9: movsx rbx,al 0x4007fd: mov rax,QWORD PTR [rbp-0x30] 0x400801: add rax,0x8 0x400805: mov rax,QWORD PTR [rax] 0x400808: mov rdi,rax
というように解いていくとflagはPandi_panda
だとわかる。