2

My ROP exploit crashes with segmentation fault for unknown reason. This is a vulnerable code (compiled via command gcc h2.c -no-pie -fno-stack-protector -m32 -o h2):

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

char string[100];
void exec_string() {
    system(string);
}

void add_bin(int magic) {
    if (magic == 0xdeadbeef) {
        strcat(string, "/bin");
    }
}

void add_sh(int magic1, int magic2) {
    if (magic1 == 0xcafebabe && magic2 == 0x0badf00d) {
        strcat(string, "/sh");
    }
}

void vulnerable_function(char* string) {
    char buffer[100];
    strcpy(buffer, string);
}

int main(int argc, char** argv) {
    string[0] = 0;
    vulnerable_function(argv[1]);
    return 0;
}

I followed this example: https://medium.com/@nikhilh20/return-oriented-programming-rop-chaining-def0677923ad

In addition, there are no suitable gadgets of pop pop ret pattern (actually, there are, but pop [some reg] pop ebp ret, which messes up the stack as well as gadgets with leave instruction).

I've tried two different stack paddings for an exploit: the first one is identical to the primer in the link I provided above. The second one is (top - higher addresses, bottom - lower addresses):

address of exec_string
garbage value
0x0badf00d
0xcafebabe
add esp 8; pop ebx; ret <-- gadget
address of add_sh
0xdeadbeef
pop; ret gadget <-- gadget
address of add_bin <-- compromised instruction pointer after BoF
AAAA
....
112 'A's to overflow the buffer and overwrite ebp (108 + 4)
....
AAAA

Let me explain the add esp, 8; pop ebx; ret gadget. There are no gadgets like pop [some reg]; pop [some reg, not ebp]; ret for chaining calls from add_sh to exec_string functions, so I've tried to make a little hack. I've chosen add esp, 8; pop ebx; ret gadget to pop out 0xcafebabe and 0x0badf00d via add esp,8 then pop out garbage unreferenced value via pop ebx and then ret to exec_string. Does it suppose to work at all? Correct me if I wrong.

Moreover, when I've started debugging, it results with:

Cool, it looks like I owned an instruction pointer, I need to replace it with add_bin function address to jump to it and start a ROP chain.

But...

SIGSEGV in 0x91c2b1c2? I've entered a correct add_bin address, ASLR, PIE and canaries are disabled. I thought that maybe there is an undefined reference to string that vulnerable_function gets, but in primer in the link provided above it was ignored, so it confused me a lot.

Asm .
  • 59
  • 5

2 Answers2

1

If you fix this issue, I believe you will be successful.

gef➤  ropper --search pop
[...]
0x0804901e: pop ebx; ret; 
0x080491c4: pop edi; pop ebp; ret; 
[...]

These gadgets don't "mess up" the stack in this case; they clean it up a bit after the overflow so that you are able to return to the next function in the chain. The gadget you picked instead is close, but would need to be an add esp, 4 instead of 8, or without the additional pop. You'll see why if you step through it in the debugger.

So, instead use the pop; pop; ret from above.

multithr3at3d
  • 12,355
  • 3
  • 29
  • 42
  • It fails when I want to jump to add_bin function, look at two debugging screenshots in the question post. How does it happen? I can't jump even to add_bin despite of the fact that I owned the instruction pointer. How does it happen? – Asm . Jan 12 '20 at 17:49
  • @Asm. The screenshots don't show at what part of execution the segfault occured, are you sure it's at `add_bin`? Maybe you are getting further than you think. – multithr3at3d Jan 12 '20 at 20:38
1

The problem was actually in Python 3 that couldn't output a raw bytes in a straightforward way like in Python 2. Also, my theory about add esp, 8; pop ebx; ret gadget is correct :) This is an alternative way to build a ROP chain (the garbage value is not referenced by add_sh function, so I can do that without a danger to fall into a segmentation fault, it may come very handy in particular cases when there are few perfect gadgets in the binary). Here is the exploit:

Asm .
  • 59
  • 5