Trustwave Rapid Response: CrowdStrike Falcon Outage Update. Learn More

Trustwave Rapid Response: CrowdStrike Falcon Outage Update. Learn More

Managed Detection & Response

Eliminate active threats with 24/7 threat detection, investigation, and response.

Co-Managed SOC (SIEM)

Maximize your SIEM investment, stop alert fatigue, and enhance your team with hybrid security operations support.

Advisory & Diagnostics

Advance your cybersecurity program and get expert guidance where you need it most.

Penetration Testing

Test your physical locations and IT infrastructure to shore up weaknesses before exploitation.

Database Security

Prevent unauthorized access and exceed compliance requirements.

Email Security

Stop email threats others miss and secure your organization against the #1 ransomware attack vector.

Digital Forensics & Incident Response

Prepare for the inevitable with 24/7 global breach response in-region and available on-site.

Firewall & Technology Management

Mitigate risk of a cyberattack with 24/7 incident and health monitoring and the latest threat intelligence.

Offensive Security
Solutions to maximize your security ROI
Microsoft Exchange Server Attacks
Stay protected against emerging threats
Rapidly Secure New Environments
Security for rapid response situations
Securing the Cloud
Safely navigate and stay protected
Securing the IoT Landscape
Test, monitor and secure network objects
Why Trustwave
About Us
Awards and Accolades
Trustwave SpiderLabs Team
Trustwave Fusion Security Operations Platform
Trustwave Security Colony
Technology Alliance Partners
Key alliances who align and support our ecosystem of security offerings
Trustwave PartnerOne Program
Join forces with Trustwave to protect against the most advance cybersecurity threats
SpiderLabs Blog

Exploiting Password Recovery Functionalities

Password recovery functionalities can result in vulnerabilities in the same application they are intended to protect. Vulnerabilities such as username enumeration (showing different error messages when the user exists or not in the database), sensitive information disclosure (sending the password in clear-text by e-mail to user) and recover password message hijack (involving an attacker receiving a copy of the recover password message) are some common vulnerabilities that may be found in a password recovery functionality. Various developers don't take into consideration the real implications of unsecure password recovery, and this blog post will show how things get complicated when developers don't apply basic security practices to this kind of functionality.

An example of a good password recovery functionality generates a token and sends this token by e-mail to the user as a one-time password recovery method (commonly as a link). This token should have the following characteristics:

  • have at least 64 chars in length
  • be unique
  • be random
  • be one-time use only
  • and have a short life (expire in 24h or less)


When a user clicks the link, the application must check if the token is valid. If so, the application must invalidate the token so it can't be reused and allow the user to change his password. Furthermore, if a user attempts to recover their password a second time before completing the recovery process the first time, the application must invalidate the old password request and generate a new one. It's desirable (but not mandatory) to have a second validation for the authenticity of the password recovery attempt before changing the user's password. An example would be asking the user to answer a secret question or confirm data sent to the user's cellphone via SMS.

Now, let's examine a real-world example of a badly designed password recovery system, enumerate all associated vulnerabilities and try to generate exploits for some of these vulnerabilities:

