Comprehensive Guide to Fuzzing with Spike

In my previous post on Boofuzz, we explored how powerful fuzzing can be in uncovering vulnerabilities in network protocols by automating the injection of malformed data. While Boofuzz provides an intuitive and Pythonic approach to fuzzing, there’s another tool that’s a classic in the fuzzing toolkit: Spike. Known for its raw power and simplicity, Spike is widely used in penetration testing for fuzzing network protocols, especially in situations where you need a fast, direct fuzzing solution.

This blog will dive into Spike, from the basics of setup and scripting to advanced techniques that allow for protocol-specific fuzzing. We’ll cover everything from how to construct Spike scripts, handle protocol-specific edge cases, and analyze outputs, making this a complete guide for those looking to expand their fuzzing arsenal.

Installation

Installing Spike on Kali Linux is straightforward, as it’s included in the Kali package repository. To begin, ensure your system is up-to-date:

sudo apt update && sudo apt upgrade

Then, install Spike using the following command:

sudo apt install spike

This will install the main spike package, along with its additional binaries and dependencies. The complete installation size is around 3.77 MB, making it lightweight yet versatile.

After installing the Spike package, you should see a suite of specialized binaries designed for different fuzzing tasks. These binaries include:

citrix                   - Fuzzing Citrix services for vulnerabilities
closed_source_web_server_fuzz - Fuzzes closed-source web servers by targeting HTTP methods and file extensions
dceoversmb               - Fuzzes DCE/RPC over SMB for buffer overflow and similar flaws
dltest                   - Tests the loading of `.spk` Spike script files for debugging
do_post                  - Sends HTTP POST requests for fuzzing web services
generic_chunked          - Fuzzes web servers with chunked HTTP encoding
generic_listen_tcp       - Sets up a TCP listener to handle incoming fuzzed traffic
generic_send_tcp         - Sends fuzzed data over TCP to a target server
generic_send_udp         - Sends fuzzed data over UDP to a target server
generic_web_server_fuzz  - Fuzzes generic web servers by sending malformed HTTP requests
generic_web_server_fuzz2 - Advanced version of `generic_web_server_fuzz` with extended capabilities
gopherd                  - Fuzzing target for Gopher protocol testing
halflife                 - Fuzzes servers supporting the Half-Life game protocol
line_send_tcp            - Sends line-based TCP fuzzing input to test line-based protocols
msrpcfuzz                - Fuzzes Microsoft RPC services over TCP to identify potential vulnerabilities
msrpcfuzz_udp            - Fuzzes Microsoft RPC services over UDP
ntlm2                    - Brute-forces NTLM authentication over a specified service
ntlm_brute               - Fuzzes NTLM login processes with various username/password combinations
pmspike                  - General-purpose fuzzing utility for protocol testing
post_fuzz                - Sends POST requests to fuzz web applications and services
post_spike               - A specific tool for fuzzing HTTP POST requests
quake                    - Fuzzing tool for the Quake game server protocol
quakeserver              - Listens for and handles Quake protocol requests
sendmsrpc                - Sends fuzzed data over Microsoft RPC
ss_spike                 - General-purpose spike script tester
statd_spike              - Fuzzes the NFS `statd` daemon, often used in UNIX systems
sunrpcfuzz               - Fuzzes SunRPC services with a variety of arguments
webfuzz                  - Fuzzes web services with custom requests and payloads
x11_spike                - Tests X11 protocol for fuzzing vulnerabilities

Creating Spike scripts allows for precise fuzzing of network protocols and services. A Spike script (typically saved with the .spk extension) defines the structure of requests and payloads sent to a target, making it a powerful way to test custom protocols or non-standardized services.

Basic Structure of a Spike Script

Spike scripts use predefined functions to send data and manage how Spike generates and mutates input fields. Here’s a breakdown of the fundamental components and how they’re used in a Spike script:

1. Spike Script Functions Overview:

  • s_string("text"): Sends a static string as part of the fuzzing request.
  • s_string_variable("variable_name"): Fuzzes by injecting various strings in place of the specified variable name.
  • s_binary("abcdef"): Sends raw binary data, specified in hexadecimal.
  • s_readline(): Read response from server

