The SSL-VPN pot of gold
I found a private FortiGate SSL-VPN kit in the wild and released it. 179 working clients, two public CVEs, 53 SKUs. The tree is on GitHub.
- Name
- The SSL-VPN pot of gold
- Series
- The SSL-VPN pot of gold
- Phase
- 0 · Introduction
- Type
- N-day analysis
- CVE
- CVE-2024-21762
- CVE Risk
- critical
- Disclosure Status
- public
- Vendor
- Fortinet
- Affected
- FortiGate SSL-VPN, 53 SKUs, FortiOS 6.0 through 7.4.1 labels
- Published
- 31 Aug 2026
- Updated
- 01 Sept 2026
- Tags
- n-day, fortinet, ssl-vpn, cve-2024-21762, cve-2023-27997, series
179 working pre-auth RCE clients
I found them in the wild: a directory of exp_*.py files, 179 unique hashes, names like exp_60E-v6.4.7.py and exp_1000D-v7.4.0.py. Each file is a working client for a specific FortiGate SKU and FortiOS build. Two public CVEs. 53 hardware types. 55 firmware labels, 6.0.1 through 7.4.1. A hit is unauthenticated code execution in sslvpnd - on the firewall itself.
I am @abraxas_null. The bugs were already public. The catalog is public now too.
The tree is on GitHub: Fortigate-SSL-VPN-Exploit-Kit (catalog). Recovered as found. I did not write these files. Appendix maps every path. Research and detection only - the CVEs were patched before I published the folder.
What I actually picked up
Not 179 vulnerabilities. Two primitives, restamped across hardware and firmware until the folder looked like a parts catalog. FortiOS labels in the filenames run 6.0.1 through 7.4.1.
Family A is CVE-2024-21762. Family B is CVE-2023-27997. Twenty SKUs carry both families as different files for different builds.
Heaviest retargeting: FortiGate-60E (19 files), 100E (14), 60F (10), 100F (9). That is branch-office hardware. The author invested where the internet actually lives.
Trains in the filenames: 6.0 (20), 6.2 (27), 6.4 (55), 7.0 (42), 7.2 (29), 7.4 (5). Family A walks almost the full advertised window for 21762, including 7.4.0 and 7.4.1 (Fortinet's cut is 7.4.3). Family B stays inside the 27997 window. No Family B file is labeled past 7.2.5 / 7.0.12 / 6.4.13. That alignment is how you know the mapping is not a guess I made because the numbers were pretty.
The bugs were public. The catalog was not.
CVE-2024-21762 is an out-of-bounds write in sslvpnd while parsing HTTP Transfer-Encoding: chunked. Fortinet: FG-IR-24-015. Public colour: Assetnote, Two Bytes is Plenty. Both CVEs sit in CISA's KEV catalog.
CVE-2023-27997 is a heap overflow on enc= at /remote/hostcheck_validate. Fortinet: FG-IR-23-097. Lexfo named the line XORtigate. Bishop Fox showed the internet was still full of it after the advisory.
Anyone with a lab and a weekend can learn those bugs. What I found is a per-image gadget table with a private naming scheme, an ARM connect-back stager, and a /s.js loader that is consistent across the tree. Offsets are compile-time constants. No comments. No "SKU" flag. You pick the file that matches the box, then you aim.
Wrong file, wrong gadgets, sslvpnd falls over. These clients are written to mutate memory and retry. A "we only scanned" story does not survive contact with this folder.
What a hit means
Unauthenticated code execution in the SSL-VPN process on the firewall itself. That process terminates TLS for remote users, holds a seat on a box that owns routing policy, VPN sessions, and often LDAP/RADIUS bindings. FortiOS does not offer a useful /bin/sh. Public research and this kit both go through an internal command helper and/or /bin/node (Node.js, which FortiOS actually ships).
The first drop stopped at "get a callback." The second-stage bodies are in the GitHub tree: s.js and the shellcode/ blobs. They steal FortiOS config from /data/config/*.gz. That is credential and topology compromise, not a crashed daemon. Historically, people who get this foothold also write webshells, add admins, and leave files that survive a lazy upgrade. Persistence is still not a distinct third stage in these scripts. It remains the correct residual-risk model if a live hit cannot be ruled out.
Treat a confirmed hit as compromise of the network edge, not as a crashed daemon with a funny core file.
What this kit does not prove
- A new 0-day. The primitives are n-days with public write-ups.
- FortiProxy, FortiManager, FortiAnalyzer, FortiWeb. No samples.
- SKUs not in the 53 (many 70F/90G/120G units, VM-only images, 6K/7K chassis). No compiled offsets.
- Builds past Fortinet's published cuts. Confirm against the live advisory, not my folder.
- Persistence. That would live in the missing follow-on.
A public PoC against a VM is a different artifact. This pack is for whoever answered recon.
How to read the series
- Phase 0 · Introduction (you are here). The find, the counts, the stakes.
- Phase 1 · Two public doors. Family A and Family B as behavior, not a recipe.
- Phase 2 · The matrix. 53 SKUs, trains, CPU. Searchable, paginated.
- Phase 3 · Hunting the kit. Distinctive URIs, patch cuts, what to do if the portal was reachable.
- Phase 4 · Appendix. The public tree: what each file is, where it lives.
If you run FortiGates: inventory model, exact FortiOS, SSL-VPN on or off, whether the portal was reachable from untrusted networks. Then read Phase 2. Do not inventory only 60-series branch boxes because those filenames were the loudest.