1:  <?php  2:    3:  /* generates a new random password */  4:  function generatePassword() {  5:       $chars = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9");       6:       for ($i = 0; $i < 10; $i++){            7:            $password .= $chars[rand(0,35)];  8:       }  9:       return $password;  10:  }  11:    12:  /* send the new password to the user e-mail and update the database */  13:  if ($_REQUEST['mail']) {       14:       $con = new Connection();  15:       $con->sql = "  SELECT,   16:            ,   17:            ,   18:                      usr_user.password  19:                  FROM  usr_user   20:                  WHERE = '" . $_REQUEST['mail'] . "'  21:                  ORDER  BY id DESC ";  22:       $res = $con->executeQuery();  23:       if (is_array($res)){  24:            $usr = $res[0];  25:            $password = generatePassword();  26:            $con->sql = "UPDATE usr_user SET password = MD5(trim('".$password."')) WHERE email = '" . $_REQUEST['mail'] . "' ";  27:            $con->executeQuery();  28:              29:            /* headers */  30:            $headers = "MIME-Version: 1.0\r\n";  31:            $headers .= "Content-type: text/html; charset=iso-8859-1\r\n";  32:    33:            /* aditional headers */  34:            $headers .= "To: " . $usr->name . " <" . $_REQUEST['mail'] . ">\r\n";  35:            $headers .= "From: Administrator <>\r\n";  36:              37:            /* message body */  38:            $html = '<html><body>';  39:            $html .= '<p><strong>' . $usr->name . '</strong></p>';  40:            $html .= '<p>This is the new password: <strong>' . $password . '</strong></p>';  41:            $html .= '<p>To access the administrative panel:</p>';  42:            $html .= '<br/><p>Administrator</p>';  43:            $html .= '</body></html>';  44:         45:            /* Send e-mail to user with his new password  46:            if (mail($_REQUEST['mail'], "Your new administrative password", $html, $headers)){  47:                 $message = "Your new password was sent to: " . $_REQUEST['mail'];  48:                 $success = true;  49:            }  50:       } else {            51:            $message = "The provided e-mail is invalid";  52:            $success = false;  53:       }  54:         55:  }  56:    57:  ?>  58:    

Username Enumeration:&nbsp;

The first vulnerability we can identify, is a user enumeration vulnerability, because when the user supplies a registered e-mail, the application will reply with "Your new password has been sent to:". Otherwise, the application will reply with "The provided e-mail is invalid".

2.&nbsp;&nbsp;&nbsp; Denial of Service:

The second vulnerability we can identify is a denial of service abusing the functionality of password recovery because this application changes the actual password of user to a new/randomly generated password (as you can see in the lines 25-28). That way an attacker could create, for example, an automatic script to abuse the functionality by resetting user passwords every 15 seconds and blocking real users from loggin into the application. And, in combination with a username enumeration vulnerability, the severity of this vulnerability increases.

&nbsp;3.&nbsp;&nbsp;&nbsp; Sensitive Information Disclosure:

The third vulnerability we can identify is sensitive information disclosure because the application sends an e-mail to the user with the newly generated password in clear-text and doesn't force the user to change his password the next time he logs in. So, if an attacker compromises the e-mail of a user and the user forgets to change their password the next time they log in, the application can be accessed by the attacker using the original e-mail message.

&nbsp;4.&nbsp;&nbsp;&nbsp; SQL Injection:

The fourth vulnerability we can identify is&nbsp; SQL Injection. User input is not properly validated and directly concatenated to the query string in the lines 15 and 26. An attacker can exploit this vulnerability in a number of ways.

&nbsp;The first is through denial-of-service by abusing the update query and changing all users password by supplying the following input:&nbsp;

  • Input:' or 1=1%23
  • First SQL becomes (Line 15): SELECT,,, usr_user.password FROM usr_user WHERE = '' or 1=1#' ORDER&nbsp;&nbsp; BY id DESC
  • Second SQL becomes (Line 26): UPDATE usr_user SET password = MD5(trim('xxxxxxxxxx')) WHERE email like '' or 1=1#'

Another attack vector would be using this SQL Injection to recover other types of information from the database via blind queries. Unfortunately we can't use this vector to recover the md5 hash of passwords from the database because all blind requests where the response is "True" will actually change the password of all users when the application executes the update query.

&nbsp;5.&nbsp;&nbsp;&nbsp; Reflected Cross-Site Scripting:

The Fifth vulnerability we can identify, is reflected cross-site scripting. In the reply message provided by the application in line 47, the user input $_REQUEST['mail'] is directly concatenated to the response message (without any treatment) when the application finds a valid username in the database. To exploit this vulnerability we will need to combine this vulnerability with the SQL Injection by supplying the following input to the application:

  • User Input:' or 1=1%23<script>alert(1)</script>
  • First SQL becomes (Line 15): SELECT,,, usr_user.password FROM usr_user WHERE = '' or 1=1#<script>alert(1)</script>' ORDER&nbsp;&nbsp; BY id DESC
  • Second SQL becomes (Line 26): UPDATE usr_user SET password = MD5(trim('xxxxxxxxxx')) WHERE email like '' or 1=1#<script>alert(1)</script>'
  • Response Message (Line 47): Your new password was sent to: ' or 1=1#<script>alert(1)</script>

So, as we can see, the application will accept the input as a valid SQL statement changing all user passwords and will return the message described above to the user browser to trigger the malicious script.

6.&nbsp;&nbsp;&nbsp; Password Recovery Message Hijack:

And last but not least, the sixth vulnerability we can identify is password recovery message hijacking. As we can see in the line 34, the application concatenates the user input $_REQUEST['mail'] directly to the MIME message header instead of using the registered user e-mail. To exploit this vulnerability we will need to combine this vulnerability with the SQL injection vulnerability by supplying the following input to the application:

  • User' or 1=1%23
  • First SQL becomes (Line 15): SELECT,,, usr_user.password FROM usr_user WHERE = '[null byte char]' or 1=1#' ORDER&nbsp;&nbsp; BY id DESC&nbsp;
  • Second SQL becomes (Line 26): UPDATE usr_user SET password = MD5(trim('xxxxxxxxxx')) WHERE email like '[null byte char]' or 1=1#'
  • MIME Header becomes (Line 34): To: John Smith <[null byte char]' or 1=1#>

Just like the exploitation of reflected cross-site scripting, the queries 1 and 2 will be valid and will reset the password of all users because doesn't exists a registered e-mail with '[null byte char]' and will send a e-mail to John Smith <[null byte char]' or 1=1#>. But, as we all know, the e-mail MIME header will be treated as a string and the [null byte] will be considered part of that character string. So, as is also known, the null byte represents the end of a character string and because of this behavior will kill the rest of that string. In this case the MIME header becomes John Smith <>&nbsp;allowing the attacker to hijack the password recovery message and discover the password generated for all users (because all users passwords are changed in the update query).

With this real world example, we can see that a simple password recovery system can possibly add six or more vulnerabilities to an application.

Hope you enjoy! :-)

Keep Hacking!

Latest SpiderLabs Blogs

Trustwave Rapid Response: CrowdStrike Falcon Outage Update

Trustwave is proactively assessing and monitoring our clients who may have been impacted by CrowdStrike’s recently rolled-out update for its Windows users. The critical issue identified with...

Read More

Using AWS Secrets Manager and Lambda Function to Store, Rotate and Secure Keys

When working with Amazon Web Services (AWS), we often find that various AWS services need to store and manage secrets. AWS Secrets Manager is the go-to solution for this. It's a centralized service...

Read More

Facebook Malvertising Epidemic – Unraveling a Persistent Threat: SYS01

The Trustwave SpiderLabs Threat Intelligence team's ongoing study into how threat actors use Facebook for malicious activity has uncovered a new version of the SYS01 stealer. This stealer is designed...

Read More