Password Reset Attacks
We’ll start looking at JSP files.
- Exploration of Structure
The application is inspected using white box techniques, revealing that is packaged as an EAR file, which contains several WAR files. The structure is analyzed using the tree command:
tree -L 3
This exploration is crucial to understand the application's composition and the locations of key files.
- Vulnerability Discovery in Password Reset Function
Focus is placed on the password reset functionality. The RequestPasswordReset.jsp file is specifically examined for vulnerabilities related to authentication and password resets.
- Analysis of RequestPasswordReset.jsp
This file is found to contain custom libraries and essential application logic for password resets. The importance of non-null variables principalName, providerName, and segmentName is noted, as they are crucial for the password reset logic to execute.
- Tracing the Password Reset Logic
The process involves obtaining a UserHome object and invoking its requestPasswordReset method. This investigation leads to the inspection of various files, including example-kernel.jar.
- Analysis of UserHomeImpl and UserHomes Classes
Here, the requestPasswordReset method is closely examined. In the UserHomes class, this method generates a reset token and forms URLs for password reset confirmation and cancellation.
- Token Generation Method Analysis
The getRandomBase62 method in Util.java, which is responsible for generating a random token, is analyzed. The method's reliance on the current time to create a random string highlights a potential vulnerability due to its predictability.
- Potential Exploit
The deterministic nature of token generation, based on System.currentTimeMillis(), poses a significant vulnerability. This could be exploited to bypass authentication, leading to unauthorized access and potentially remote code execution and web shell creation on the server.
- Analysis of Token Generation Method
It's observed that example-app uses java.util.Random, seeded with System.currentTimeMillis(), for generating password reset tokens. This method's lack of cryptographic security could lead to predictable outcomes.
- Demonstration of Predictability in Random Numbers
The predictability of Random is demonstrated using jshell, showing that two instances with the same seed generate identical number sequences:
jshell
import java.util.Random;
Random r1 = new Random(42);
Random r2 = new Random(42);
int x, y;
for(int i=0; i<10; i++) { x = r1.nextInt(); y = r2.nextInt(); if(x == y){
System.out.println("They match! " + x);}}
Contrarily, SecureRandom produces different outputs even with the same seed, underscoring its cryptographic strength. This is again shown using jshell.
jshell
import java.security.SecureRandom;
byte[] s = new byte[] { (byte) 0x2a}
SecureRandom r1 = new SecureRandom(s);
SecureRandom r2 = new SecureRandom(s);
if(r1.nextInt() == r2.nextInt()) { System.out.println("They match!"); } else { System.out.println("No match."); }
/exit
- Vulnerability in Token Generation
The use of Random with System.currentTimeMillis() is identified as a vulnerability, as it could allow the prediction of token values if the generation time is known.
- Exploitation Strategy
The text suggests that predicting the token generation time could enable an attacker to replicate the token using a similarly seeded Random instance, compromising account security.
- Account Determination
A default installation of example-app includes three accounts with known username/password pairs: guest/guest, admin-Standard/admin-Standard, and admin-Root/admin-Root.
The purpose is to analyze error messages from login and password reset pages to determine the validity of submitted usernames.
Identifying the Password Reset Page:
Navigate to the login page and submit invalid credentials to reveal the link to the password reset page.
The password reset page URL: http://example-app/passwdreset?login=false
Submit a password reset request for a default username (guest, admin-Standard, or admin-Root) through the identified password reset page.
Observe the response differences between valid and invalid account submissions.
A successful password reset request for a valid account and an error message for an invalid account can help identify active accounts.
Based on the response differences, the existence of the "guest" account is confirmed.
- Timing the Reset Request
In order to generate the correct password reset token, we need to guess the seed value, which is the exact millisecond that the token was generated.
The value returned by System.currentTimeMillis() is already in UTC.
We can get the range of potential seed values using the date command before and after we submit the reset request with curl:
date +%s%3N && curl -s -i -X 'POST' --data-binary 'id=guest' 'http://example-app/RequestPasswordReset.jsp' && date +%s%3N
This range varies based on network latency and server processing time. However, the seed is determined early in the password reset process, so it is likely to be closer to the start time rather than the end time.
The server response included a Date header with a value we can convert to the Unix epoch time using a site such as EpochConverter to compare with the locally calculated timestamps.
The values should be close enough to proceed with this attack.
- Generate Token List
Now that we have the range of potential random seeds, we need to create our own token generator:
touch
example-appToken.java
We will set the start and stop values which are based on the timestamps from when we ran curl:
Compile it:
javac
example-appToken.java
Run it:
java
example-appToken > tokens.txt
- Resets Automation
Examining UserHomes.class, we find the format of a reset link:
We have our tokens, but we will also need to provide values for providerName, segmentName, and id. We can use the inspector to locate this values. Then we will search those patterns at files like WizardInvoker.jsp to notice what values we should send.
Examining PasswordResetConfirm.jsp, we notice that, in addition to the token, providerName, segmentName, and id, we need to provide a new password value in the password1 and password2 fields
To automate everything with python:
./example-appReset.py -u guest -p password
Last updated