ちょっとずつ成長日記

強くなりたいと願いつつ少しずつ頑張る日記

Codegate CTF Preliminary 2013 Vuln100(解けなかった)

今回は64bit-ELFでfork-server型だった。最初に実行したときはなんかクイズみたいな形式で出題されたので、とりあえず、答えになりそうなものをstringshttp://blog.hatena.ne.jp/shimasyaro/shimasyaro.hatenablog.com/edit?entry=10328749687216287040コマンドで探してみたが、怪しい文字列はどうやら全部、MD5でハッシュ化されていた。仕方ないので素直に解いていくことにした(諦め)

shima@chino:~/workspace/pwn_list_baby/vuln100$ nc localhost 6666
Welcome to CODEGATE2013.
This is quiz game.
Solve the quiz.


It is Foot Ball Club. This Club is an English Primier league football club. This Club founded 1886. This club Manager Arsene Wenger. This club Stadium is Emirates Stadium. What is this club? (only small letter)
arsenal
good!1
It is a royal palace locate in northern Seoul, South Korea. First constructed in 1395, laster burned and abandoned for almost three centuries, and then reconstructed in 1867, it was the main and largest place of the Five Grand Palaces built by the joseon Dynasty. What is it?(only small letter)
gyeongbokgung
good!2
He is South Korean singer, songwriter, rapper, dancer and record producer. He is known domestically for his humorous videos and stage performances, and internationally for his hit single Gangnam Style. Who is he?(only small letter)
psy
good!3
rank write! your nickname:

素直に問題を解いていくと、どうやらrankに自分の名前を登録できるような仕組みになっているらしい。ここに今回は脆弱性があるみたい。詳しくここら辺を見ていくことにする。まずは、セキュリティチェック

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : disabled
PIE       : disabled
RELRO     : Partial

何でもありな状態であるため、今回はshellcodeを使っていこうかな。SSPも無効になっているため、stackをチェックする機構が独自に作られていなければBOFできそう。PIEもないので実行ファイルのアドレスは固定であるため、適当なセクションを使うのもありかも。とりあえずデバッグしてみることに!すると・・・

[-------------------------------------code-------------------------------------]
   0x400cc7:    mov    rdx,rsi
   0x400cca:    mov    rsi,rcx
   0x400ccd:    mov    rdi,rax
=> 0x400cd0:    call   0x400a80 <memcpy@plt>
   0x400cd5:    mov    rdx,QWORD PTR [rbp-0x118]
   0x400cdc:    mov    rax,QWORD PTR [rbp-0x8]
   0x400ce0:    mov    rsi,rdx
   0x400ce3:    mov    rdi,rax
Guessed arguments:
arg[0]: 0x7fffffffd970 --> 0x7fffffffda28 --> 0x0 
arg[1]: 0x7fffffffdfa8 ('A' <repeats 29 times>, "\n")
arg[2]: 0x1e 
arg[3]: 0x7fffffffdfa8 ('A' <repeats 29 times>, "\n")
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd960 --> 0xffffffffffffffff 
0008| 0x7fffffffd968 --> 0x7fffffffdfa8 ('A' <repeats 29 times>, "\n")
0016| 0x7fffffffd970 --> 0x7fffffffda28 --> 0x0 
0024| 0x7fffffffd978 --> 0x7ffff7649978 --> 0xc0022000055fa 
0032| 0x7fffffffd980 --> 0x0 
0040| 0x7fffffffd988 --> 0x7fffffffda80 --> 0x7fffffffdec0 --> 0x0 
0048| 0x7fffffffd990 --> 0x400a90 (xor    ebp,ebp)
0056| 0x7fffffffd998 --> 0x7ffff79f7760 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0000000000400cd0 in ?? ()
gdb-peda$ b *0x400cd0
Breakpoint 2 at 0x400cd0
gdb-peda$ x/100wx $esp
0xffffffffffffd960:    Cannot access memory at address 0xffffffffffffd960
gdb-peda$ x/100gx $rsp
0x7fffffffd960:    0xffffffffffffffff 0x00007fffffffdfa8
0x7fffffffd970:    0x00007fffffffda28 0x00007ffff7649978
0x7fffffffd980:    0x0000000000000000 0x00007fffffffda80
0x7fffffffd990:    0x0000000000400a90 0x00007ffff79f7760
0x7fffffffd9a0:    0x0000000000000000 0x0000000000000000
0x7fffffffd9b0:    0x00007fffffffda28 0x00007fffffffda10
0x7fffffffd9c0:    0x00007fffffffda00 0x00007ffff7a63002
0x7fffffffd9d0:    0x0000000000000000 0x00007fffffffda80
0x7fffffffd9e0:    0x0000000000400a90 0x0000000000400c59
0x7fffffffd9f0:    0xfffffe03ffffdec0 0x00007fffffffe060
0x7fffffffda00:    0x31f2ab2cbe4cf530 0xb9e789adaa8c1973
0x7fffffffda10:    0x31f2ab2c00000000 0xb9e789adaa8c1973
0x7fffffffda20:    0x0000000000000018 0x0000000000000000
0x7fffffffda30:    0x0000000000000000 0x0000000000000000
0x7fffffffda40:    0x0000000000000000 0x0000000000000000
0x7fffffffda50:    0x0000000000000000 0x0000000000000000
0x7fffffffda60:    0x00007fffffffdec0 0x0000000000400a90
0x7fffffffda70:    0x00007fffffffdfa0 0x00007fffffffd970
0x7fffffffda80:    0x00007fffffffdec0 0x000000000040121e

