02x01 - How to maybe not be as bad at fuzzing unknown binary protocols as you were before reading this

Disclaimer:  I wrote this post a while ago, and definitely before I had enough knowledge to really share accurately.  Feel free to read on, but there's probably a lot of bad info in this.

You're bad at fuzzing unknown binary protocols, huh? Yeah, well, me too.  In fact, I've only done it once, and I had an RFC to look at, so I guess it technically wasn't an 'unknown' protocol... and it was mostly a walkthrough.

So, we'll go start to finish on this in a few posts, maybe.

Pre-Requisites:

  • Familiarity with debuggers, i.e.
    • OllyDBG
    • Immunity
  • Familiarity with:
    • Fuzzers (SPIKE, boofuzz, sulley, etc)
    • scapy
    • Python
    • Wireshark
    • Assembly (sorta)
      • Stack Based Buffer Overflows
      • SEH Exploits
  • Virtual Machines
    • Attacker 
      • Kali? Windows? Whatever floats your boat.
    • Victim x 2
      • Windows 7+
    • Note: If you're using windows as the attacking machine, you don't need two victim machines.
  • That's probably it?
Okay, so this post is a work in progress for a period, as I go through it as well.

First, what's the point?

DiskSaavy Enterprise 10.4.18 Remote Buffer Overflow SEH


Instead of providing what's already out there, a PoC exploit for DiskSaavy Enterprise, we're going to be looking at the steps required to come from using an application to generating a crash, to weaponizing that crash.  

The first thing you'll need to do is grab the vulnerable app: Exploit-DB

In fact, I'd grab two copies of it-- one for a server machine, and one for a client.

DiskSaavy includes a management server and a client application.  The management server is accessible via port 9124/tcp, as well as a web server running on a port of your choice.  We're going to be focusing on the 9124/tcp port first, and in another post may look at another exploit for DiskSaavy that targets the webserver.  Unfortunately, there's no RFC available for this particular protocol, and I can't seem to find any info on packet breakdowns, so we're gonna have to spend a bit of time learning how it works.

0x01 - What do these packets look like?


Install the app on two windows machines, one that acts as your 'victim' and the other acting as a client.  Boot up Wireshark on your victim (server) machine, set it to listen, and make a connection to it from your client.

Note: You can also get away with running only one Virtual Machine, by utilizing your host machine as the 'client' and 'attacker' machine.  I don't necessarily advise this, as this is a piece of vulnerable software.

Below is a screenshot of a PCAP of the incoming connection to my server machine:


Quite a few packets were generated for that incoming connection, we won't worry about all of them for the time being, let's just focus on a bit at a time.  We see our initial SYN,SYN-ACK,ACK, then what appears to be a query from our client machine for information, followed by two responses, one likely confirming receipt of query, the next responding with an answer.

One great thing about Wireshark is it's ability to break down packets into separate parts.  To a noob like me, this is immensely helpful, as we can see what parts of the packets are areas we want to focus on.  We know we probably don't want to be messing with the top three sections of the packets too much (Ethernet, IP, TCP) and likely want to be focusing on the data section.

Note: We will be modifying the Ethernet / IP portions of the packets later on, just to change the source IP and source MAC values to our attacking machine.

Okay, export the stream to a pcap and let's move on.

At this point we've captured some traffic and thanks to Wireshark, have a decent idea of where we'd like to start modifying data.

0x02 - Enter Scapy


Scapy is a python application for modifying / sending / receiving packets.  It's a really powerful application and can be extremely intimidating at first.  I'm completely overwhelmed with it's capabilities, but there's no better way to become better at using something then, well, using it.

Scapy may not even be a prime candidate for what we're going to be doing, but let's interact with some packets anyway.

If you're not familiar with Scapy (at all), go do a bit of reading on what it is and how to use it.  There's a Cheat sheet from SANS available here and an awesome article from thePacketGeek, here that should get the fundamentals down.


Here I have read in the pcap file to scapy, and read out the first 'relevant' packet, our client's query.  Scapy breaks the packets up by layer and allows manipulation of the fields within each.  For instance below, we interact with the ethernet layer to modify the source Mac address:

packets[3][Ether].src = '00:00:00:00:00:00'

Pretty simple!

We're really only interested in the data bit, as we'll be utilizing Spike to fuzz the server, but for the time being, let's modify some of these packets to the server and see what responses we get.  Originally, I thought the first step would be to modify the source IP and MAC values then simply send the packets along.  It turns out, without modifying the TCP sequence numbers on the packets you'll get retransmission errors, which makes sense.  Rather than modify the sequence numbers, I decided it would be better to implement an automated three-way handshake.  As it happens, Spike already performs a three way handshake when it is started up, but let's get more acclimated with scapy, anyway.