2. Example: Basic Spike Script for Fuzzing HTTP GET Requests

In this example, we create a simple Spike script to fuzz a web server by sending various malformed GET requests:

s_string("GET /");
s_string_variable("filename");	// Fuzz Filename
s_string(" HTTP/1.1\r\n");
s_string("Host: ");
s_string("example.com\r\n");
s_string("\r\n");

This script:

  • Sends the GET command with a variable filename that will be fuzzed.
  • Specifies the Host header with a static value, example.com.
  • Closes the request with two carriage return/line feed (\r\n) sequences.

3. Adding Custom Fields

For this example, we’ll be using Damn Vulnerable Web Application (DVWA) to demonstrate SPIKE-based fuzzing on a captured POST request to /login.php.

Upon logging in, we capture the following request:

POST /login.php HTTP/1.1
Host: localhost:42001
Content-Length: 86
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="129", "Not=A?Brand";v="8"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Accept-Language: en-US,en;q=0.9
Origin: http://localhost:42001
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:42001/login.php
Accept-Encoding: gzip, deflate, br
Cookie: security=impossible; PHPSESSID=7p7l3t0ob14k2vqmshkqej4os1
Connection: keep-alive

username=joker&password=batman&Login=Login&user_token=e5cabdb39c207c18648e03ba6bacfece

To simplify and focus on fuzzing critical parts, we’ll streamline this request by removing non-essential headers and specifically target the username and password fields for fuzzing. Below is a SPIKE script that we will use for fuzzing:

s_string("POST /login.php HTTP/1.1\r\n");
s_string("Host: localhost:42001\r\n");
s_string("Content-Length: 86\r\n");
s_string("Content-Type: application/x-www-form-urlencoded\r\n");
s_string("Connection: keep-alive\r\n");
s_string("Cookie: security=impossible; PHPSESSID=7p7l3t0ob14k2vqmshkqej4os1\r\n");
s_string("\r\n");

s_string("username=");
s_string_variable("username");  // Fuzzing `username` field
s_string("&password=");
s_string_variable("password");  // Fuzzing `password` field
s_string("&Login=Login&user_token=e5cabdb39c207c18648e03ba6bacfece\r\n");

Save the script above as dvwa_fuzz.spk.

Running the Fuzzing Script with line_send_tcp

Using SPIKE’s line_send_tcp utility, we can direct our fuzzing attempts to the local server at the specified port. Here’s how to execute it:

# Usage: ./line_send_tcp host port spike_script SKIPVAR SKIPSTR
# ./line_send_tcp 192.168.1.100 701 something.spk 0 0
line_send_tcp 127.0.0.1 42001 dvwa_fuzz.spk 0 0

In this command: SKIPVAR and SKIPSTR are parameters used to control the fuzzing process:

  • SKIPVAR: This parameter specifies how many variables should be skipped in the input data when sending the fuzzing payload.
  • SKIPSTR: This parameter indicates how many characters or strings should be skipped from the start of the input data.

By using 0 for both SKIPVAR and SKIPSTR, we ensure that all variables and strings in our script are subjected to fuzzing. This comprehensive approach allows the line_send_tcp command to send a series of crafted requests, iterating through various combinations of inputs for the username and password fields. As a result, we can effectively identify potential vulnerabilities, such as buffer overflows or improper input handling, in the DVWA application.

To observe the equests sent to DVWA, you can check the logs located at /var/log/dvwa/access.log. Alternatively, you can set up a listener using netcat on port 4444 to capture incoming raw rrequests.

Setting Up Netcat Listener

nc -nlvp 4444 -k

With the listener running, you can send your fuzzing requests to port 4444:

line_send_tcp 127.0.0.1 4444 dvwa_fuzz.spk 0 0

Once the command is executed, you should see the captured request in the netcat terminal:

