CVE-2016-1897/8 ffmpeg任意文件读取/SSRF漏洞复现

CVE-2016-1897/8 ffmpeg任意文件读取/SSRF漏洞复现

FFmpeg是我前段时间分析某视频网站加密的时候了解到的,功能非常强大。是视频处理最常用的开源软件,用途广泛,大量用于视频网站和商业软件(比如 Youtube 和 iTunes),也是许多音频和视频格式的标准编码/解码实现。在FFMpeg2.X 由于在解析HTTP Live Streaming流媒体m3u8文件处理不当,可导致SSRF漏洞与任意文件读取漏洞。当网站允许用户上传多媒体文件,并使用FFMpeg进行处理时会触发该漏洞。

HLS(HTTP Live Streaming)

HLS(HTTP Live Streaming)是Apple公司开发的一种基于HTTP协议的流媒体通信协议,大多数都应用在PC上和Iphone上。它的基本原理是把一个视频流分成很多个很小的ts流文件,然后通过HTTP下载,每次下载一点点。在一个开始一个新的流媒体会话时,客户端都会先下载一个m3u8(播放列表 Playlist)文件,里面包含了这次HLS会话的所有数据。HLS简单来说就是视频流文件,现在大多数的视频网站都是采用流媒体的形式播放视频。用我自己的话说就是把一个完整的视频文件切割成了非常多个ts文件,ts还是视频文件,只不过每个ts的时间很短。

HLS的index文件,所谓index文件就是m3u8文本文件。客户端播放HLS视频流的逻辑其实非常简单,先下载一级Index file,它里面记录了二级索引文件(Alternate-A、Alternate-B、Alternate-C)的地址,然后客户端再去下载二级索引文件,二级索引文件中又记录了TS文件的下载地址,这样客户端就可以按顺序下载TS视频文件并连续播放。

#EXTM3U
#EXT-X-TARGETDURATION:8
#EXT-X-ALLOW-CACHE:YES
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:3.754,
seg-1-f1-v1-a1.ts?1mqgoyWZAC6vEjtMMTcvGkyU5AimjYcZuGVfPqAufYI769J-tDClP-xags8qqmD5umWfpLyFAP5hwohKTpafGO5K_YUNc1kX05uBi5aOEM9LUzUdXeFmKSoqVUtlWwIDDzsdIUwBsZ4LIgpc4PtGQDflORbu7nMMg-W5rNWM_wnyLJMW8le4M39TwCecyXAgwLYJM7trTWZBMWWhpQQg
......
#EXTINF:7.257,
seg-1162-f1-v1-a1.ts?1mqgoyWZAC6vEjtMMTcvGkyU5AimjYcZuGVfPqAufYI769J-tDClP-xags8qqmD5umWfpLyFAP5hwohKTpafGO5K_YUNc1kX05uBi5aOEM9LUzUdXeFmKSoqVUtlWwIDDzsdIUwBsZ4LIgpc4PtGQDflORbu7nMMg-W5rNWM_wnyLJMW8le4M39TwCecyXAgwLYJM7trTWZBMWWhpQQg
#EXT-X-ENDLIST

这里我用P站的m3u8文件举例子,只截取了开头和结尾部分。

  • #EXTM3U 标签是m3u8的文件头,开头必须要这一行
  • #EXT-X-TARGETDURATION 每个分片TS的最大的时长, 这里是8秒
  • #EXT-X-ALLOW-CACHE 是否允许cache
  • #EXT-X-VERSION该标签可有可无
  • #EXT-X-MEDIA-SEQUENCE 第一个TS分片的序列号
  • #EXTINF 表示该一段TS流文件的长度
  • #EXT-X-ENDLIST 这个相当于文件结束符

这些是m3u8的最基本的标签,而问题就出在FFMpeg去请求TS流文件的时,由于我们可以伪造一个m3u8文件,FFMpeg不会判断里面的流地址,直接请求。

对于HLS有所了解了,再来看漏洞本身,先看vulhub对该漏洞环境提供了一个视频上传的功能。

<?php
if(!empty($_FILES)) {
    $filename = escapeshellarg($_FILES['file']['tmp_name']);
    $newname = './' . uniqid() . '.mp4';
    shell_exec("ffmpeg -i $filename $newname");
}
?>

从ffmpeg -i $filename $newname可知直接将参数带入ffmpeg执行,对上传的文件没有做任何检查。这里我们上传一个自己构造的m3u8文件。

这里我仅保留了一些m3u8文件必须的参数,(#EXT-X-MEDIA-SEQUENCE或#EXT-X-TARGETDURATION必须存在任意一个,前者是定义ts流文件的序号。去掉会报错:无效文件),然后提交该文件。

同时在我的vps上用nc监听该端口。

从user-agent可以看出确实是ffmpeg/libav访问的UA,直接发起了http请求,这就造成一个SSRF。结合SSRF任意文件读取,再看看ffmpeg支持的协议。

Input: 【输入协议】
applehttp bluray cache concat crypto data file gopher hls http httpproxy https mmsh mmst pipe rtp srtp tcp tls udp rtmp rtmpe rtmps rtmpt rtmpte

Output:【输出协议】
file gopher http httpproxy https md5 pipe rtp srtp tcp tls udp rtmp rtmpe rtmps rtmpt rtmpte

zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。