A few minutes later and we've a rather rudimentary script:


One thing you may run into when sending your three-way handshake is your kernel sending a RST packet once the SYN,ACK is sent back from the victim machine.  The attacking machine's kernel sees the SYN,ACK, but has no associated open socket and sends a RST back. (I'm not sure if this is also the case when running scapy in windows). To get around this, you'll need to block your kernel from sending RSTs via iptables.

Running the script, we get effectively the same communication we see in our initial pcap, save a few packets:


So, now that there's an easy way to send packets, let's spend some time 'dissecting' the raw data that's being sent.

The payload being sent to the application appears to be broken into two separate parts, delimited via a space.  Removing the space and re-sending the packet gleans some interesting results, Wireshark gets pretty upset with us and it's clear the packet wasn't handled correctly.  Interestingly however, a few more changes results in a crash, for instance below:

rawData = "u\x19\xba\xab\x03\x00\x00\x00\x01\x00\x00\x00\x1a\x00\x00\x0A " /
"\x00\x00\x00\x00\x00\x00\x00SERVER_GET_INFO\x022\x01Data\x010\x01\x00\x00\x00`\xc0\xf1\x02"



This is a pseudo-unexpected turn of events-- we are certainly attempting to make the application crash, but it wasn't expected quite so soon, nor so easily.  After some exploration, it quickly becomes apparent the last four bytes of the first section (pre-space delimiter) of our payload are being put into the ECX register, and we control them.  This is good news, as it suggests that this crash might just be exploitable, and not a dead end.  Either the application is attempting to parse ECX and getting mangled up, or it's attempting to perform an operation that's dependent on what's in that register.

In reality, something else entirely could be happening, but I have no idea.

I touched up my scapy script to functionize and break down the packet being sent into separate chunks, which allows me to easily modify byte values later, if I find this crash can lead to an exploit.  I played with sending different values to the application manually, but found that time consuming and not too helpful, as expected.  At this point, I decided to try fuzzing with SPIKE.

0x03 Enter SPIKE


SPIKE is, uh, confusing... to say the least.  It has what I feel is a pretty steep learning curve, but it's also pretty cool.  It's one of those applications that you figure out how to work with, by working with it.  It's painful, poorly documented and no longer maintained.  I actually ended up shying away form using SPIKE for this particular application, as it has some limitations that ended up proving really hard for me to circumvent without straying away from what I was currently focusing on.

SPIKE is a proven fuzzing platform that takes 'spikes' written in c as input for packet generation.  The first thing I did was to break down the packet similarly to how I had done with the scapy script.  SPIKE accepts different input in the form of binary values, strings, blocks, and much more.  As an example, if we wanted to send a static string to our application, one that read 'Hello, World!', we could create the following spike and send it off:

s_string("Hello, World!");

That's... quite literally it.  You can then run SPIKE by using the following syntax:

$ generic_send_tcp example-script.spk 0 0

Pretty simple.  There's also a generic_send_udp, generic_listen, generic_chunked, and more.

SPIKE will then start "fuzzing" from locations we gave it, in this case, 0 0.  There's two things to note here-- one, I said "fuzzing" for a reason.  We didn't actually tell SPIKE to fuzz anything.  Now although that does seem a bit odd, we told SPIKE to send the string "Hello, World!", not perform any actions on it.  To actually fuzz the string, we need to call the 's_string_variable();' method instead.  The variable portions tells SPIKE that this is not to be considered a static string, and that it's value should be tampered with.  The second thing to note above are the positions 0,0.  SPIKE interprets the first position as the starting variable to fuzz, and the second as the test position.  SPIKE sends many, many different strings at the application.  Perhaps you know from playing with SPIKE that the first 1000 strings it fuzzed did not produce any odd behavior, but you stopped the script to make some changes.  Not a problem, sending 0,1000 will start at the 1000th fuzz string and continue on as if nothing happened.

In this case, we have multiple string values, and multiple binary values that we will be sending to the application.  We can cut down on the number of values / types of values to fuzz by sending only the hex equivalent values of our legitimate packet, as well.

SPIKE has many more possible methods to call for fuzzing different types of data, and can essentially be customized as much as you want to add more data types, etc.  My knowledge level is not great enough to modify SPIKE on a whim, so I started looking at any documentation on types of functions that can be called.  The following three articles provided quite a bit of insight into using SPIKE, though many of the functions that are called were non-existent in my version, as they were custom:

