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-enroll-autoadd — pfSense Plus MIM API toolkit b4acd7ca - High - Remote - Privilege leftover - Paramiko AutoAddPolicy enroll | Kitploit
Tools/GitHubGitHub/abraxas/pfsense-api-enroll-autoadd
Vulnerability AnalysisExploitationNetwork SecurityCryptographyPenetration TestingAuthenticationPapers & ResearchRed TeamingLabs & Practice
GitHubabraxas/pfsense-api-enroll-autoadd

pfsense-api-enroll-autoadd

pfSense Plus MIM API toolkit b4acd7ca - High - Remote - Privilege leftover - Paramiko AutoAddPolicy enroll

View Repository
1 day agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Abraxas Labs - pfsense-api-enroll-autoadd

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  pfsense-api-enroll-autoadd

pfsense-api-enroll-autoadd

Class: Privilege leftover Reach: Remote

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

example-add-devices.py is the documented way to register the Nexus controller to each pfSense device. It never load_system_host_keys(). It sets paramiko.AutoAddPolicy() then connect then exec_command(device_script). The comment says to drop AutoAdd when devices are already in known_hosts. Shipping default is AutoAdd.

First-contact SSH to a new box accepts whatever host key answers. Password or key auth is presented to that peer. stdout is json.loads'd and POST /mim/devices'd to the real controller.

This is not the third-party CE REST package. This is the official OpenAPI plus generated Python client for pfSense Plus Nexus Multi-instance Management. Server is Plus-only. The lab is a Paramiko SSH gadget. I did not talk to a live Plus controller.

IDno CVE yet
ClassPrivilege leftover (Paramiko AutoAddPolicy on enrollment SSH)
ReachRemote (on-path to device SSH on first contact)
CWECWE-322
CVSSHigh: 8.1 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
ProductNetgate/pfsense-api (Plus Nexus MIM client toolkit)
Affectedmain b4acd7ca21dbca739a530403a1f62a7440f7726f example-add-devices.py
AuthOperator runs the official sample; attacker is on-path to device SSH
LicenseGNU Affero GPL v3.0
Lab127.0.0.1:19111 only. No Plus image.

AC:H is first-contact / on-path. A workstation that already has the real device keys in known_hosts and has the AutoAdd line removed is not this leftover.

Same pin leftovers: JSON interpolation of ControllerSummary into the enrollment shell (G1) and samples force verify_ssl=False (G9). Series hub: pfsense-api-nexus-mim.

What an attacker can do

Sit on-path to a first-contact SSH address in pfsense_addresses while the operator runs the sample. AutoAdd is still on.

MethodSinkPrivilege
Sit on-path to a first-contact SSH address in pfsense_addressesset_missing_host_key_policy(paramiko.AutoAddPolicy()) then connect (example-add-devices.py:151-160)Integrity (lab-proven): unknown host key is accepted. Lab: AutoAddPolicy connected (autoadd=yes). RejectPolicy failed (reject-control=yes).
Same session, answer exec_command(device_script)stdout parsed as DeviceIdentity (example-add-devices.py:161-187)Integrity (lab-proven): exec returned identity JSON containing PFSENSE-API-ENROLL-AUTOADD-WITNESS (identity-json=yes).
Same MITM, read the exec payloaddevice_script is leftover G1's curl -d of ControllerSummaryRecon (inferred from source): controller identity key, Netgard vpn_pubkey / vpn_netkey / listen addrs. Not dumped by this lab.
Same MITM, password or key authSSHUSER / SSHPASS or agent/keys (example-add-devices.py:156-160)Recon (inferred): credentials or keys presented to the fake host. Lab used password auth only as the sample SSHPASS path.
Same stdout JSON, add_controlled_device.syncPOST /mim/devices on the real controllerIntegrity (inferred): registers attacker Noise/VPN keys and address. Plus handshake not executed in this lab.
MITM is the SSH serverwhatever exec the client sent, as SSHUSERIntegrity / availability (inferred): run, drop, or skip the enrollment script. Unix-socket calls on the real device happen only if the MITM forwards them.

Lab-proven vs inferred: AutoAdd connect, RejectPolicy fail, and identity JSON with the witness are lab. Controller-key dump, credential theft, POST /mim/devices of a fake device, and running the real unix-socket curls are inferred from the same sample path.

Requires: operator runs the official sample against an SSH address whose host key is not already pinned, with AutoAdd left on. Network path to that SSH. AC:H is first-contact / on-path.

Adjacent surface that stays closed

SurfaceWhy
RejectPolicy on the same unknown hostLab: reject-control=yes. Paramiko refuses the key.
Workstation with real device keys in known_hosts and AutoAdd line removedThe comment's intended mode. Sample never loads those keys unless you add the call.
HTTPS controller loginverify_ssl=False is a sibling sample leftover (G9), not this sink.
Unix-socket MIM on the real firewallOnly if the MITM forwards exec. This lab never talks to /var/run/pfnet-controller.sock.
Generated Client default verify_ssl=TrueLibrary default is not the leftover. Samples force False.
Plus RBAC / live :8443This lab is a Paramiko gadget. I did not talk to a Plus controller.
Unauthenticated Internet-to-8443Login still issues a JWT. Not this finding.
Diagnostics PHP/shellIntended admin power for a fleet JWT. Not this finding.

How I found it

I pinned github.com/Netgate/pfsense-api main b4acd7ca21dbca739a530403a1f62a7440f7726f after the CE WebGUI leftovers. This tree is OpenAPI plus generated Python for Plus Nexus MIM. I read the enrollment loop in example-add-devices.py. Host-key policy is AutoAdd. Secrets sit on the same exec channel. The sample never calls load_system_host_keys().

Wrong turns already recorded: treating AutoAdd as intended-lab-only (the comment is opt-out, not opt-in); assuming known_hosts is loaded; folding this into the ControllerSummary shell interpolation leftover; live-labbing Plus; claiming this is unauth HTTPS to :8443.

Theatre: a reverse shell. The oracle is RejectPolicy fail plus AutoAdd connect plus identity JSON with the witness.

Lab

python3 pfsense-api-enroll-autoadd-Abraxas-Labs.py

or

cd lab
./run.sh

Loopback SSH 127.0.0.1:19111. Compose project pfsense-api-enroll-autoadd. CONTROL: RejectPolicy fails unknown host. INJECT: official-sample AutoAddPolicy, connect, exec_command of the enrollment script; stdout is identity JSON with the witness. No live Plus controller. Witness PFSENSE-API-ENROLL-AUTOADD-WITNESS. Stack tears down after the run.

SUCCESS PFSENSE-API-ENROLL-AUTOADD autoadd=yes reject-control=yes identity-json=yes PFSENSE-API-ENROLL-AUTOADD-WITNESS

The fix

Download Tool