reFORMer sample documentation

Author:Josh Stone
Contact:josh@josho.org
Date:2010-07-10
License:GPLv2
Source:reformer-v0.5.tar.gz

Table of Contents

0 ChangeLog

  • 2011-01-27 v0.5   Added support for "100 Continue" responses

1 Introduction

I have grown frustrated with the lack of flexible tools available for executing a brute-force attack on HTTP login forms. Some are available, for example, Brutus is one of the better options out there, but still leaves some room for improvement. Another great option is Burp Suite and its intruder mode, but the free version features a rate-limiting behavior that makes it completely impractical for field use. Hydra is also a great tool for brute force attacks, but its HTTP mode assumes only the simplest of targets.

What do I mean by "flexible"? I want to have absolute control over the HTTP request sent for each brute force attempt. What if I have to set a cookie? Not all tools let me do that. What if I need to change an encoding, or insert unusual characters? What if the HTTP method is not GET or POST? Ultimately, I want something that gives me low-level power without costing money.

reFORMer is my little contribution as an attempt to shore up this small gap in the penetration testing world. This initial version is very limited in features, but is at least flexible enough for me to do the things I need to do, even if it means a little extra work in preparation. This document describes the use of reFORMer with a simple example. If you have a good handle on HTTP and the way your target functions, this is a good enough shell for getting started.

2 The Sample Environment

This demonstration concerns a simple web-based login form. In truth, this particular form could easily be brute-forced with the other tools mentioned above. However, this is only an example, and it is expected that the reader may be able to identify opportunities for applying this simple tool to more complex forms in "the wild."

This particular form provides two fields for a user to fill out in order to login. This login form can be seen in the image below. Since the promised reward for compromising this form is some number of secrets, I am all the more excited to execute a brute force attack on this application.

3 An initial attempt

The first thing to do is try a simple login attempt. In this case, I think I typed in "admin" for username and "admin" for password. As anyone should know, this should get me in 38% of the time (remember, 73% of all statistics are made up on the spot).

Now, before submitting this form, I want to remember an important axiom: don't waste the first authentication attempt. Prior to clicking "Submit Query", I'll start up Wireshark to record the network traffic involved with this request. Why, you might ask? This will become important if "admin" is, in fact, not the right password. So, with my sniffer running, I submit the form. The web browser takes me back to the login form (not shown), but Wireshark has plenty of information for me to review.

4 Setting up the request

The highlighted packet is the actual POST request that submitted my username and (incorrect) password to the site. This is all very interesting, but what I want to see is the raw HTTP request itself. I can accomplish this with Wireshark's follow tcp stream feature, as demonstrated below.

Ah, that's much more useful to a real human like myself. The highlighted portion is the request that was sent by my browser. The rest (starting with "HTTP/1.1 200 OK") is the response. I want to preserve this request, so I'll copy it and paste it into a text editor. Note that the request incorporates a payload in which the username and password are specified as normal HTTP parameters. I want to change these to a placeholder so that reFORMer can insert different values for each authentication attempt. This is depicted in the screenshot below.

As you can see, the placeholders I chose are "%USER%" and "%PASS%". These are selected because they don't collide with any other text in the request, so I know that the insertions performed by reFORMer will work properly. Note also that I have removed one line – this is the "Accept-Encoding:…" header. reFORMer does not currently understand compressed encodings, so I have to take this out. If I don't, the responses will not be properly matched for identifying success. This file is saved as "req.txt".

5 Preparing the dictionary

The next thing I want to do, which is normal for any brute-force attack, is prepare my dictionary. This is a list of all the guesses for username and password that I want to make. In this case, I'll make my first brute-force attempt with a very small dictionary (gambling on early success!). I create a file with a certain format as shown in the following screenshot.

