天融信关于VLC Media Player 2.2.8 Use After Free漏洞分析
一、背景介绍
VLC 是一款自由、开源的跨平台多媒体播放器及框架。它支持众多音频与视频解码器及文件格式和各类流式协议,也能作为流式服务器在 IPv4 或 IPv6 的高速网络连接下使用。
本文主要分析 VLC Media Player 2.2.8 版本的 MKV 格式视音频分离器 (demuxer) 中存在的一个 UAF 漏洞,实验环境为最新版本的 Win10 64 位, 主要从漏洞细节和漏洞的利用两大部分对漏洞进行分析。
在漏洞细节部分,主要分为以下三个方面:
1. 如何找到漏洞触发点?
2. 如何确定 UAF 对象?
3. 分析漏洞成因。
在漏洞利用部分,下面这些问题都将得到说明:
1. 如何通过精确的 Heap Spary 布置 shellcode?
2. 如何重新利用 UAF 对象?
3. 如何 bypass DEP&ASLR?
MKV
MKV 格式属于 Matroska 开源多媒体容器标准中的一种。它是建立在 EBML 语言的基础上,这是一种类似于 XML 格式的可扩展二进制元语言,使用可变长度的整数存储,以节省空间。EBML 元素都有自己的级别,每一个高一级的元素由若干次一级的元素组成。整个 MKV 文件 从整体看可分为 2 大部分:EBMLHeader 和 Segment。前者包含了文件的版本、文档类型等相关信息;后者则保存了媒体文件的视频和音频的实际数据,又可以再分为 SeekHead、Chapters、Attachments、Cluster 等若干子元素。
1.1 漏洞描述
天融信阿尔法实验室经过深入分析关于该漏洞主要是源于 VLC 播放器用于处理 MKV 格式的视音频分离器模块——libmkv_plugin.dll 中, 该模块的一个 matroska_segment_c 对象在释放后被重引用。可以通过构造大量和该对象大小相同的数据块,最终使这块内存重新被分配,后面再引用该对象时,便可控制程序指针,最后通过精确的 Heap Spray 布置 shellcode、ROP 绕过 DEP,造成任意代码执行。
1.2 受影响的系统版本
VLC media player
1.3 漏洞编号
CVE-2018-11529
二、漏洞细节
由于 VLC Media Player 的 release 版本没有调试信息,所以我们可以在官网下载源码自行编译带有调试信息的程序。另外要注意的的一点是,官方推荐使用 MinGW 在 Linux 环境下交叉编译 VLCMedia Player。而 MinGW 使用的是 DWARF 格式调试信息而非 PDB 格式,所以在 Windbg 中调试时,依然无法看到符号信息,但这依然方便了我们使用 IDA 静态分析。
2.1 漏洞触发点
首先我们需要找到漏洞触发的位置,使用 Windbg 自带工具 gflag 开启页堆:
将 vlc.exe 附加到 Windbg 上,打开 poc.mkv,在此处触发了异常,可以确定漏洞存在于 libmkv_plugin.dll 模块,再结合 IDA 和源码分析,得知具体位置是在函数 int Control(demux_t_0 *p_demux, int i_query, va_list args) 中
现在关闭页堆,重新打开 vlc.exe,并在刚才异常的位置下断点,再次打开 poc.mkv,可以看到 [ebp+28h] 处的值为 0×22000020,
查看 ebp 处的内容,发现正是 PoC 中构造的 UAF_object 的内容,因此可以基本确定,ebp 中保存的是指向 UAF 对象指针。
当然这里并不是漏洞的触发点,UAF 漏洞的触发一般都是要再次引用该对象的某个方法。所以我们可以在 [ebp+28h] 处设置一个内存访问断点(也就是上图中 0×22000020 的位置):ba r4 0f4069e8
继续运行程序,断在了函数 matroska_segment_c::UnSelect() 中:
继续往后执行几步便会触发漏洞,弹出计算器。
这里的 call 指令调用了一个位于 vlc.exe 模块中的地址,结合 PoC 来看也是 ROP 链第一个 gadget 的地址。
到这里已经可以初步推测漏洞成因,在对象 matroska_segment_c 被释放后,接着申请与其大小相同内存去「占坑」,待后面重引用该对象中某个函数或成员时,就可以控制程序执行流程。
2.2 释放重引用的位置
接下来的问题是——matroska_segment_c 对象是在哪里被释放,又是在哪里被重新分配呢?尝试使用!heap -p -a 查看分配此内存时的栈回溯信息,发现无法却显示。
这是因为这里编译器采用了一种称为 FPO(Frame Pointer Omission)的优化方式,它压缩或者省略了在栈上为函数创建栈帧指针的过程。这样可以加速函数调用,但是在这种情况下,调试器可能不能基于 EBP 展开栈帧(除非它有启用了 FPO 模块相匹配的符号文件,而前面提到过,我们没有办法生成用于 Windbg 调试的 PDB 文件)。
一、背景介绍
VLC 是一款自由、开源的跨平台多媒体播放器及框架。它支持众多音频与视频解码器及文件格式和各类流式协议,也能作为流式服务器在 IPv4 或 IPv6 的高速网络连接下使用。
本文主要分析 VLC Media Player 2.2.8 版本的 MKV 格式视音频分离器 (demuxer) 中存在的一个 UAF 漏洞,实验环境为最新版本的 Win10 64 位, 主要从漏洞细节和漏洞的利用两大部分对漏洞进行分析。
在漏洞细节部分,主要分为以下三个方面:
1. 如何找到漏洞触发点?
2. 如何确定 UAF 对象?
3. 分析漏洞成因。
在漏洞利用部分,下面这些问题都将得到说明:
1. 如何通过精确的 Heap Spary 布置 shellcode?
2. 如何重新利用 UAF 对象?
3. 如何 bypass DEP&ASLR?
MKV
MKV 格式属于 Matroska 开源多媒体容器标准中的一种。它是建立在 EBML 语言的基础上,这是一种类似于 XML 格式的可扩展二进制元语言,使用可变长度的整数存储,以节省空间。EBML 元素都有自己的级别,每一个高一级的元素由若干次一级的元素组成。整个 MKV 文件 从整体看可分为 2 大部分:EBMLHeader 和 Segment。前者包含了文件的版本、文档类型等相关信息;后者则保存了媒体文件的视频和音频的实际数据,又可以再分为 SeekHead、Chapters、Attachments、Cluster 等若干子元素。 本文来自无奈人生安全网
1.1 漏洞描述
天融信阿尔法实验室经过深入分析关于该漏洞主要是源于 VLC 播放器用于处理 MKV 格式的视音频分离器模块——libmkv_plugin.dll 中, 该模块的一个 matroska_segment_c 对象在释放后被重引用。可以通过构造大量和该对象大小相同的数据块,最终使这块内存重新被分配,后面再引用该对象时,便可控制程序指针,最后通过精确的 Heap Spray 布置 shellcode、ROP 绕过 DEP,造成任意代码执行。
1.2 受影响的系统版本
VLC media player
1.3 漏洞编号
CVE-2018-11529
二、漏洞细节
由于 VLC Media Player 的 release 版本没有调试信息,所以我们可以在官网下载源码自行编译带有调试信息的程序。另外要注意的的一点是,官方推荐使用 MinGW 在 Linux 环境下交叉编译 VLCMedia Player。而 MinGW 使用的是 DWARF 格式调试信息而非 PDB 格式,所以在 Windbg 中调试时,依然无法看到符号信息,但这依然方便了我们使用 IDA 静态分析。
2.1 漏洞触发点
首先我们需要找到漏洞触发的位置,使用 Windbg 自带工具 gflag 开启页堆:
将 vlc.exe 附加到 Windbg 上,打开 poc.mkv,在此处触发了异常,可以确定漏洞存在于 libmkv_plugin.dll 模块,再结合 IDA 和源码分析,得知具体位置是在函数 int Control(demux_t_0 *p_demux, int i_query, va_list args) 中
现在关闭页堆,重新打开 vlc.exe,并在刚才异常的位置下断点,再次打开 poc.mkv,可以看到 [ebp+28h] 处的值为 0×22000020,
查看 ebp 处的内容,发现正是 PoC 中构造的 UAF_object 的内容,因此可以基本确定,ebp 中保存的是指向 UAF 对象指针。
当然这里并不是漏洞的触发点,UAF 漏洞的触发一般都是要再次引用该对象的某个方法。所以我们可以在 [ebp+28h] 处设置一个内存访问断点(也就是上图中 0×22000020 的位置):ba r4 0f4069e8
copyright 无奈人生
继续运行程序,断在了函数 matroska_segment_c::UnSelect() 中:
继续往后执行几步便会触发漏洞,弹出计算器。
这里的 call 指令调用了一个位于 vlc.exe 模块中的地址,结合 PoC 来看也是 ROP 链第一个 gadget 的地址。
到这里已经可以初步推测漏洞成因,在对象 matroska_segment_c 被释放后,接着申请与其大小相同内存去「占坑」,待后面重引用该对象中某个函数或成员时,就可以控制程序执行流程。
copyright 无奈人生
2.2 释放重引用的位置
接下来的问题是——matroska_segment_c 对象是在哪里被释放,又是在哪里被重新分配呢?尝试使用!heap -p -a 查看分配此内存时的栈回溯信息,发现无法却显示。
这是因为这里编译器采用了一种称为 FPO(Frame Pointer Omission)的优化方式,它压缩或者省略了在栈上为函数创建栈帧指针的过程。这样可以加速函数调用,但是在这种情况下,调试器可能不能基于 EBP 展开栈帧(除非它有启用了 FPO 模块相匹配的符号文件,而前面提到过,我们没有办法生成用于 Windbg 调试的 PDB 文件)。
www.wnhack.com