RedTeam Pentesting GmbH - Blog

2 December 2020

Introducing monsoon ‒ a Lean and Versatile HTTP Enumerator

We recently released our first open-source project, monsoon. monsoon is a so-called command-line HTTP enumerator: A tool that iterates over a list of values, for example a word list or a range of integers, and sends one HTTP request per item towards a given server. The target server, path and HTTP headers can be configured on the command line. There, one can replace parts of the HTTP request with the placeholder FUZZ. All its occurrences are replaced with the current item during each iteration. Optionally, monsoon can filter or even parse the HTTP response.

monsoon can be very helpful during penetration testing and in this blog post we would like to motivate its development and introduce some common scenarios that can be tackled using monsoon.

Motivation

There are quite a few similar software projects on the internet, namely DirBuster, gobuster, wfuzz or ffuf. We have used some of them during penetration tests and while these might be great tools for certain jobs, we felt that none of them reflect our penetration testing workflow very well.

Penetration tests at RedTeam Pentesting mostly consist of a manual, creative search for vulnerabilities, since we, as well as our customers, feel that this is the most efficient way to deliver high-quality results. However, this does not imply that we do not use automated tools for highly repetitive tasks, such as port scanning or brute-force attacks. In order to integrate corresponding software into our creative workflow, tools have to be very versatile. The most versatile tool sets are made up of multiple single-purpose, easy to use tools working on open/standardised data formats. Great examples can be found in the basic Unix tool set: cat, grep, cut, head, tail, … all of which act on simple text streams and strive to fulfill a single purpose.

Thus, our goal when developing monsoon was to stay close to the minimally necessary feature set for an HTTP enumerator and to add new features only if they are actually relevant for our penetration testing workflow. The first commits to the monsoon repository are from 2017; since then we have used and refined monsoon in many many penetration tests.

Note: The applications analysed in this blog post have been developed specifically for the purpose of demonstrating monsoon. All names, addresses and other data are purely fictional.

File and Directory Discovery

The most common usage scenario for monsoon is the discovery of files or folders which are served by a web server, but are not directly linked from any previously known page. This might for example include administration panels, different applications or remnants of development, such as debugging endpoints or even source code. If these resources are not protected by separate authentication, any attacker who knows the corresponding URL can interact with them.

This is where monsoon comes in: monsoon allows us to query many URLs in sequence, with the goal of guessing URLs to aforementioned hidden resources. In this process, our success rate depends on the speed and quality of guesses. A good starting point for guessing hidden file and directory names is the SecLists project by Daniel Miessler. SecLists is a large collection of word lists for many different purposes. The files that we are interested in during this attack phase are contained in the folder Discovery/Web-Content. Among others, the folder contains the RAFT word lists originally compiled by FishNet Security, such as raft-small-files.txt and raft-small-directories.txt.

The following screen cast shows an invocation of monsoon on a sample application with the goal of discovering hidden subdirectories below the path /app:

The HTTP responses are summarised in the result table. With the command-line option --hide-status set to 404, we have hidden 996 responses for which the web server has responded with 404 Not Found. We’re rather interested in the four results for which the web server has responded with status code 302, indicating a redirection. It’s a very common behavior of web servers to redirect requests from /foo to /foo/ if the directory foo exists. In this case there are several interesting directories, such as internal and phpMyAdmin which we subsequently would inspect manually.

Enumeration

Another common scenario is the exploitation of a so-called insecure direct object reference (IDOR) vulnerability. Such vulnerabilities exist whenever access to a resource only depends on a predictable reference, such as a numerical ID, a known algorithm generating a serial number or otherwise obtained UUIDs. Imagine a web application where data for your user profile is fetched from the endpoint /api.php?userid=11:

$ curl -s 'http://app.example.com/api.php?userid=11' | jq
{
  "Id": 11,
  "FirstName": "RedTeam",
  "LastName": "Pentesting",
  "UserName": "rtpt",
  "Email": "jobs@redteam-pentesting.de"
}

What happens if /api.php?userid=10 is requested? In this example, we assume that the analysed web application does not intend to offer the functionality to display other users personal information and should therefore deny the access to it. Despite the intention of the web application, user data is returned which indicates an IDOR vulnerability:

$ curl -s 'http://app.example.com/api.php?userid=10' | jq
{
  "Id": 10,
  "FirstName": "Ben",
  "LastName": "Grimm",
  "UserName": "b.grimm",
  "Email": "b.grimm@example.com"
}

We often use monsoon in this scenario in order to demonstrate the impact of such a vulnerability to our customers. With the -r/--range option, monsoon iterates over ascending integer numbers instead of a word list. This is demonstrated in the following screen cast:

That was fast! Note that the results appear out of order because monsoon by default sends five concurrent requests. Furthermore, we have parsed the JSON response with the command-line JSON parser jq. Its output (the fictional person’s name) is displayed in the result table.

Additionally, monsoon can perform basic content extraction without an external process. For this purpose, one can provide a regular expression to the --extract parameter. monsoon will try to match the regular expression to the HTTP response body. If one or more matches have been found, the content of the first capture group of each match will be displayed in the results table. This can be useful if, for example, you want to extract content from responses containing HTML. Imagine the following endpoint:

$ curl -s 'http://app.example.com/dashboard.php?userid=11'
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Profile of RedTeam Pentesting</title>
    </head>
    <body>
        <h1>Profile of RedTeam Pentesting</h1>
        <table>
            <tr><th>Key</th><th>Value</th></tr>
            <tr><td>First Name</td><td>RedTeam</td></tr>
            <tr><td>Last Name</td><td>Pentesting</td></tr>
            <tr><td>Email</td><td>jobs@redteam-pentesting.de</td></tr>
        </table>
    </body>
</html>

Here, we can use the regular expression <title>Profile of ([^<]+)</title> to extract a name from the title. Watch to see monsoon quickly extract names from our sample application:

Brute-Force

HTTP requests are not always as straight-forward as the ones shown before. You might encounter requests which require certain HTTP headers or some complex body structure. In those cases it might be easier to start from a known HTTP request, one that has for example been captured with an HTTP attack proxy like ZAP. One example could be the following login request to a our sample application:

POST /login.php HTTP/1.1
Host: app.example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://127.0.0.1:8080/
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

username=admin&password=FUZZ

We save this request as a file with the name login-request.txt. As the request body shows, we would like to authenticate with the username admin, but we don’t know the password (yet). Therefore, we substitute the password parameter with the placeholder FUZZ. Now, we can specify the file name login-request.txt as the value of the --template-file parameter. For the URL we only have to specify the correct server, as this cannot be deduced from the template file. Note that some fields such as the Content-Length header will be automatically adjusted by monsoon.

Again, decent word lists to start from can be found in the SecLists project. This time, we will use a word list from the Passwords directory. Most files in this directory contain common passwords and default passwords. For this demonstration, we will use the word list xato-net-10-million-passwords-10000.txt which has been originally compiled by Mark Burnett (xato.net). The invocation with the aforementioned template file is as follows:

Et voilá, we discovered that the password is wonderful! 😁

Conclusion

monsoon is a very versatile HTTP enumerator suited for penetration testing of web applications. Its limited feature set helps the project stay lean while allowing for creative use. In the end, it’s a tool, developed to support your creative workflow.