This PR adds a Nuclei template to detect CVE-2025-52970, a critical SQL injection vulnerability in Fortinet FortiWeb’s device status API that bypass authentification & leads to remote code execution.

What the Original Exploit Script Does

  1. SQL Injection Vector: Injects malicious SQL payloads via the Authorization: Bearer ’;{SQL_PAYLOAD} header
  2. Database Manipulation: Uses SQL queries to create tables and write payload chunks to the database
  3. File Writing: Abuses SELECT INTO OUTFILE to write two files:
    • A CGI webshell (/migadmin/cgi-bin/x.cgi)
    • A Python hook script (/var/log/lib/python3.10/pylab.py)
  4. RCE Achievement: Triggers the Python script to make the webshell executable, achieving remote command execution via the User-Agent header

What This Nuclei Template Does This template provides safe, non-destructive detection of the vulnerability by:

  1. Detection Methods Implemented:
    • Error-based SQLi: Bearer ’;SELECT/**/1;– - Looks for SQL error messages
    • Time-based SQLi: Bearer ’;WAITFOR//DELAY//‘0:0:10’;– - Confirms blind SQLi with 10-second delay
    • Version Disclosure: Bearer ’;SELECT/**/@@version;– - Attempts to identify database version
  2. Key Features:
    • Follows the exact same injection vector as the original exploit (Authorization header)
    • Uses the same API endpoint: /api/fabric/device/status
    • Maintains the same headers and request structure as the original script
    • Provides multiple verification methods to avoid false positives
    • Safe for scanning - no file writing or destructive operations

Quick start

  1. FortiWeb images not available anywhere publicly, you should signup here https://support.fortinet.com/
  2. Then from your account, from main menu, select the drop down menu: support, then click VM images, then choose FortiWeb then select platform in my case I choosed vbox, there are two other menus, latest versions & early versions, choose early versions (where you’ll find versions in question).
  3. Extract, import ovf file, & install the image.
  4. Configure network: settings, network
    1. Adapter 1: Bridged adapter
    2. Adapter 2: Internal network
    3. Adapter 3: Host-only adapter
  5. Run image, for login: admin, for password: hit enter (empty), then you’ll prompeted to change the password, change it, then automatically will logged in then, it’ll prompt you to enter credentials again
  6. Setup the UI: (ip 10.27.43.200 & default gateway 10.27.43.229 are not fixed depends on your setup) Block 1: Configure the Interface IP
config system interface
edit port1
set ip 10.27.43.200/24
set allowaccess https http ping
end

Block 2: Configure the Default Gateway

config router static
edit 1
set device port1
set gateway 10.27.43.229
next
end

No restart required, but prefer to restart, access the UI from your browser http://10.27.43.200/

Lab details

  • FortiWeb VM: 7.2.10 GA build0409
  • Access: https://10.27.43.200 (mgmt UI reachable)
  • Targeted endpoint: /api/v2.0/system/status.systemstatus
  • Result: consistently 401 Unauthorized
  • Example response (redacted):
root@DESKTOP-6QN3GRE:~/nuclei/nuclei-templates# nuclei -t http/cves/2025/CVE-2025-52970.yaml -u https://10.27.43.200/ -debug -irr
__ _
____ __ _______/ /__ (_)
/ __ \/ / / / ___/ / _ \/ /
/ / / / /_/ / /__/ / __/ /
/_/ /_/\__,_/\___/_/\___/_/ v3.4.10
projectdiscovery.io
[INF] Current nuclei version: v3.4.10 (latest)
[INF] Current nuclei-templates version: v10.2.8 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 114
[INF] Templates loaded for current scan: 1
[WRN] Loading 1 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] [fortigate-fortiweb-sqli-cve-2025-52970] Dumped HTTP request for https://10.27.43.200/api/fabric/device/status
GET /api/fabric/device/status HTTP/1.1
Host: 10.27.43.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Authorization: Bearer ';SELECT/**/1;--
Connection: close
[DBG] [fortigate-fortiweb-sqli-cve-2025-52970] Dumped HTTP response https://10.27.43.200/api/fabric/device/status
HTTP/1.1 401 Unauthorized
Connection: close
Content-Security-Policy: Script-Src 'self', frame-ancestors 'self'; Object-Src 'self'; base-uri 'self';
Date: Thu, 11 Sep 2025 11:15:26 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
Content-Length: 0
[INF] [fortigate-fortiweb-sqli-cve-2025-52970] Dumped HTTP request for https://10.27.43.200/api/fabric/device/status
GET /api/fabric/device/status HTTP/1.1
Host: 10.27.43.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Authorization: Bearer ';WAITFOR/**/DELAY/**/'0:0:10';--
Connection: close
[DBG] [fortigate-fortiweb-sqli-cve-2025-52970] Dumped HTTP response https://10.27.43.200/api/fabric/device/status
HTTP/1.1 401 Unauthorized
Connection: close
Content-Security-Policy: Script-Src 'self', frame-ancestors 'self'; Object-Src 'self'; base-uri 'self';
Date: Thu, 11 Sep 2025 11:15:26 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
Content-Length: 0
[fortigate-fortiweb-sqli-cve-2025-52970:dsl-1] [http] [critical] https://10.27.43.200/api/fabric/device/status
[INF] [fortigate-fortiweb-sqli-cve-2025-52970] Dumped HTTP request for https://10.27.43.200/api/fabric/device/status
GET /api/fabric/device/status HTTP/1.1
Host: 10.27.43.200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Authorization: Bearer ';SELECT/**/@@version;--
Connection: close
[DBG] [fortigate-fortiweb-sqli-cve-2025-52970] Dumped HTTP response https://10.27.43.200/api/fabric/device/status
HTTP/1.1 401 Unauthorized
Connection: close
Content-Security-Policy: Script-Src 'self', frame-ancestors 'self'; Object-Src 'self'; base-uri 'self';
Date: Thu, 11 Sep 2025 11:15:26 GMT
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
Content-Length: 0
[INF] Scan completed in 69.702849ms. 1 matches found.
root@DESKTOP-6QN3GRE:~/nuclei/nuclei-templates#

What I tried

  • Plain unauthenticated request like provided in first reference, not succeed
  • Variant with a minimal cookie (Era=9) as per public writeups, not succeed
  • Different ports / schemes (HTTP→HTTPS redirect; HTTPS on 443), not succeed
  • Tried to simulate what the second reference did, but in safe way, SQL execution 5-second delay, succeed
  • Tried to simulate what the second reference did, but in safe way, SQL execution 10-second delay, succeed

Template / PR Information

Template Validation

I’ve validated this template locally?

  • YES
  • NO

Additional Details

  • Lab image: FortiWeb VM 7.2.10 GA (build0409)
  • Endpoint probed: /api/v2.0/system/status.systemstatus
  • Observed result: 401 Unauthorized for both plain and cookie-variant probes
  • Example (redacted):
    HTTP/1.1 401 Unauthorized
    Set-Cookie: APSCOOKIE_FWEB_733867907=0&0; path=/; expires=Tue, 23-Sep-1975 ...
    Content-Length: 0
image image image

/claim #13123

Claim

Total prize pool $100
Total paid $0
Status Pending
Submitted September 10, 2025
Last updated September 10, 2025

Contributors

BE

Benraouane Soufiane

@benraouanesoufiane-proton-me

100%

Sponsors

PR

ProjectDiscovery

@projectdiscovery

$100