[-------------------------------------code-------------------------------------]
   0x400cdc:    mov    rax,QWORD PTR [rbp-0x8]
   0x400ce0:    mov    rsi,rdx
   0x400ce3:    mov    rdi,rax
=> 0x400ce6:    call   0x400a30 <strcpy@plt>
   0x400ceb:    mov    rax,QWORD PTR [rbp-0x8]
   0x400cef:    mov    QWORD PTR [rip+0x2013e2],rax        # 0x6020d8
   0x400cf6:    leave  
   0x400cf7:    ret
Guessed arguments:
arg[0]: 0x7fffffffd970 ('A' <repeats 29 times>, "\n")
arg[1]: 0x7fffffffdfa8 ('A' <repeats 29 times>, "\n")
arg[2]: 0x7fffffffdfa8 ('A' <repeats 29 times>, "\n")
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffd960 --> 0xffffffffffffffff 
0008| 0x7fffffffd968 --> 0x7fffffffdfa8 ('A' <repeats 29 times>, "\n")
0016| 0x7fffffffd970 ('A' <repeats 29 times>, "\n")
0024| 0x7fffffffd978 ('A' <repeats 21 times>, "\n")
0032| 0x7fffffffd980 ('A' <repeats 13 times>, "\n")
0040| 0x7fffffffd988 --> 0xa4141414141 ('AAAAA\n')
0048| 0x7fffffffd990 --> 0x400a90 (xor    ebp,ebp)
0056| 0x7fffffffd998 --> 0x7ffff79f7760 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0000000000400ce6 in ?? ()
gdb-peda$ x/100gx $rsp
0x7fffffffd960:    0xffffffffffffffff 0x00007fffffffdfa8
0x7fffffffd970:    0x4141414141414141 0x4141414141414141
0x7fffffffd980:    0x4141414141414141 0x00000a4141414141
0x7fffffffd990:    0x0000000000400a90 0x00007ffff79f7760
0x7fffffffd9a0:    0x0000000000000000 0x0000000000000000
0x7fffffffd9b0:    0x00007fffffffda28 0x00007fffffffda10
0x7fffffffd9c0:    0x00007fffffffda00 0x00007ffff7a63002
0x7fffffffd9d0:    0x0000000000000000 0x00007fffffffda80
0x7fffffffd9e0:    0x0000000000400a90 0x0000000000400c59
0x7fffffffd9f0:    0xfffffe03ffffdec0 0x00007fffffffe060
0x7fffffffda00:    0x31f2ab2cbe4cf530 0xb9e789adaa8c1973
0x7fffffffda10:    0x31f2ab2c00000000 0xb9e789adaa8c1973
0x7fffffffda20:    0x0000000000000018 0x0000000000000000
0x7fffffffda30:    0x0000000000000000 0x0000000000000000
0x7fffffffda40:    0x0000000000000000 0x0000000000000000
0x7fffffffda50:    0x0000000000000000 0x0000000000000000
0x7fffffffda60:    0x00007fffffffdec0 0x0000000000400a90
0x7fffffffda70:    0x00007fffffffdfa0 0x00007fffffffd970
0x7fffffffda80:    0x00007fffffffdec0 0x000000000040121e

一番気になったのは、memcpyとstrcpyが同じBufferのアドレスを使用していた点である。具体的な位置としては0x00007fffffffd970というアドレスを使用していた。そこをこの二つのライブラリは使用していた。また、0x7fffffffda78のアドレスにBufferのアドレスが格納されている。このアドレスはmemcpyを実行した後に書き換えが可能であるため、次のstrcpyが実行されるときに任意のアドレスに変更することができる。
C言語にすると以下のような感じ

memcpy(Buffer, UserInput, sizeof(UserInput) - 1);
strcpy(Buffer, UserInput);

その脆弱性を利用して、うまくreturnアドレスを書き換えることができるため、今回はこの脆弱性を利用してshellcodeのアドレスにreturnアドレスを書き換えたい。
具体的にどうするかを説明していく。
最初に、必要なものはbufferのアドレスの特定である。今回はfork-server型であるため、親プロセスが死なない限り、アドレスの位置は変わらない。そこでまず一回目はstackに格納されているアドレスをleakしてからbufferのアドレスのoffsetを足してあげることで求める。今回は登録した内容をsendで見せるような処理を最後にしているためそこからleakする。この出力は終端文字がつけられる処理がないため、終端文字を消してstackに格納されているアドレスをleakさせる
次に、leakしたbufferアドレスから8byte進んだ先にstrcpyのアドレスを設定する。こうすることによってbufferの最後から8byteの部分が、うまくstackに格納されているreturnアドレスを上書きしてくれる。
ではさっそく、やってみよう。と思ってleakしてみたが、正確なアドレスを絞り込むことは難しかった。
他のwrite upを見たところ結局はBrute Forceをやっているようなwrite upがほとんどを占めていた。(この方法しかないのかな?)
私もやってみたが、上手くできなかった(圧倒的実力不足)
解けないこともあるんだね。雑魚だものしょうがない(諦め)