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-acme-key-dump — pfSense Plus MIM API toolkit b4acd7ca - High - Remote - Privilege leftover - GET /services/acme dumps keys | Kitploit
Tools/GitHubGitHub/abraxas/pfsense-api-acme-key-dump
Vulnerability AnalysisExploitationData ExfiltrationInformation GatheringWeb SecurityPenetration TestingSecret DetectionPapers & ResearchAPI Security
GitHubabraxas/pfsense-api-acme-key-dump

pfsense-api-acme-key-dump

pfSense Plus MIM API toolkit b4acd7ca - High - Remote - Privilege leftover - GET /services/acme dumps keys

View Repository
11 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-acme-key-dump

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  pfsense-api-acme-key-dump

pfsense-api-acme-key-dump

Class: Privilege leftover Reach: Remote

pfSense Plus Nexus Multi-instance Management OpenAPI toolkit b4acd7ca - Netgate

GET /services/acme (GetACMEConfig) returns ACMEConfig with no write-only or redacted flag. The 200 schema includes the ACME account private key, every issued leaf private key, any custom leaf key, and the DNS-provider tokens used for validation. Cert manager at least has a dedicated GET .../export-key. ACME has none. Config GET is the dump.

A controller session that can GET this path copies every hostname key the firewall enrolls, plus the DNS credentials that prove control of those names.

This tree is the public OpenAPI plus a generated Python client. It is not the CE REST package. The MIM controller is Plus-only and is not in the GitHub repo. I did not talk to a live controller. plus-not-executed=1.

IDno CVE yet
ClassPrivilege leftover (secret dump on config GET)
ReachRemote (authenticated MIM controller; not proven unauth)
CWECWE-200
CVSSHigh: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N if a services-read role receives the body. If only superuser can GET it, the dump is still the wrong shape for a config listing.
ProductNetgate/pfsense-api OpenAPI for pfSense Plus Nexus MIM
Affectedpublic main b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25, Add Snort-3 API definitions). No tags.
AuthController JWT from POST /login. Examples send Bearer. Spec has no securitySchemes.
LicenseGNU Affero GPL v3.0
Lab127.0.0.1:19151 only. No Plus image.

Series hub: pfSense Plus MIM leftovers. This is part 5. Chains with G9 stolen JWT (samples set verify_ssl=False) and G6 fleet token (one login Bearer is reused for every device_id). Sibling dump: G4 cert-manager export-key.

What an attacker can do

Requires a controller session that can GET /services/acme. Docs map that to mim_services_read / mim_services / mim_superuser. Spec does not attach those roles to the path. Plus RBAC was not executed.

A stolen JWT from G9 (MITM of the official samples) or a helpdesk fleet token from G6 is enough to point this GET at every enrolled box. That chain is inferred. This leftover is the GET body.

Recon

MethodSinkPrivilege
GET /services/acmeACMEConfig.account_keys[].account_key (format: byte)Lab-proven on the published spec and mock: 200 schema includes account_key; mock body round-trips PFSENSE-API-ACME-KEY-DUMP-WITNESS. Inferred on Plus: copy the Let's Encrypt (or other ACME) account private key. Talk to the ACME account off-box.
Same GETcerts[].issued_cert.privateKey (format: byte)Lab-proven spec+mock. Inferred on Plus: copy every issued leaf private key the firewall enrolled. Off-box TLS impersonation for those names.
Same GETcerts[].custom_key (format: byte)Lab-proven spec+mock. Inferred on Plus: copy a custom leaf key when key_type=custom.
Same GETcerts[].domain_list[].config.credentials (additionalProperties: string)Lab-proven spec+mock. Inferred on Plus: copy DNS validation secrets (Cloudflare tokens, AWS keys, RFC2136 secrets). Those prove control of the names.
Same GETaccount emails, custom server URLs, action_list.commandLab-proven the fields sit on the schema. Hook execution is a modify path, not this GET.

Integrity

None by the GET itself. Later use of stolen keys and DNS tokens is off-box (issue a rogue cert, talk to the ACME account, change DNS). Not exercised.

Availability

None. Config listing does not revoke or rewrite certificates.

Requires: authenticated MIM controller access that is allowed to GET the ACME tag. Not proven unauth. Generated _get_kwargs for this op adds no Authorization; examples still login and send Bearer.

Adjacent surface that stays closed

SurfaceWhy
Live pfSense Plus / Nexus controllerNot executed. plus-not-executed=1.
Unauthenticated Internet-to-8443Examples require POST /login. Missing OAS security is a spec gap, not a server 200-without-JWT proof.
POST /services/acme/cert/{name}/issue and .../renewIntended services-modify.
POST /services/acme/genprivatekeyIntended generate-and-return of a new account key. Not this leftover.
POST /diag/cmd/php / POST /diag/cmd/shellIntended admin console. Separate surface. Vendor treats Diagnostics: Command as intended (CVE-2025-69691 disputed).
GET /system/certificates/{refid}/export-keySeparate leftover: dedicated key export on the cert manager. ACME has no equivalent export op.
GET /services/acme/validmethodsMethod catalog. No keys.
CE jaredhendrickson/pfsense-apiDifferent product.

How I found it

I pinned public Netgate/pfsense-api b4acd7ca after the CE 2.9.0-DEVELOPMENT wave. This tree is OpenAPI 3.0.3 (pfapi_openapi.yml, 486 paths, 755 ops) plus a generated Python client for the Plus MIM controller on :8443. No tags. Latest public commit on the day I cloned was 2026-05-25, "Add Snort-3 API definitions."

Twelve hunts over login/JWT, diagnostics, MIM enrollment, client TLS, users/certs, packages, VPN/firewall, OpenAPI security, device IDOR, git/firmware/feeds, plus a loopback mock of every generated operation.

Skip list first: the five CE leftovers already mailed (QinQ parent-if, OpenVPN wizard CRLF, CARP VHID, limiter number, IPsec login banner). The third-party CE REST package. Diagnostics PHP/shell as unpublished RCE. Missing securitySchemes as proven unauth. POST /system/firmware has no URL. Ping/DNS/traceroute are the diagnostic.

I read GET /services/acme. The 200 $ref is ACMEConfig. Walking properties hits account_key, privateKey, custom_key, and credentials with format: byte on the key fields. The generated client get_acme_config.py calls GET /services/acme and parses ACMEConfig.

Wrong turns: treating POST /services/acme/genprivatekey as the leftover (that mint is the feature); treating missing securitySchemes as proven unauth (examples still send Bearer); claiming a non-superuser role actually receives the keys on Plus.

Theatre: a live Plus box. The oracle is the published schema plus a loopback mock 200.

Source

pfapi_openapi.yml GET /services/acme:

/services/acme:
  get:
    tags:
      - services
    summary: Get ACME Config
    operationId: GetACMEConfig
    responses:
      '200':
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ACMEConfig'
Download Tool