Hacking HTTP with HTTPfuzz
So you’ve been given a web app to pentest. Maybe it’s a banking app or a document workflow system. Either way, you need to make sure it’s done safely. Modern web applications have a large attack surface, and testing everything by hand is inefficient. That’s where fuzzers come in handy. Fuzzers allow you to generate new inputs based on a seed and pass them to a program. Fuzzing can quickly show areas that are worth further examination.
I’m going to walk you through finding bugs in the Damn Vulnerable Web App (DVWA) with HTTPfuzz, but you can apply this steps to any target as long as you have permission from the owner. HTTPfuzz is a flexible HTTP fuzzer written in Go. It can fuzz any part of a request: multipart file uploads, multipart form fields, text request bodies, directories, filenames and URL query parameters.
Attacking services without consent is illegal in most countries. You can follow along using Docker on your computer without risking your freedom. Be sure to stop the container when you’re done using it, and only bind it to localhost to prevent yourself from getting hacked.
A fuzzer is a very clumsy tool. It can knock systems offline, lock user accounts, fill up databases and generally annoy our friends on the blue team. I’d recommend only running a fuzzer against a development instance of the app. It’s useful for finding bugs before the software goes to production. Don’t run a fuzzer on a shared application unless you’re sure your inputs won’t cause damage and you have permission from the operations team. It’s best to set a delay between requests if you’re running HTTPfuzz against a shared application, and be sure to check how many requests you’ll send before firing your lasers.
What is HTTPFuzz?
HTTPfuzz is a flexible CLI HTTP fuzzer written in Go. It supports fuzzing any part of a request body, including multipart file uploads, JSON fields, HTTP Headers and URL parameters. HTTPfuzz can be extended with Go plugins for better integration with your pentesting workflow.
HTTPfuzz plugins are simply Go plugins that export a method named New that returns an implementation of HTTPfuzz’s Listener interface. Everything you need to know to write plugins is in the gist below.
A Listener receives a stream of Results from the fuzzer. A Result contains the HTTP response from the target, the corresponding request, the payload, payload location and the time the request took. Plugins can use this to save requests and responses to a database, check for vulnerabilities and anything else you can think of.
Many apps allow users to upload files for all kinds of reasons: photo galleries, documents, scanning cheques and much more. File uploads expose tons of attack surface. XSS, path injection, introducing malware into a network, remote code execution and so much more is available to you by bugs in file uploads. DVWA is no exception.
Automatically Generated Files
The easiest way to check which file types are allowed is simply uploading different kinds of files and looking at the responses. If a website says it only accepts photos, try uploading a PHP file or an executable and see what happens. For example, JPEG photos always start with the bytes FF D8 FF. You can use a hex editor like Hex Fiend to see the byte patterns at the beginning of every file of the same time.
If the whitelisting is done correctly, it will check the first few bytes of the uploaded file against a list of expected file signatures. HTTPfuzz generates files by putting header bytes for the file type at the top of a byte array filled with random bytes. These generated files will probably not be valid, which is why you’d use user-supplied payloads once you’ve determined how restrictive the validation is.
We can combine this with a simple plugin that tells us when a file has been successfully uploaded to let us enumerate the allowed file types.
Build the plugin and send off the automatically generated file payloads. We’ll be able to see what’s allowed based on what is successfully uploaded.
Running this reveals that DVWA does not perform any filtering at all on uploaded files: it’s a free for all.
Now that we know what kind of files are allowed, it’s time to see if any vulnerabilities can be exploited. We should see if we can exploit bugs in how DVWA handles filenames and types based on what we discovered with the automatically generated files. Since we know DVWA doesn’t perform any filtering, we should try for PHP code execution.
PHP Code Execution
One of the payloads was a PHP program that would display information about the server’s PHP environment. Since DVWA has a file inclusion vulnerability, we can execute our payload by passing the saved payload’s filename to the vulnerable “page” URL parameter.
We could stop here since we owned the box, but I want to show you some more HTTPfuzz features.
You can mark targets in text request bodies with the delimiter character. By default, it’s “`”. The command injection challenge sends an IP address via POST request to a vulnerable ping function. You can often find vulnerabilities like this on routers and online vulnerability scanners. Consider the following request:
We’re trying to execute code on the DVWA. We’ll try the Unix and Windows command injection payloads from the command-injection-payload-list and examine the results in an intercepting proxy to see if any of these give us a clue how to exploit the vulnerability.
HTTPfuzz makes it easy to brute force your way into valid accounts. The DVWA has a brute force challenge that accepts the username and password as GET parameters. Consider the HTTP request below.
First, we’ll need a wordlist with common passwords. I’ll use rockyou.txt for this demonstration. We’ll also need to differentiate between successful and unsuccessful login responses. An easy way to do this is to submit an invalid password and observe the response.
Trying to send a bad password gives an error message. That’s good enough for us. We can create a HTTPfuzz plugin that returns the payload used when that error message isn’t in the page. That payload should be the password.
Build the plugin and pass it to HTTPfuzz to see if admin’s password is in rockyou.txt. Since the password is in rockyou.txt, the plugin will print it so we can solve this challenge.
Running this attack shows that the admin’s password is indeed in rockyou.txt. This attack may seem contrived, but many appliances and programs have known default passwords. The Mirai botnet spread by brute forcing known default router passwords via telnet.
You can check out httpfuzz on GitHub. It’s written in Go and GPLv3 licensed. It runs on Windows, Linux and macOS. It’s a versatile HTTP testing tool that can perform many attacks, like dirbuster style directory brute force attacks and HTTP header fuzzing.