abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-acme-key-dump
クラス: 権限の残存 到達範囲: リモート
pfSense Plus Nexus マルチインスタンス管理 OpenAPI ツールキット b4acd7ca - Netgate
GET /services/acme (GetACMEConfig) は、write-only や redacted フラグなしで ACMEConfig を返します。200 スキーマには、ACME アカウントの秘密鍵、発行されたすべてのリーフ秘密鍵、任意のカスタムリーフ鍵、および検証に使用される DNS プロバイダトークンが含まれます。少なくとも cert manager には専用の GET .../export-key があります。ACME にはありません。Config GET がそのダンプです。
このパスを GET できるコントローラセッションは、ファイアウォールが登録するすべてのホスト名鍵と、それらの名前の制御を証明する DNS 認証情報をコピーします。
このツリーは公開 OpenAPI と生成された Python クライアントです。CE REST パッケージではありません。MIM コントローラは Plus 専用であり、GitHub リポジトリにはありません。私は実際のコントローラとは通信していません。plus-not-executed=1。
| ID | CVE はまだありません |
| クラス | 権限の残存 (config GET でのシークレットダンプ) |
| 到達範囲 | リモート (認証済み MIM コントローラ。未認証は証明されていません) |
| CWE | CWE-200 |
| CVSS | High: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (services-read ロールがボディを受け取る場合)。superuser のみが GET できる場合でも、このダンプは config リストとして誤った形です。 |
| 製品 | Netgate/pfsense-api pfSense Plus Nexus MIM 用 OpenAPI |
| 影響を受ける | 公開 main b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25, Add Snort-3 API definitions)。タグはありません。 |
| 認証 | POST /login からのコントローラ JWT。例では Bearer を送信します。仕様には securitySchemes がありません。 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1:19151 のみ。Plus イメージはありません。 |
シリーズハブ: pfSense Plus MIM leftovers。これはパート 5 です。G9 盗まれた JWT (サンプルは verify_ssl=False を設定) および G6 フリートトークン (1 回のログイン Bearer がすべての device_id で再利用される) と連鎖します。兄弟ダンプ: G4 cert-manager export-key。
GET /services/acme を実行できるコントローラセッションが必要です。ドキュメントではこれを mim_services_read / mim_services / mim_superuser にマッピングしています。仕様はこれらのロールをパスに付加していません。Plus RBAC は実行されていません。
G9 から盗まれた JWT (公式サンプルの MITM) または G6 からのヘルプデスクフリートトークンがあれば、この GET をすべての登録済みボックスに向けるのに十分です。その連鎖は推測です。この残存は GET ボディです。
| 手法 | シンク | 権限 |
|---|---|---|
GET /services/acme | ACMEConfig.account_keys[].account_key (format: byte) | 公開仕様とモックでラボ実証済み: 200 スキーマに account_key が含まれる。モックのボディは PFSENSE-API-ACME-KEY-DUMP-WITNESS をラウンドトリップする。Plus では推測: Let's Encrypt(または他の ACME)アカウントの秘密鍵をコピーする。オフボックスで ACME アカウントと通信する。 |
| 同じ GET | certs[].issued_cert.privateKey (format: byte) | 仕様+モックでラボ実証済み。 Plus では推測: ファイアウォールが登録したすべての発行済みリーフ秘密鍵をコピーする。それらの名前に対するオフボックス TLS なりすまし。 |
| 同じ GET | certs[].custom_key (format: byte) | 仕様+モックでラボ実証済み。 Plus では推測: key_type=custom の場合にカスタムリーフ鍵をコピーする。 |
| 同じ GET | certs[].domain_list[].config.credentials (additionalProperties: string) | 仕様+モックでラボ実証済み。 Plus では推測: DNS 検証シークレット(Cloudflare トークン、AWS キー、RFC2136 シークレット)をコピーする。これらは名前の制御を証明する。 |
| 同じ GET | アカウントのメールアドレス、カスタムサーバー URL、action_list.command | これらのフィールドがスキーマ上に存在することはラボ実証済み。 フック実行は変更パスであり、この GET ではない。 |
GET 自体によるものはなし。盗まれた鍵と DNS トークンの後続利用はオフボックス(不正な証明書の発行、ACME アカウントとの通信、DNS の変更)。検証されていない。
なし。設定の一覧表示は証明書を失効させたり書き換えたりしない。
必要条件: ACME タグを GET することが許可された、認証済み MIM コントローラーアクセス。未認証では証明されていない。この操作のために生成された _get_kwargs は Authorization を追加しない。例は依然としてログインして Bearer を送信する。
| サーフェス | 理由 |
|---|---|
| 稼働中の pfSense Plus / Nexus コントローラー | 実行されていない。plus-not-executed=1。 |
| 未認証のインターネットから 8443 へ | 例は POST /login を必要とする。OAS の security 欠落は仕様のギャップであり、JWT なしでサーバーが 200 を返す証明ではない。 |
POST /services/acme/cert/{name}/issue と .../renew | 意図された services-modify。 |
POST /services/acme/genprivatekey | 意図された新しいアカウント鍵の生成と返却。この残存物ではない。 |
POST /diag/cmd/php / POST /diag/cmd/shell | 意図された管理コンソール。別のサーフェス。ベンダーは Diagnostics: Command を意図されたものとして扱う(CVE-2025-69691 は係争中)。 |
GET /system/certificates/{refid}/export-key | 別の残存物: 証明書マネージャー上の専用鍵エクスポート。ACME には同等のエクスポート操作がない。 |
GET /services/acme/validmethods | メソッドカタログ。鍵はなし。 |
CE jaredhendrickson/pfsense-api | 別製品。 |
CE 2.9.0-DEVELOPMENT の波の後、公開されている Netgate/pfsense-api b4acd7ca をピン留めした。このツリーは OpenAPI 3.0.3(pfapi_openapi.yml、486 パス、755 操作)に加え、:8443 上の Plus MIM コントローラー用に生成された Python クライアントである。タグはなし。クローンした日の最新公開コミットは 2026-05-25 の「Add Snort-3 API definitions.」だった。
login/JWT、diagnostics、MIM enrollment、client TLS、users/certs、packages、VPN/firewall、OpenAPI security、device IDOR、git/firmware/feeds にわたる 12 回の探索、加えて生成されたすべての操作のループバックモック。
まずスキップリスト: すでにメール済みの 5 つの CE 残存物(QinQ parent-if、OpenVPN wizard CRLF、CARP VHID、limiter number、IPsec login banner)。サードパーティの CE REST パッケージ。未公開 RCE としての Diagnostics PHP/shell。未認証が証明されたものとしての securitySchemes 欠落。POST /system/firmware には URL がない。Ping/DNS/traceroute は診断機能である。
GET /services/acme を読んだ。200 の $ref は ACMEConfig である。プロパティをたどると、鍵フィールドに format: byte を持つ account_key、privateKey、custom_key、credentials に行き当たる。生成されたクライアント get_acme_config.py は GET /services/acme を呼び出し、ACMEConfig をパースする。
誤った道: POST /services/acme/genprivatekey を残存物として扱うこと(その mint は機能である)。securitySchemes の欠落を未認証が証明されたものとして扱うこと(例は依然として Bearer を送信する)。非スーパーユーザーロールが Plus で実際に鍵を受け取ると主張すること。
茶番: 稼働中の Plus ボックス。オラクルは公開されたスキーマとループバックモックの 200 である。
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'
ACMEAccountKey.account_key:
account_key:
type: string
description: |
if key_type is not "custom", system will overwrite this field with generated private key
format: byte
ACMEIssuedCert.privateKey:
privateKey:
type: string
format: byte
ACMECertificate.custom_key は format: byte です。ACMEValidationMethodConfig.credentials は additionalProperties: string です。
生成されたクライアント py/pfapi/api/services/get_acme_config.py の _get_kwargs:
_kwargs: dict[str, Any] = {
"method": "get",
"url": "/services/acme",
}
python3 pfsense-api-acme-key-dump-Abraxas-Labs.py
または:
cd lab
./run.sh
Loopback のみ: http://127.0.0.1:19151。Compose プロジェクト pfsense-api-acme-key-dump。Witness PFSENSE-API-ACME-KEY-DUMP-WITNESS。Pin b4acd7ca21dbca739a530403a1f62a7440f7726f を実行時にクローンまたはコピー。Docker 必須。Plus イメージ不要。
PoC は、pin された OpenAPI を走査してこれら4つのシークレットフィールドを探し、生成された _get_kwargs(GET /services/acme、Authorization なし)をロードし、モック 200 を介して witness をラウンドトリップします。
IOC plus-not-executed=1 mock=http://127.0.0.1:19151 pin=b4acd7ca21dbca739a530403a1f62a7440f7726f
IOC schema-get-acme account_key=1 privateKey=1 custom_key=1 credentials=1
IOC mock-get http=200 account_key=1 privateKey=1 custom_key=1 credentials=1
SUCCESS pfsense-api-acme-key-dump schema=account_key,privateKey,custom_key,credentials mock-http=200 plus-not-executed=1 PFSENSE-API-ACME-KEY-DUMP-WITNESS