pfSense Plus MIM API toolkit b4acd7ca - عالي - عن بُعد - قراءة ملف - قواعد Snort {file} فك الترميز ثم الدمج
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-snort-file-join
الفئة: قراءة ملف الوصول: عن بُعد
pfSense Plus MIM API (Netgate/pfsense-api b4acd7ca) - Netgate
GET /services/snort/rules/{name}/{file} يأخذ معاملَي مسار، كلاهما type: string، بدون pattern. الوصف: فحص ملف في مجموعة القواعد. SnortRuleFileContents.filename هو "مسار الملف". الدالة المولَّدة get_snort_ruleset_file._get_kwargs تنفّذ quote(str(...), safe="")، لذا يصبح ../ هو ..%2F على الشبكة. الخادم الذي يفك ترميز URL ثم يدمج في دليل مجموعة القواعد لا يزال يخرج خارجها.
المتصل الذي يستطيع GET ذلك المسار، مع JWT للأسطول، يقرأ ملفات خارج مجموعة القواعد المسمّاة بصفته وكيل MIM على كل جهاز مُسجَّل. كما أن الدمج لم يُنفَّذ. المختبر هو أداة فك-ترميز-ثم-دمج للمسار العام.
هذا هو المتبقي 8 من 9. الخريطة: pfsense-api-nexus-mim. نفس المتبقي المثبَّت: fleet JWT. هذا ليس jaredhendrickson/pfsense-api.
| ID | لا يوجد CVE بعد |
| الفئة | قراءة ملف (Snort {file} فك-ترميز-ثم-دمج) |
| الوصول | عن بُعد (GET مُصادَق عليه؛ JWT الأسطول يعيد استخدام نفس المسار على كل device_id) |
| CWE | CWE-22 |
| CVSS | مرتفع: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N لـ JWT قد يستطيع GET ملف مجموعة قواعد Snort |
| المنتج | Netgate/pfsense-api (pfSense Plus Nexus MIM controller OpenAPI + العميل المولَّد) |
| المتأثر | main b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25، Add Snort-3 API definitions) |
| المصادقة | الأمثلة ترسل JWT الخاص بالـ controller بعد POST /login. OpenAPI لا يحتوي على securitySchemes. عدم المصادقة غير مُثبَت. |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1:19181 فقط. أداة فك-ترميز-ثم-دمج. الدمج الإضافي لم يُنفَّذ. |
يحتاج إلى متصل يستطيع GET /services/snort/rules/{name}/{file}. الأمثلة الرسمية تستخدم Authorization: Bearer بعد POST /login، ثم تعيد استخدام ذلك الرمز كـ base_url=.../api/device/pfsense/{device_id}/api لكل معرّف من GET /mim/devices. العمليات المولَّدة لا تزال تكتب AuthenticatedClient | Client. CSRF ليس في اللعبة على هذا GET.
| الطريقة | الحوض | الصلاحية | المختبر مقابل المستنتج |
|---|---|---|---|
GET من العميل المُولَّد مع {file}=../../oracle/WITNESS (على السلك ..%2F..%2Foracle%2FWITNESS) | فك ترميز unquote(file) ثم ضمّه إلى دليل مجموعة القواعد المُسمّاة والقراءة | استطلاع: HTTP 200، filename هو /oracle/WITNESS، والجسم PFSENSE-API-SNORT-FILE-JOIN-WITNESS. المقصود هو ملف .rules داخل مجموعة القواعد تلك. | مُثبت مختبرياً (gadget). كما أن الضم لم يُنفَّذ. |
نفس GET مع {file}=../../../etc/passwd | نفس الضم إذا ما قام المتحكم بإسناده إلى نظام ملفات الجهاز | استطلاع: قراءة ملفات المضيف بصلاحية وكيل MIM (عادةً ما يكون Plus WebGUI/PHP بصلاحية root). استخدم المختبر /oracle/WITNESS، وليس /etc/passwd حياً. | مستنتج (نفس الضم، مسار المضيف). |
نفس GET بعد fleet JWT (POST /login مرة واحدة، وإعادة التشغيل على /api/device/pfsense/{id}/api) | وكيل الجهاز لنفس {file} غير المقيّد | استطلاع: رمز متحكم واحد على شكل مكتب مساعدة يقرأ الملفات على كل صندوق مُسجَّل، وليس فقط الصندوق الذي كان تسجيل الدخول موجهاً إليه. | مستنتج (عقد G6 + هذا المسار). كما أن RBAC لم يُنفَّذ. |
نفس البقايا على {name} | GET|DELETE /services/snort/rules/{name} وكذلك {name} الشقيق للعنوان/الكبت هي أيضاً سلاسل غير مقيّدة | استطلاع / سلامة: إعادة تسمية أو حذف مجموعة قواعد يكون اسمها مساراً. | مستنتج من المواصفة. المختبر شغّل {file} فقط. |
| تحكم مقيّد بنفس مسار السلك | relative_to(ruleset_dir.resolve()) بعد فك الترميز | مغلق. HTTP 400، لا شاهد. | مُثبت مختبرياً |
{file}=local.rules الحميد | قراءة مجموعة القواعد المقصودة | مغلق. 200، sid:1، لا شاهد، سواء الساذج أو المتحكم. | مُثبت مختبرياً |
المغلق المجاور: ترميز النسبة المئوية من العميل لـ ../ (encoding=%2F). ضم التحكم بعد فك الترميز (control-confined=yes). ضم المتحكم الإضافي (plus-join-not-executed). القراءة المقصودة لـ local.rules داخل مجموعة القواعد foo. GET غير المُصادَق (غير مُثبت؛ الأمثلة ترسل Bearer). POST /services/snort/rules أرشيف / .so مزروع (مقصود لمسؤول IDS، وليس هذه البقايا). تشخيصات PHP/shell. كتابة ملف. shell المضيف. هذه البقايا ليست RCE.
ثبّتت Netgate/pfsense-api عند b4acd7ca21dbca739a530403a1f62a7440f7726f لأن HEAD في 2026-10-14 لم يكن له وسوم وآخر commit هو "Add Snort-3 API definitions". هكذا يوجد هذا المسار. لا يحتوي YAML على أي مفاتيح pattern: في أي مكان. {name} و {file} سلاسل غير مقيّدة. quote(..., safe="") هو مُرمِّز من جهة العميل، وليس فحص basedir من جهة الخادم.
/services/snort/rules/{name}/{file}:
parameters:
- in: path
name: name
required: true
schema:
type: string
- in: path
name: file
required: true
schema:
type: string
get:
description: Obtain the contents of the specified file in the ruleset. This is intended for inspecting scripts provided by it.
operationId: GetSnortRulesetFile
"url": "/services/snort/rules/{name}/{file}".format(
name=quote(str(name), safe=""),
file=quote(str(file), safe=""),
),
المسارات الخاطئة المسجلة بالفعل: التعامل مع ترميز العميل كإغلاق للاجتياز؛ تركيب pfSense Plus؛ تصنيف أرشيف Snort .so كبقايا هذه؛ الادعاء بـ GET غير المصادق. المسرح: صدفة عكسية. الأوراكل هو gadget 200 من /oracle/WITNESS بالإضافة إلى control 400.
python3 pfsense-api-snort-file-join-Abraxas-Labs.py
أو
cd lab
./run.sh
استهدف فقط http://127.0.0.1:19181. مشروع Compose pfsense-api-snort-file-join. أداة فك الترميز ثم الدمج للمسار العام. كما أن الدمج لا يُنفَّذ. يتم تفكيك Stack بعد التشغيل.
SUCCESS PFSENSE-API-SNORT-FILE-JOIN encoding=%2F decode-then-join=yes control-confined=yes plus-join-not-executed PFSENSE-API-SNORT-FILE-JOIN-WITNESS
ترميز العميل لـ ../../../etc/passwd هو ..%2F..%2F..%2Fetc%2Fpasswd. طلب GET ساذج لـ /services/snort/rules/foo/..%2F..%2Foracle%2FWITNESS أعاد 200، اسم الملف /oracle/WITNESS، والمحتوى PFSENSE-API-SNORT-FILE-JOIN-WITNESS. الطلب نفسه تحت تحكم مقيّد يُحلّ ضمن جذر مجموعة القواعد أعاد 400 وبدون شاهد. بقي local.rules الحميد داخل foo.
حلّل ضمن جذر مجموعة قواعد بعد فك الترميز. ارفض .. والمسارات المطلقة. Path.resolve() ثم relative_to(ruleset_dir.resolve())، أو ما يعادله، قبل القراءة. قيّد {file} (و {name}) بنمط آمن لمجموعة القواعد في OpenAPI حتى تتوقف المولّدات عن إرسال سلاسل بشكل مسار.