I'm calling this the "symbol file." It's not just a dictionary, because I may need to insert things other than just usernames and passwords if the form login is very complex. For example, suppose I needed to modify session cookies, or numeric values for each attempt – I could use additional symbols to accomplish this. Anyway, the rows in this file are a little significant:

  • The first row is a list of symbols describing each column
  • The second row lists the corresponding placeholders in the request
  • The remaining rows are the values for each authentication attempt

This file is saved with the filename "sym.txt". Note that in a complex situation, I might write a script to generate this file. That way, if I wanted to try multiple usernames with multiple passwords, this could easily be manufactured with a few loops.

6 Executing the attack

Now, I will execute reFORMer at a command shell. The program takes several arguments for doing a regular expression match on authentication responses, which are listed below:

  • hostname or IP address of target server
  • TCP port number for web server
  • filename for raw request with placeholders
  • filename for symbol file with values to insert
  • type of test to use to determine success
  • success regexp that indicates a successful login

I do intend to extend reFORMer so that if a success string is not known, other criteria may be defined to determine success. For example, the HTTP response code could be a clue. Also, making it a "failure string" might be a good idea. In some cases, just recording the size of the returned page could be a clear indicator – or even the changing or setting of a cookie. These methods are supported, but discussion is relegated to the end of this documentation.

At any rate, the attempt running reFORMer goes like this:

Yeehaw! One of my attempts worked. It looks like the password for the "admin" user is "password". I know, you may be thinking that this is completely unrealistic – that no one would really use such a silly password. However, in my experience, I would never call this unrealistic ;-).

7 Payoff

A simple test with the right password in the login form logs me in, and I can behold the secrets!

So there you have it, a quick run through how to use reFORMer to perform a relatively low-level brute force attack on a web-based login form.

8 Other ways to do it

8.1 Testing size of responses

Suppose I don't know anything about the response that will be received in the case of a successful authentication. Or, for example, perhaps the response is dynamic enough that matching text in the response is unreliable. One way of identifying different responses is to test the length of the response. reformer supports such a mode, using the "size" detector. Here is another run of the tool in this same example with this detector selected:

As you can see in the response, all attempts returned 371 bytes except for one – the request for which the password guess was "password". This is a clear indicator that there may have been a successful authentication in that case.

8.2 Testing a failure string

What if I don't know what the successful login page looks like? Maybe I can make some assumptions and test for a "failure" string. For example, maybe it is plausible that the successul response will not contain within it the login form. This is very likely, as web applications go, so we can do the inverse of the original test above – test for a known string that indicates a failed authentication attempt:

This output is nearly identical to the original scan above, but note the difference in arguments. This is still a regular expression, so we can define more complex matches if we need to.

9 reFORMer usage statement

atlantis $ reformer

reFORMer version 0.2, Copyright (C) 2010 Josh Stone (josh@josho.org)
reFORMer comes with ABSOLUTELY NO WARRANTY; it is licensed under the
GNU Public License (GPL), version 2

usage: reformer <host> <port> <request> <symbols> <detector> [parameter]

  <host>      Hostname or IP address of target system
  <port>      TCP port hosting target web server
  <request>   Text file containing raw HTTP request to send
  <symbols>   Comma delimited text file containing symbol data
  <detector>  Detector to use for identifying success
  [parameter] Optional parameter for success detector

Supported detectors:

  reg        Use Regular Expression success detector
  nreg       Use Regular Expression failure detector
  size       Use response size analyzer as success detector

Symbol file format is as follows:

  Line 1:  comma delimited symbol names (e.g., user,password)
  Line 2:  comma delimited substitutions (e.g., %USER%,%PASS%)
  Rest:    comma delimited values (e.g., admin,admin)

Note that request file should have substitution symbols inserted
where appropriate, so they can be replaced with the values from
each row of the symbol file.  For example, the 'content' portion
of the request file might look like this:

  user=%USER%&pass=%PASS%&val=something

Author: Joshua Stone <josh@atlantis>

Date: 2010-07-11 09:13:44 CDT

HTML generated by org-mode 6.30c in emacs 23