Phân tích lỗ hổng SolarWinds Orion Deserialization to RCE (CVE-2021–31474)
Sau 2 tháng trời diff patch Exchange thì tới patch của tháng 5 này thì mình đã bị ngộ độc và quá chán nản,
Mang tiếng patch của Pwn2own mà chỉ có 5–6 điểm khác biệt,
Theo suy đoán của mình thì có lẽ 1 phần nào đó trong những chain attack tại Pwn2own đã bị vá ngay vào bản vá của tháng 4,
Và theo thông tin từ ZDI thì có vẻ như bản patch tháng 5 này của M$ còn thiếu bug nữa:
.
.
Dạo quanh ZDI để tìm cảm hứng thì bất chợt gặp 1 advisory khá là hay ho:
SolarWinds Network Performance Monitor FromJson Deserialization of Untrusted Data Remote Code Execution Vulnerability (CVE-2021–31474) (https://www.zerodayinitiative.com/advisories/ZDI-21-602/)
Sẵn tiện vừa nghiên cứu xong bug deserialize của Exchange, và cũng đang muốn đổi gió nên mình kéo về nghiên cứu bug này!
SolarWinds có nhiều bộ bundle software, phục vụ cho từng mục đích khác nhau, ví dụ như: System management/Network management/DB management…
Cách setup bộ SolarWinds cũng khá đơn giản, hoàn toàn có thể tải bản trial tại trang chủ: https://www.solarwinds.com/network-performance-monitor
Việc setup chỉ đơn giản là click click và chờ, trong bundle đã bao gồm tất cả các software cần thiết rồi,
.
.
Sau khi search thêm 1 vòng thì có được thêm thông tin từ trang chủ của SolarWinds (https://documentation.solarwinds.com/en/success_center/orionplatform/content/release_notes/orion_platform_2020-2-5_release_notes.htm):
Kết hợp thông tin của ZDI và SolarWinds thì có thể biết được một số thông tin như sau:
- Lỗ hổng này không chỉ tồn tại trên SolarWinds Network Performance Monitor (NPM), mà chính xác hơn nó tồn tại trên SolarWinds Orion Platform (các product khác của SolarWinds như SAM, SEM, VIM, IPM, …đều được xây dựng trên nền tảng này).
- Lỗ hổng này tồn tại trên các phiên bản Orion < 2020.2.5
- Lỗ hổng này yêu cầu đăng nhập với một user bất kỳ, chứ không phải pre-auth theo như thông tin của ZDI
Quay trở lại với thông tin từ document của SolarWinds, lỗ hổng này tồn tại trong chức năng “test alert actions” của web interface:
Chức năng Test Action này cũng đã từng được ZDI đề cập tới trong 1 bài viết về những lỗ hổng có liên quan tới vụ SUNBURST https://www.zerodayinitiative.com/blog/2021/1/20/three-bugs-in-orions-belt-chaining-multiple-bugs-for-unauthenticated-rce-in-the-solarwinds-orion-platform
Nội dung của 1 request Test Action có dạng như sau:
Sau khi bới móc một hồi thì mình tìm ra class handler entrypoint này, đó là SolarWinds.Orion.Web.Actions.ActionControllerImplementation.
Mình không rõ nguyên nhân do đâu mà phần code xử lý chính của nó đã bị obfuscate hoàn toàn, làm cho quá trình đọc code gặp khá nhiều khó khăn:
Việc phân tích lỗ hổng này cũng dựa vào tâm link là chính chứ mình cũng ko có đọc đc kỹ lắm =)).
Sau khi xem xét 1 vòng thì mình nhận ra lỗ hổng Deserialization này xảy ra ngay tại bước parse dữ liệu JSON của chức năng TestAction,
Tại method TestAction, dữ liệu được parse bằng method ActionControllerImplementation.DeserializeObjectWithTypes()
Nội dung của method này có dạng như sau:
DeserializeObjectWithTypes() tiếp tục gọi SerializationHelper.FromJson() với TypeNameHandling = TypeNameHandling.Objects
SerializationHelper.FromJson() lại tiếp tục gọi SerializationHelper.FromJsonInternal() -> JsonConvert.DeserializeObject()
Dựa vào những kiến thức mình được biết về JSON Deserialize trong .Net (https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf) thì tại entrypoint này hoàn toàn có thể khai thác Insecure Deserialization -> RCE.
Tuy nhiên việc deserialize -> RCE không đơn giản như vậy,
Trong thực tế, trường hợp JsonConvert.DeserializeObject<object>() hay JsonConvert.DeserializeObject<GadgetType>() rất rất hiếm khi hoặc có thể nói là không bao giờ xảy ra.
Do vậy mà để khai thác được Deserialize trên .Net, cần phải lươn lẹo và lắt léo hơn một tí
Xem kỹ hơn ở dữ liệu đầu vào được deserialize, đây là một instance của kiểu SolarWinds.Orion.Core.Models.Actions.Contexts.ActionContextBase
Đáng chú ý, trong class này có field với kiểu SolarWinds.Orion.Core.Models.MacroParsing.MacroContext, được gán attribute [DataMember]
(Trong .Net deser, các field có attribute [DataMember] mới có thể được serialize/deserialize với DataContractSerializer).
Trong class MacroContext lại chứa field DataMember với kiểu List<ContextBase>:
Nội dung của class ContextBase như sau:
Trong đó, các khai báo “[KnownType(typeof(ClassX))]” ngay phía trên class biểu thị cho các ClassX này là một trong những class triển khai của class này.
Ví dụ với trường hợp trên:
- Khai báo “[KnownType(typeof(SwisEntityContext))]” trước class ContextBase
Có nghĩa class SwisEntityContext là một class triển khai của class ContextBase.
Hay có thể hiểu theo nghĩa ngắn gọn hơn, khai báo như vậy có nghĩa class ContextBase này chỉ chấp nhận deserialize những class được khai báo là:
- ReportingContext
- AlertingContext
- GenericContext
- SwisEntityContext
Tiếp tục xem xét một trong những class triển khai của ContextBase, là class SolarWinds.Orion.Core.Models.MacroParsing.SwisEntityContext. SwisEntityContext có chứa một field với kiểu SolarWinds.InformationService.Contract2.PropertyBag:
PropertyBag lại kế thừa Dictionary<string, object>
=> Có thể lợi dụng điều này để gài gadget vào bên trong object.
Thay vì deserialize trực tiếp gadget RCE, mình gói gadget vào một Object hợp lệ ròi deserialize nó!
.
.
Mọi thứ gần như đã hoàn hảo, tuy nhiên có một chi tiết nhỏ mà mình đã bỏ sót chưa nhắc đến,
Trước khi gọi FromJsonInternal(), method SerializationHelper.ApplyDeserializationBlacklist() được gọi
Theo như nội dung của method SerializationHelper.ApplyDeserializationBlacklist(), nó set giá trị blacklist, hạn chế những class có thể được deserialize, bao gồm các class sau:
Tuy nhiên nếu chỉ dựa vào blacklist này là chưa đủ, đối chiếu theo ysoserial.net, còn có rất nhiều gadget khác chưa bị nằm trong blacklist này, và vẫn có thể bị lợi dụng để RCE như: RolePrincipal, SessionSecurityToken, SessionViewStateHistoryItem …
Ở đây mình sử dụng gadget SessionSecurityToken cho PoC,
Kết hợp tất cả các dữ liệu trên được PoC như sau:
PoC payload: https://gist.github.com/testanull/dcb536b409a28d74430a441d53b14456
PoC video:
Như vậy mình cũng đã nói qua về lỗ hổng CVE-2021–31474 của SolarWinds Orion, cũng như một phần nhỏ của Json.Net Deserialize,
Kiến thức về .Net deserialize còn khá mới nên có thể sẽ có nhiều sai sót, mong bạn đọc có thể bổ sung và góp ý!
Cảm ơn các bạn đã theo dõi!
__Jang__