pfSense Plus MIM API ツールキット b4acd7ca - 高 - リモート - 権限の残留 - example-add-devices.py JSON から SSH へ
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-enroll-json-ssh
クラス: 特権の残留 到達範囲: リモート
pfSense Plus MIM API ツールキット (b4acd7ca) - Netgate
example-add-devices.py は、SSH 経由で各 pfSense Plus デバイスに Nexus コントローラーを登録するための、文書化された方法です。これは GET /mim/controller/identity を json.dumps し、" のみを置換した後、そのブロブを二重引用符で囲まれた curl -d POSIX スクリプトに二度 .format します。Paramiko の exec_command は、pfsense_addresses 内のすべてのアドレスで、SSHUSER(サンプルのデフォルトは admin)としてスクリプトを実行します。
json.dumps と replace('"', '\\"') の組み合わせにより、引用符は閉じられたままになります。$()、バッククォート、${...} は JSON のメタ文字ではありません。これらは、まだ開いている二重引用符付きの -d 文字列内で生き続けます。OpenSSH の exec はシェルです。これが残留です。
これはサードパーティの CE REST パッケージではありません。これは pfSense Plus Nexus マルチインスタンス管理 コントローラー用の公式 OpenAPI クライアントとサンプルです。私が Plus を構成したのではありません。ラボは、固定された補間とモックの /var/run/pfnet-controller.sock です。
| ID | CVE はまだなし |
| クラス | 特権の残留(コントローラー JSON から登録 SSH へ) |
| 到達範囲 | リモート(サンプルが verify_ssl=False を設定している間の CONTROLLER_URL へのオンパス、または ControllerSummary 文字列フィールドの書き込み者) |
| CWE | CWE-78 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
| 製品 | Netgate/pfsense-api(Plus MIM ツールキット) |
| 影響を受けるもの | 公開 main b4acd7ca21dbca739a530403a1f62a7440f7726f の example-add-devices.py |
| 認証 | オペレーターが文書化されたサンプルを実行します。攻撃者はオンパスであるか、サマリー文字列を書き込むことができます。コントローラーへのログインは依然として最初に行われます。 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1:19101 のみ。Plus イメージはありません。 |
Nexus MIM 残留シリーズのパート 1。関連項目: enroll-autoadd、unix-sock-noauth、example-ssl-verify(G9 はオンパスのピアがこの JSON をどのように形成するかです)、fleet-jwt、export-key-get。
残留とは、まだ開いている二重引用符付きの -d 文字列内でのコマンド置換です。json.dumps と引用符パスにより、文字列は閉じられたままになります。$()、バッククォート、${...} は生き残り、OpenSSH がスクリプトを exec するときに SSHUSER として実行されます。
| 手法 | シンク | 権限 | ラボ実証または推測 |
|---|---|---|---|
ControllerSummary の文字列フィールドに $()(またはバッククォート / ${...})を入れ、オペレーターに example-add-devices.py を実行させる | controller_info.replace('"', '\\"') → device_script.format(...) → sshclient.exec_command(device_script)(example-add-devices.py 約104-161行) | pfsense_addresses 内の各アドレス上で SSHUSER としてのシェル(サンプルのデフォルトは admin、pfSense の admin SSH は通常 root 相当) | 補間についてラボ実証済み: INJECT vpn_listenaddr=$(printf %s PFSENSE-API-ENROLL-JSON-SSH-WITNESS >/oracle/witness) がクォートのみのエスケープを生き延び(dollar-paren-survived=yes)、witness を書き込んだ(inject-oracle=yes)。Paramiko/SSH 自体はこの compose には含まれない。 |
サンプルが verify_ssl=False を使用している間の GET /api/mim/controller/identity に対する TLS MITM | 同じ ControllerSummary のパース、続いて同じスクリプト | 同じシェル。ControllerSummary の全フィールドは str または Unset であるため、型としてパースできる MITM JSON ボディで十分。 | サンプルからの推測(example-add-devices.py のログイン Client と AuthenticatedClient はどちらも verify_ssl=False を設定)。ラボは summary オブジェクトを直接 POST する。関連: example-ssl-verify。 |
コントローラー上の name または vpn_listenaddr に置換文字を書き込み、次の enroll を待つ | 同じシンク | オペレーターが次にサンプルを実行したときの同じシェル | 推測。これらのフィールドの事前書き込みが必要(すでにコントローラー管理者、または unix-sock-noauth の関連レポート)。 |
同じシェル、ControllerSummary.additional_properties 経由の追加キー | 同じダンプに追加の MITM キーが含まれる(to_dict は from_dict の後に残りをコピーする) | 追加フィールドが -d に、そしてシェルに流れ込む | to_dict からの推測。ラボは vpn_listenaddr 経由でのみ注入する。 |
| 手法 | シンク | 権限 | ラボ実証または推測 |
|---|---|---|---|
| 登録ワークステーションの stdout を読む | print("CONTROLLER_SUMMARY:", controller_info) | コントローラー識別情報 key、Netgard vpn_pubkey / vpn_netkey / リッスンアドレス | サンプルの print からの推測。ラボはライブのコントローラーブロブを出力しない。 |
| SSH exec チャネルをスニッフィングまたは MITM する | exec_command(device_script) のペイロードは curl の -d JSON | 各デバイスへのワイヤー上の同じコントローラー識別情報 | 推測。そのチャネル上の AutoAddPolicy は関連レポート。 |
| ガジェット上の CONTROL ケース | POST /case name=control | 正直な vpn_listenaddr が unix ソケットにそのまま到達する | ラボ実証済み。 192.0.2.10:51820 がそのまま POST され、オラクルなし(control-clean=yes)。 |
| 手法 | シンク | 権限 | ラボ実証または推測 |
|---|---|---|---|
SSHUSER としての注入コマンド | 同じ exec_command | pfnet-controller の停止、登録のワイプ、再起動、またはその他の方法でデバイスを MIM から切り離す | シェルの副作用としての推測。ラボは witness ファイルを書き込むのみ。 |
必要条件: 公式サンプルパス(オペレーター enroll)。そのサンプルが実行されていれば、オンパスピアに対して UI:N。コントローラーへのログインは依然として最初に発生する。
pfSense ボックス上の admin としてのシェルは「JWT が php できる」ということではない。それは登録ワークステーションが sh -c を通じてファイアウォールにコントローラーブロブを渡すということである。そこから、整形された JSON がデバイスによって JWT なしで /var/run/pfnet-controller.sock に POST される(unix-sock-noauth)。AutoAddPolicy は、このスクリプトを受け取る SSH ピアがピン留めされていないことを意味する(enroll-autoadd)。G9 verify_ssl=False は、オンパスピアがそもそも JSON を書き込む方法である。
| Surface | Why |
|---|---|
生成されたライブラリのデフォルト verify_ssl=True | この残存物はサンプルであり、pfapi.Client のデフォルトではない。 |
curl -d "..." のクォートブレイクアウト | JSON と " の置換により文字列は閉じたまま保たれる(quote-only-escape=yes)。 |
from_dict / json.dumps を通過した ControllerSummary からの生改行スクリプト分割 | U+000A が \n になる。 |
| 登録ワークステーション上の RCE | フォーマットはローカル。シェルはリモートの exec。 |
| Nexus コントローラへの未認証 HTTPS | login.sync が依然として最初に実行される。 |
add_controlled_device.sync | パース済み JSON を HTTPS に POST する。DeviceIdentity.controller_add を exec することはない。 |
| CONTROL listenaddr | $() / バッククォートなし。オラクルを書き込まない。 |
unix POST ボディ内の INJECT $() | 展開は curl の前に sh で行われる(inject-meta-reached-unix は fail)。 |
Paramiko AutoAddPolicy() | 兄弟パック。これと混在させないこと。 |
| JWT なしのデバイス unix ソケット MIM | 兄弟パック。 |
| pfSense Plus コントローラ/デーモン | このリポジトリには含まれない。構成されていない。 |
意図された POST /diag/cmd/php と /diag/cmd/shell | すでに管理者である Nexus コンソール。この残存物ではない。 |
| サードパーティ CE REST パッケージ | 異なる GitHub ツリー。 |
私は github.com/Netgate/pfsense-api b4acd7ca21dbca739a530403a1f62a7440f7726f(2026-05-25、Add Snort-3 API definitions)をピン留めした。タグはない。ツリーは OpenAPI 3.0.3(pfapi_openapi.yml、486 パス、755 オペレーション)に加え、生成された Python とサンプルで構成されている。HTTPS コントローラと pfnet-controller は Plus 専用であり、リポジトリには含まれていない。
12 回の探索。Login/JWT、diagnostics、MIM enrollment、client TLS、users/certs、packages、VPN/firewall、OpenAPI security、device IDOR、git/firmware/feeds、さらにすべての生成オペレーションのループバックモック。755/755 の _get_kwargs が 127.0.0.1:55980 に送信された。AuthenticatedClient は常に Bearer を送信した。Client は何も送信しなかった。php/shell を含めて。パスパラメータは ../ をパーセントエンコードする。ライブラリのデフォルトは verify_ssl=True。公式のすべての例は False を設定している。