VLC播放器加载恶意字幕文件导致执行任意代码漏洞分析与out-of-bo
今年5月23号的时候,听说checkpoint搞了个大新闻:vlc等播放器加载特定字幕可以完全控制用户电脑。当时我就震惊了:还有何种操作。想想看,当你吃着辣条,看着电影,突然就弹了个计算器,这电影真高级(滑稽。震惊之余就有点好奇到底是怎么做到的,但是当时checkpoint说考虑到影响,暂时不会公布细节。刚好这几天有空,就分析了一下。
1. 官方公告
这是checkpoint的新闻。Checkpoint对这个漏洞的描述是:VLC ParseJSS Null Skip Subtitle Remote Code Execution
http://blog.checkpoint.com/2017/05/23/hacked-in-translation/
这篇里面有对应的cve列表
>https://threatpost.com/subtitle-hack-leaves-200-million-vulnerable-to-remote-code-execution/125868/
CVE列表
https://nvd.nist.gov/vuln/detail/CVE-2017-8313
https://nvd.nist.gov/vuln/detail/CVE-2017-8312
https://nvd.nist.gov/vuln/detail/CVE-2017-8311
对应的代码patch地址,在cve链接里面有
这里用vlc2.2.4版本的源码和32bit release来分析,大家可以自己到vlc官网下载。
有问题的函数代码贴在文章最后面,方便分析。
2. 分析漏洞
大致阅读以下ParseJSS函数的代码,可以猜测漏洞应该跟缓冲区溢出有关,而且是堆上的缓冲区。
堆缓冲区溢出的利用思路一般是实现out-of-bounds write,根据write的数据不同,又有更具体的细分(实际上有的利用方法在最新的os里面已经失效了)
覆盖heap链表的元数据,实现write what where
覆盖相邻heap上的对象的虚表
覆盖相邻heap上的函数指针
覆盖相邻heap上的FILE对象
覆盖相邻heap上的数组的元数据实现内存任意读写
等等
总的来说一句话:先实现out-of-bounds write,这是最关键的一步
CVE-2017-8313
这个cve的描述大致是由于在循环遍历字符串字符的时候,没有检查字符串终止标记(0字符),导致out-of-bounds read。下面是对应的patch
这个改动很好理解,就不多说了。
其实我一度以为这个patch对应checkpoint对漏洞的描述:VLC ParseJSS Null Skip Subtitle Remote Code Execution。但实际上并不是。。。
不过这里是out-of-bounds read,最多也就抛异常,如果能覆盖SEH结构的话,倒还有点用,但是并没有。所以先跳过这个。
CVE-2017-8312
这个cve的大概描述是由于没有检查字符串长度,导致越界读内存(out-of-bounds read),可能会读到没有初始化的数据。
从patch里面可以看到,shift似乎受我们控制,但是这里只能实现越界读,并不能实现越界写。
剩下最后一个了,看看有没有惊喜。
CVE-2017-8311
这个cve的描述大概是由于跳过字符串终止标记导致缓冲区溢出,从而导致执行任意代码。
看起来就是关键啊,先来看看patch。
这部分代码是在switch的这个分支里面:case ‘\’:
这里psz_text被加了两次,然后switch的break出去之后,还有一次psz_text++;总共加了3次。
所以如果刚好*(psz_text + 2) ==‘0’的话,会导致这个0字符被跳过,然后就溢出了。
问题是,看起来这个0字符后面的数据不受我们控制啊。
如果你尝试构造一下类似的字符串测试,会发现提前就被截断了:
abcd‘0’ efg
efg这部分数据到不了后面的代码路径。
怎么办?
如果你用调试器自己一遍运行流程的话,你会发现,psz_text的地址似乎有可能每次都一样的。
是不是想到了什么?对的,就是类似heap spraying。
假设有两个字符串,1的长度比2的长
那么加载1,首先在内存里看到的是
BBBBBBBBBBBBBBB
然后加载2,在内存里看到的是
aaaaaaaaaaa’0’BBBB
0字符后面的数据是受我们控制的
3. poc
考虑到影响,更进一步的分析就不做了,这里放出供测试用的poc
把这段字符串复制到文本文件里面,保存为jss后缀的文件就可以了。
0:0:0.0 0:0:0
0:0:0.0 0:0:0.0 [ BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
0:0:0.0 0:0:0.0 [ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\C
在调试器里验证的结果
4.ParseJSS的代码方便参考
static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
{
VLC_UNUSED( i_idx );
demux_sys_t *p_sys = p_demux->p_sys;
text_t *txt = &p_sys->txt;
今年5月23号的时候,听说checkpoint搞了个大新闻:vlc等播放器加载特定字幕可以完全控制用户电脑。当时我就震惊了:还有何种操作。想想看,当你吃着辣条,看着电影,突然就弹了个计算器,这电影真高级(滑稽。震惊之余就有点好奇到底是怎么做到的,但是当时checkpoint说考虑到影响,暂时不会公布细节。刚好这几天有空,就分析了一下。
1. 官方公告
这是checkpoint的新闻。Checkpoint对这个漏洞的描述是:VLC ParseJSS Null Skip Subtitle Remote Code Execution
http://blog.checkpoint.com/2017/05/23/hacked-in-translation/
这篇里面有对应的cve列表
>https://threatpost.com/subtitle-hack-leaves-200-million-vulnerable-to-remote-code-execution/125868/
CVE列表
https://nvd.nist.gov/vuln/detail/CVE-2017-8313
https://nvd.nist.gov/vuln/detail/CVE-2017-8312
https://nvd.nist.gov/vuln/detail/CVE-2017-8311
对应的代码patch地址,在cve链接里面有
这里用vlc2.2.4版本的源码和32bit release来分析,大家可以自己到vlc官网下载。
有问题的函数代码贴在文章最后面,方便分析。 copyright 无奈人生
2. 分析漏洞
大致阅读以下ParseJSS函数的代码,可以猜测漏洞应该跟缓冲区溢出有关,而且是堆上的缓冲区。
堆缓冲区溢出的利用思路一般是实现out-of-bounds write,根据write的数据不同,又有更具体的细分(实际上有的利用方法在最新的os里面已经失效了)
覆盖heap链表的元数据,实现write what where
覆盖相邻heap上的对象的虚表
覆盖相邻heap上的函数指针
覆盖相邻heap上的FILE对象
覆盖相邻heap上的数组的元数据实现内存任意读写
等等
总的来说一句话:先实现out-of-bounds write,这是最关键的一步
CVE-2017-8313
这个cve的描述大致是由于在循环遍历字符串字符的时候,没有检查字符串终止标记(0字符),导致out-of-bounds read。下面是对应的patch
这个改动很好理解,就不多说了。
其实我一度以为这个patch对应checkpoint对漏洞的描述:VLC ParseJSS Null Skip Subtitle Remote Code Execution。但实际上并不是。。。
不过这里是out-of-bounds read,最多也就抛异常,如果能覆盖SEH结构的话,倒还有点用,但是并没有。所以先跳过这个。
无奈人生安全网
CVE-2017-8312
这个cve的大概描述是由于没有检查字符串长度,导致越界读内存(out-of-bounds read),可能会读到没有初始化的数据。
从patch里面可以看到,shift似乎受我们控制,但是这里只能实现越界读,并不能实现越界写。
剩下最后一个了,看看有没有惊喜。
CVE-2017-8311
这个cve的描述大概是由于跳过字符串终止标记导致缓冲区溢出,从而导致执行任意代码。
看起来就是关键啊,先来看看patch。
这部分代码是在switch的这个分支里面:case ‘\’:
这里psz_text被加了两次,然后switch的break出去之后,还有一次psz_text++;总共加了3次。
所以如果刚好*(psz_text + 2) ==‘0’的话,会导致这个0字符被跳过,然后就溢出了。
问题是,看起来这个0字符后面的数据不受我们控制啊。 www.wnhack.com
如果你尝试构造一下类似的字符串测试,会发现提前就被截断了:
abcd‘0’ efg
efg这部分数据到不了后面的代码路径。
怎么办?
如果你用调试器自己一遍运行流程的话,你会发现,psz_text的地址似乎有可能每次都一样的。
是不是想到了什么?对的,就是类似heap spraying。
假设有两个字符串,1的长度比2的长
那么加载1,首先在内存里看到的是
BBBBBBBBBBBBBBB
然后加载2,在内存里看到的是
aaaaaaaaaaa’0’BBBB
0字符后面的数据是受我们控制的
3. poc
考虑到影响,更进一步的分析就不做了,这里放出供测试用的poc
把这段字符串复制到文本文件里面,保存为jss后缀的文件就可以了。
0:0:0.0 0:0:0
0:0:0.0 0:0:0.0 [ BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
0:0:0.0 0:0:0.0 [ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\C
内容来自无奈安全网
在调试器里验证的结果
4.ParseJSS的代码方便参考
static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
{
VLC_UNUSED( i_idx );
demux_sys_t *p_sys = p_demux->p_sys;
text_t *txt = &p_sys->txt;
本文来自无奈人生安全网