$ nc -nlvp 4444 -k
Listening on 0.0.0.0 4444
Connection received on 127.0.0.1 36448
POST /login.php HTTP/1.1
Host: localhost:42001
Content-Length: 86
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Cookie: security=impossible; PHPSESSID=7p7l3t0ob14k2vqmshkqej4os1

username=../../../../../../../../../../../../etc/hosts%00&password=password&Login=Login&user_token=e5cabdb39c207c18648e03ba6bacfece

Fuzzing Only the Password Field To specifically fuzz the password field (the second field in the request), you need to skip the first field (username). You can achieve this by using the following command:

line_send_tcp 127.0.0.1 4444 dvwa_fuzz.spk 1 0

In this command, the 1 as the SKIPVAR argument tells SPIKE to skip the first variable (username), allowing you to focus on fuzzing the password field.

4. Example: Spike Script for Fuzzing Protocols with Fixed Raw Bytes When working with certain protocols, you may need to prefix your requests with specific fixed raw bytes. For example, if a protocol expects the bytes \xde\xad\xbe\xef at the beginning of the request, you can seamlessly incorporate this requirement in your Spike script using the s_binary() function. The following script demonstrates how to structure such a request:

s_binary("\xde\xad\xbe\xef"); 	// Fixed raw bytes at the start
s_string("test");		// Test string
s_string("\r\n");		// End of line
s_string_variable("FuzzMe");	// Variable to be fuzzed
s_string("\r\n");		// End of line

When listening on port 4444 and examining the output with a hex dump, you can observe the structure of the data being sent. By using the following command:

$ nc -nlvp 4444 | xxd

You’ll see output similar to this:

Listening on 0.0.0.0 4444
Connection received on 127.0.0.1 52158
00000000: dead beef 7465 7374 0d0a 4675 7a7a 4d65  ....test..FuzzMe
00000010: 0d0a 

In this output, the first part, dead beef, represents the fixed raw bytes we prefixed to the request.

Exploring Prebuilt Fuzzing Scripts in Spike

Spike offers a collection of prebuilt fuzzing scripts located in the /usr/share/spike/audits/ directory. These scripts cover a variety of protocols and applications, making it easier to start fuzzing with minimal setup. Below is a list of some available audits:

$ ls /usr/share/spike/audits/
BIZTALK2000  exchange2K  IMAP                       MSSQL   PPTP        SSL
CIFS         FTPD        lotus                      ORACLE  RealServer  UPNP
COMPAQ       H323        MSContentManagementServer  POP3    SMTP

Fuzzing an FTP Server

Let’s concentrate on fuzzing an FTP server by reviewing the script found in /usr/share/spike/audits/FTPD/ftpd1.spk. This script illustrates how to format commands for communicating with the FTP server. Here’s a breakdown of the script:

$ cat /usr/share/spike/audits/FTPD/ftpd1.spk
s_string("HOST ");
s_string_variable("192.168.1.108");
s_string("\r\n");

s_string_variable("USER");
s_string(" ");
s_string_variable("bob");
s_string("\r\n");
s_string("PASS ");
s_string_variable("bob");
s_string("\r\n");

s_string("SITE ");
s_string_variable("SEDV");
s_string("\r\n");

Creating a Directory with MKD Command To create a directory on the FTP server, we can use the MKD command. Here’s how to structure that command in Spike:

s_string("USER ");
s_string("admin");
s_string("\r\n");
s_string("PASS ");
s_string("password");
s_string("\r\n");

s_string("MKD ");
s_string_variable("FUZZ");
s_string("\r\n");
$ line_send_tcp 192.168.245.34 2221 fuzz.spk 0 0

By utilizing the prebuilt scripts and adjusting the variables, you can effectively fuzz your FTP server for vulnerabilities and test its security robustness.

Conclusion

In this guide, we’ve covered the essentials of using Spike for fuzzing, including crafting custom scripts and utilizing binaries like line_send_tcp. However, the world of fuzzing extends far beyond the examples we’ve explored. I encourage you to delve into other available binaries within Spike to expand your fuzzing toolkit. Each binary offers unique functionalities that can be tailored to different protocols and applications, allowing you to enhance your testing strategies.

Happy Fuzzing! 🎉