Fuzzing Frameworks

Fuzzing Slides

Advanced Protocol Fuzzing

Introduction to Fuzzing

All of SPIKE's methods are available within 'spike.h'.  Do a locate and start looking into it.

I then made SPIKE send the data we knew worked.  That was pretty simple, and only involved dumping the hex of the valid packets data portion directly into s_binary();  The next step was breaking down the packets into different sections, and isolating the portion that gets plugged into ECX, for kicks:

s_binary("7519baab0300000000000000");
s_binary("1A000000");
s_binary("20000000000000005345525645525f4745545f494e464f0232014441544101300100000060c0f102");

A more targeted approach:

s_binary("\\x75\\x19\\xBA\\xAB\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00");
s_binary("0x1A000000");
s_string("SERVER_GET_INFO");
s_binary("\\x02");
s_string("2");
s_binary("\\x01");
s_string("DATA");
s_binary("\\x01");
s_string("0");
s_binary("\\x01\\x00\\x00\\x00");
s_string("`");
s_binary("\\xC0\\xF1\\x02");

Although the first spike is clean and straightforward, the second spike is preferable in it's compartmentalization of data.  It allows us to suffix '_variable' to the end of any s_string method and start fuzzing on those parameters.  Below, I changed the s_string("SERVER_GET_INFO"); to s_string_variable, and we see the results

As you can see, the second 'batch' of packets sent to the application shows the start of the string fuzzing.  Without adding new methods to spike, I'm at a dead end as far as fuzzing hex is concerned.  SPIKE is mainly meant for fuzzing integer and string values, therefore it certainly could come in handy later on.

Well it pretty much immediately did.  I went for a quick run and relaxed for a bit afterward.  As I was sitting, I had a decent idea-- I know that the application is processing the string commands, i.e. 'SERVER_GET_DATA' but when previously fuzzing I hadn't generated any crashes.  That's fine and kind of makes sense as far as what we know about the application goes; the server processes the headers of the packet and if those are correct, expects specific data.  In the event it does not receive the data it is expecting, it kills the connection (so far, no crash has been generated other than the ECX one I found early on).  That doesn't mean the server won't have an issue at some point, we just haven't found one.

Anyway, the only way to know what data is being processed, ignored, etc, is to be able to see that data.  It's ultra hard (from what I have found) to locate data that's being actively processed.  Looking at Olly while fuzzing shows us thread upon thread is being created and terminated, over and over.  We could start tracing on thread creation, but I found that takes foreveeeer in some cases, and wasn't as helpful as I'd hoped with my current skill set.

However, what we can do is generate a crash, with data we want to locate in it.  That way, when the application crashes we can take a look through memory to see where our values pop up at crash time, perhaps there's something useful... and indeed, there is.

I first started with normal string values:

C x 4    [4 bytes]
A x 4    [4 bytes]
C x 100  [100 bytes]

In the first two cases, no crashes occurred, which I thought was kinda odd.  I was under the impression that we sent a packet that should have crashed the application.  Well, turns out, sort of.  There's a length limit in play here.  Sending the third payload, 100 C's, results in a crash.  Not our normal crash though, this one is much better:



Well, we have data in the EBX register now, as well.  We control the address ECX points to and we control the instructions in EBX's data segment.  That's awesome, after tampering a bit, it looks like 15 bytes will cause the crash, any less and it's handled properly.  I found out something interesting at this point, which taught me a good lesson for the future.  EBX has held the data I thought I had just written into it, the whole time.  What I mean is, previously, prior to changing the 'SERVER_GET_INFO' string, it was already pointing there.  Therefore, we could have already known that we control that data, in fact, we already knew.

This taught me a good lesson on taking a closer look at what registers contain at the time of crash.  I had taken a look, but clearly not very closely, as I hadn't put two and two together.

After fuzzing almost all of the different pieces of the packet (just in case some were stored in different parts of memory) I found that I can fit a maximum of 32 bytes into the buffer.  That seems a bit odd, though.  From what I've seen in available exploits, it looks like our buffer space should be larger-- much larger in fact.

This got me thinking... and again, I learned another very valuable lesson.  The available exploits were for Windows 7.  I'm on Windows 10.  Now, this isn't always an issue, I've recreated exploits meant for systems other than what I'm running them on in the past, but I'm not sure I can work with this.

So I took a step back, and restarted on Windows 7-- something we know works, in the next post.

Comments

Popular posts from this blog

06 - How to maybe not be so bad at fuzzing, Part 2

07 - Just Another OSCE Review

05 - How to maybe not be so bad at fuzzing, Part 1