Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
pfsense-api-example-ssl-verify — pfSense Plus MIM API toolkit b4acd7ca - Medium - Remote - Privilege leftover - official samples verify_ssl=False | Kitploit
Tools/GitHubGitHub/abraxas/pfsense-api-example-ssl-verify
Defensive ToolsVulnerability AnalysisExploitationInformation GatheringWeb SecurityNetwork SecurityPenetration TestingAuthenticationPapers & Research

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
GitHubabraxas/pfsense-api-example-ssl-verify

pfsense-api-example-ssl-verify

pfSense Plus MIM API toolkit b4acd7ca - Medium - Remote - Privilege leftover - official samples verify_ssl=False

View Repository
11 day agoNot yet reviewed
Share

Abraxas Labs - pfsense-api-example-ssl-verify

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  pfsense-api-example-ssl-verify

pfsense-api-example-ssl-verify

Class: Privilege leftover Reach: Remote

pfSense Plus MIM API (Netgate/pfsense-api b4acd7ca) - Netgate

Generated Client / AuthenticatedClient default verify_ssl=True and pass that into httpx. Docs already call verify_ssl=False a security risk and show a PEM bundle path first. Every official Python sample and helper_funcs.py still construct them with verify_ssl=False. example.js sets NODE_TLS_REJECT_UNAUTHORIZED=0, so the whole Node process skips verify. Login JSON puts username and password in base64. That is the OpenAPI contract, not encryption. TLS is the confidentiality layer.

An on-path peer of :8443 presents any certificate. The sample still POSTs /login. The stand-in captures the base64 admin login and mints a JWT. That token is the chain: G4 export-key, G5 ACME dump, G6 fleet JWT, G7 ACB userkey, intended php/shell, and the JSON that G1 interpolates into SSH.

This is Part 9 of pfSense Plus MIM API toolkit. Read this leftover first even though it is Medium. The stolen JWT is how the rest become reachable from a workstation that copied example.py.

IDno CVE yet
ClassPrivilege leftover (sample TLS verify off)
ReachRemote (on-path to :8443)
CWECWE-295
CVSSMedium: 6.8 CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N
ProductNetgate/pfsense-api (Plus Nexus MIM client; not the CE REST package)
Affectedpublic main b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25) official samples and helper_funcs.py
Authoperator copies and runs a sample against the controller; no extra controller role
LicenseGNU Affero GPL v3.0
Lab127.0.0.1:19191 only. Does not compose pfSense Plus.

AC:H is on-path between the operator workstation and the MIM controller. UI:R is copy/run the sample.

What an attacker can do

Victim: operator workstation running an official sample or helper_funcs.py against https://controller:8443. Attacker: on-path to that HTTPS (LAN, rogue DHCP, compromised VPN hop, ARP). Not unauth Internet-to-firewall.

MethodSinkPrivilege
Present any cert while the sample POSTs /login or /api/login with verify_ssl=False / NODE_TLS_REJECT_UNAUTHORIZED=0httpx verify=False (Python samples) or Node TLS reject-unauthorized 0Confidentiality (lab-proven): read the login JSON. Lab: stand-in captured base64 admin / lab-controller-secret (captured_b64_admin=yes). Decode is one base64 -d.
Same MITM, 200 LoginResponsesample accepts any certConfidentiality (lab-proven): steal the access JWT. Lab: INJECT got a token that carried PFSENSE-API-EXAMPLE-SSL-VERIFY-WITNESS.
Same MITM, Set-Cookie on loginsample copies client.get_httpx_client().cookies into AuthenticatedClientConfidentiality (lab-proven cookie, inferred replay): 24-hour refresh JWT. Replay POST /login/refresh with that cookie plus the base64 username until the refresh TTL. Lab captured Set-Cookie: refresh=.... Refresh against a live controller was not executed.
Replay stolen Bearer to the real controller (if the attacker can also route to it)Plus MIM /api and /api/device/pfsense/{device_id}/apiIntegrity (inferred): admin-equivalent as the logged-in user on this API. Schema includes POST /diag/cmd/php, POST /diag/cmd/shell, POST /diag/editfile, POST /diag/backup/restore, POST /diag/control halt/reboot. Not exercised here. This lab is a controller stand-in, not Plus.
Replay stolen Bearer as leftover 6 (fleet token)one POST /login JWT reused for every device_idIntegrity (inferred): talk to firewall B after authenticating as a user meant for firewall A. LoginResponse has no per-device allow-list. Pack: pfsense-api-fleet-jwt. Plus RBAC not executed.
Replay stolen Bearer as leftover 4GET /system/certauth/{refid}/export-key, GET /system/certificates/{refid}/export-key, GET /system/certificates/{refid}/export-p12Confidentiality (inferred): pull CA and leaf private keys, PKCS12 documented without password protection, then impersonate VPN / WebGUI TLS / IPsec. Pack: pfsense-api-export-key-get.
Replay stolen Bearer as leftover 5GET /services/acmeConfidentiality (inferred): steal Let's Encrypt account key and issued cert keys for every hostname the firewall enrolls. Pack: pfsense-api-acme-key-dump.
Replay stolen Bearer, or leak userkey from a sample that GETs ACB, as leftover 7GET /services/acb?userkey= and GET /services/acb/bkp?userkey=Confidentiality (inferred): list and fetch Auto Config Backup blobs (full config). Pack: pfsense-api-acb-userkey.
Shape ControllerSummary JSON toward leftover 1MITM of verify_ssl=False HTTPS supplies the JSON that example-add-devices.py quote-escapes then .formats into SSHIntegrity (inferred): $() / backticks / newlines in a controller field run as SSHUSER on every address in pfsense_addresses. Pack: pfsense-api-enroll-json-ssh.
Inject responses toward the clientskip-verify accepts any certIntegrity (lab-proven token, inferred fleet): mint a JWT the sample will keep. Lab: INJECT token with the witness. Fake device lists / upgrade progress / login success against a live sample are the same gate.
POST /diag/control, firmware POST, restore of a broken backup (after stolen Bearer)intended admin surface once TLS is goneAvailability (inferred): halt / reboot / broken image. Same Bearer. Not labbed.

Lab-proven vs inferred: CONTROL handshake fail, INJECT token, and captured base64 admin login are lab-proven on 127.0.0.1:19191. Replay of that Bearer onto a live Plus controller, diag php/shell, G4-G7, G1 JSON shaping, and refresh-cookie mint of new access JWTs are inferred from the OpenAPI and the samples.

Requires: operator copies and runs example.py, example-add-devices.py, example-upgrade-devices.py, example-set-alias.py / example-upgrade-devices-async.py via helper_funcs.py, or example.js. Attacker on the path to :8443.

Adjacent surface that stays closed

Download Tool