[HACK CRACK] Abusing Password Resets
Dave Ferguson has beaten up on forgotten/reset password functionality for some time and recently participated in an OWASP podcast where he discussed these problems. The podcast reminded me of some techniques I've used in the past which have been successful and may be worth sharing. Accessing other user's accounts with insecurely coded forgot/reset password functionality is more common than you might think.
This posts focuses on analyzing entropy and inline password resets, two major problems with forgot/reset password functionality. To do this, we have to automate both requesting a forgot password hundreds of times and parsing thru all of the e-mails we receive. Thanks to the recently added macro support now available in Burp (thanks PortSwigger), less effort is required on our part when an application employs anti-automation features to prevent such attempts.
For those not familiar with BurpSuite's Macro support, lets walk thru this.
So here is a picture of the email reset we've been sent:
To initiate a password reset request it is a four part request & response pair sequence. This sequence is saved in our proxy history. We need to navigate to Options > Sessions > Macros > New and highlight the four messages saved in the proxy history to create and configure the new macro.
Take a look at the screenshot below:
Okay now we need to configure each individual request/response to extract data we want. We have to grab a JSESSIONID and a struts token. Lets highlight the first request/response and configure.
Example of configuring one of the items
Notice the struts.token.name and struts.token are dynamic and changing so we derive these from the response. The rest are preset values like email and birthdate (no, not my real birthdate). One thing that is important to notice is that I've decided to uncheck URL encode for the email portion. It is already URL encoded so no need. Otherwise it will cause problems.
Name the Macro
The next piece requires you to add the macro to a session rule. Again Options > Sessions > Session Handling > New. Highlight the macro you'd like to use.
Next, you'll need to add the pages to scope:
Now send the original, first request (I do this at the proxy history portion of Burp) over to intruder, select null payloads and set it for a number that is large enough to collect a big portion of passwords so we can review entropy. You'll see below that Intruder is configured to send the password reset sequence 800 times. Again, this will initiate the macro each time, so you are essentially resetting the password 800 times.
Next we need to retrieve the emails from gmail and review them for entropy. Here is a script I've written to retrieve emails from gmail, parse for the password values and write to a file called tokens.txt:
Line 12: File we will place all of our emails in (make sure you create an inbox folder)
Line 13: Initialize Pop class
Line 14: Enable SSL
Line 15: Replace with your username and password
Line 16: Call the check_for_emails method with the pop obj
Line 21-22: If we no emails, print that fact out to the screen
Line 24-25: We have emails, print that fact to the screen and call place_emails_into_file method with the pop object.
Line 31: Iterate thru pop array
Line 32: Open the file (line 12)
Line 33: Write the messages to the file
Line 36: Call the create_file_with_tokens method
Line 41: Create a new_file object which is a file called tokens.txt
Line 42: Create a read_file object which reads the inbox/emails.txt file from Line 12
Line 43: Begin reading each line from the read_file
Lines 44-46: If the line matches the "password: somepassword" write it to a file.
Line 53: Kick the whole thing off
Review the tokens.txt file
Factors that could slow us down:
1) If we can't enumerate e-mail addresses somehow. An example of enumeration would be if you type in a username/e-mail address and and the site tells you it doesn't exist. Now we know who DOES exist on the system.
2) This particular site requires a birthdate along with the email address. This is difficult but not impossible. If we know the e-mail address exists it is a matter of guessing the birthdate (automate w/ Intruder).
3) After we've reset other user's passwords, we need to guess the password (made MUCH easier by reviewing the entropy). If an account lock-out policy is enforced (after a small amount of incorrect password submissions) the account may be locked out leaving us without access. That is no fun.
Even if the reset or forgotten password function doesn't send us a clear-text password it may send us a reset link. It is important to review the randomness of that link.
Here is an example of loading the tokens file in sequencer:
We've bypassed struts token and multi-flow password resets which might have been intended to slow us down. We've collected all of our emails and parsed them for passwords/tokens/links. We've manually (in this case) reviewed the entropy but we can also do this with sequencer. Now we have a way to guess passwords more efficiently and in combination with other flaws leaves us just a short period of time from compromising accounts.