Manually Brute Forcing Against Form Tokens.

Last week I ran into a situation where I needed to manually brute force a webapp login form that used form tokens to request authentication. Our client wanted to see how far we could get in a black box scenario. The unauthenticated portion of the webapp was nothing more than a typical login page complete with registration and password reset functionality. As a result the attack surface was small. During recon we found another subdomain hosted by the client that housed a searchable database of “people that use this particular system”. Of interest was the fact that each individual’s entry contained their username for the webapp we were testing. The only limitation was a maximum of 15 results per query.

I decided to approach this in two steps with two different shell scripts for added control. First I needed to scrape usernames from the searchable database. I could then use those usernames to brute force the login form and gain entry to the webapp.

Scraping Usernames

In order to extract the usernames I used cURL and awk. If you are not familiar with how to effectively use these tools to automating mundane pentesting tasks, you need to get there. Two steps were taken to get a list of usernames:

  1. Search a name, John for example, and extract the URL for each result.
  2. cURL the individual results and extract the usernames.

I compiled a list of names to search using the top 100 male and female names in the US from the Social Security Administration, and a list of the top 1000 surnames (link). Below is the script I put together (github):

scrape
Description: Lines 7-10 loop through the name list. In line 9 I use cURL to send a post request to http://www.client.com/index.php with the data “name=$i&search_other_name=title”. The $i variable is the current name being iterated. -s silences the cURL output. The results returned are piped into awk. /view\=/ tells awk to print any lines with view= in them. gsub(/.*view\=|’\”\>[A-Z].*/,””) is used to extract everything between view= and ‘>. I am going to break this down real quick:

  • The string gsub is being applied to: <a href=’?view=stringtobeextracted’>John Smith</a></td>
  • gsub is used to replace everything before and after the desired string with nothing (“”).
  • Period asterisk (.*) functions the same as an asterisk wildcard in Windows. 
  • .*view\= will match everything prior to and including view=.
  • ‘\”\>[A-Z].* will matching everything after and including ‘>. ‘\” is how a hyphen is escaped. \> is an escaped greater than sign. [A-Z] is used to specify any uppercase letter.

The strings extracted are appended to page_id.txt. Lines 12-15 loops through a sorted, uniqued list from page_id.txt. cURL copies down the user’s page with a GET request, and awk extracts the username. Lines with Username: are printed. Everything from Username:</td><td> back and  </td forward is replaced with nothing as before. The resultant username is printed to the screen and appended to a usernames.txt file with tee. The results were great. I compiled a list of over 8800 usernames with this script. Here is some sample output:

Screen Shot 2015-08-22 at 9.02.13 PM

Brute Forcing

During testing I immediately noticed that authentication was being submitted with a unique token. Hoping I was wrong, I tried several iterations with Burp Suite’s Intruder using the same token. No joy. This token was generated each time you visited the login form. I needed to pull a token for each authentication attempt for each username I found. The result is another script with cURL and awk as the headliners (github):

brute

I elected to take a controlled approach by specifying a single password and kicking each pass off manually. This is simply a preference for control and can easily be automated with a password list. For the sake of clean looking output and tracking where the script is at in the process, I used a $count variable to track the iteration number. Line 14 increments $count each iteration where it is then used in the if statement. Line 15: cURL sends a GET request to the login form page. The line containing the form token look like this: login.form.token=”23lk4-23423kk-se23″;. Awk identifies this line by matching login.form.token. The delimiter is set to a parenthesis using -F”\””. This splits the line into three columns:

  1. login.form.token=
  2. 23lk4-23423kk-se23
  3. ;

{print $2} tells awk to print the second column. The token is stored in the $form_token variable. The $form_token is used in line 16 to define the POST parameter uid. In this line, cURL sends the POST login request which includes the current username, password, and form token in the parameters. At this point I had to identify something unique in the response to differentiate between successful and unsuccessful logins. I chose the obvious line “Error: Failed Login”. At the end of line 16, I use grep to extract that line and assign it to the $result variable.

Lines 17-22 is a basic if-else statement that will print results for the authentication attempt. [ -z “$result” ] checks for null string values in the $result variable. If there is no “Error:” match, a null string value is assigned to $result and the “if” statement is true.

Screen Shot 2015-08-22 at 9.04.56 PM

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s