我们可以控制你看到的内容:主流IPTV远程代码执行漏洞分析
41yf1sh 嘶吼专业版
概述
大约在一年前,Check Point研究团队发现乌克兰电视流媒体平台存在严重漏洞,一旦被利用,可能会使服务提供商面临严重风险。具体而言,者可能会获取整个客户数据库中的个人信息和财务详细信息,并且者还可以将其选择的任何内容以流式传输到其客户网络的屏幕上。
尽管不确定存在此漏洞的确切数量,但Check Point研究团队发现有超过1000家提供此项服务的提供商,其全球客户的数量可能会非常高。由于此漏洞已经被修复,目前我们可以披露漏洞的具体细节。
漏洞背景
Infomir是乌克兰的IPTV(互联网协议电视)、OTT(互联网应用服务)和VOD(视频点播)设备的制造商。这些机顶盒(STB)基本上都是以流式传播,一端连接到电视服务提供商,另一侧连接到电视上。每一台机顶盒(STB)都与名为Ministra(以前的名称是Stalker)的专用平台通信,并从其中接收数据。
为了接收电视网络,STB连接到Ministra,服务提供商使用Ministra平台管理他们的客户。如果***者未经授权访问此平台,他们可能会暴露服务提供商客户群的财务详细信息,或者更改发送给服务提供商客户的内容。
尽管不清楚有多少人可能受到此漏洞的影响,但由于涉及三个独立的实体(IPTV产品制造商Infomir、Ministra平台的服务提供商、使用家庭服务的最终用户),Check Point研究团队发现大约有1000多家服务提供商购买了Ministra并将其提供给客户。遗憾的是,我们不清楚这些经销商中有多少客户,但从我们最初的扫描结果来看,全球有超过1000家经销商,因此这些经销商的数量可能非常高。
在本报告中,我们讨论了STB管理平台Ministra中发现的主要漏洞,这些漏洞可以使得***者完全控制服务器。
负责任的漏洞披露原则:Check Point研究团队在一年前向Infomir报告了此漏洞,并在修复补丁后发布了补丁。鉴于可能有服务提供商尚未实施此补丁,我们还向CTA论坛报告了此问题,安全供应商已经采取行动更新其产品,以防范此类***。
由于一些经销商可能没有修复他们的服务,因此仍有遭受***的风险,我们建议客户联系他们的电视流媒体服务提供商,确保他们已经实施针对此Ministra漏洞的保护。
Check Point***防御产品(IPS)针对Infomir经销商提供了针对此威胁的保护:
“Infomir Ministra SQL注入远程代码执行”
下图展示了可用Ministra实例的密度,很可能代表服务提供商的密度:
服务提供商数量排名前10的国家(该信息仅来源于部分渠道,通过多种方法收集):
· 美国(199)
· 荷兰(137)
· 俄罗斯(120)
· 法国(117)
· 加拿大(105)
· 保加利亚(85)
· 乌克兰(72)
· 德国(65)
· 波兰(25)
· 塞尔维亚(22)
***面分析
Ministra是Infomir的Web管理平台,用于控制STB设备。该平台基于PHP,与大多数基于Web的平台一样,它具有一个需要身份验证的管理界面。但是,我们能够绕过身份验证机制,并利用一些管理类AJAX API函数。这样一来,将导致SQL注入,与PHP对象注入漏洞相结合,从而有效地允许我们在服务器上执行远程代码。
身份验证绕过漏洞分析
位于路径“admin/src/Controller”的某些管理面板控制器包含用于Ajax使用的功能。我们从“VideoClubController”中看到名为“video_categories_list_json”的函数如下:
如果“X-Requested-With”标头与“XMLHttpRequest”的内容一起发送,则“$this->isAjax”属性将设置为True。
如我们所见,此方法明确用于Ajax使用,因此仅针对于这种场景检查身份验证。但是,我们尝试通过不发送此标头来绕过身份验证检查,结果引发了一些意想不到的行为。
未经身份验证的SQL注入
由于我们可以绕过某些函数的身份验证(上述行为模式也可以在其他函数中找到),这就扩展了我们的***面。其中一个位于“VideoClubController”的“video_schedule_list_json”函数如下:
如我们所见,变量“$param”被分配了“$this->data”(GET数组数据)或“$this->postData”(POST数组数据),然后传递给“prepareDataTableParams”函数。
该函数的第一部分检查应该对哪些列进行排序。函数会循环遍历“order”数组参数,并使用“order”参数中的列值,从“coloums”数组中获取列数据。然后,为“$col_name”变量分配列的名称。
如果该列是可以使用的,则“$col_name”会被添加到“$query_param[‘order’]”数组之中。这里值得关注的地方是,用户可以通过发送类似的POST数据,从而控制“$col_name”,而这是“$query_param”数组中的一个键值:
order[][dir]=aaa&order[0][column]=0&columns[][name]=ColumnName&columns[0][orderable]=1
函数的第二部分负责按列或按搜索项过滤结果。它会在“$query_param[‘select’][]”中添加“$col_name”作为键值。此外,还将检查列是否可以被搜索,如果可以,则会将其添加到“$query_param[‘like’]”数组中。在这里,用户可以通过控制“$col_name”并发送类似数据来控制密钥:
columns[0][name]=ColumnName&columns[0][visible]=true&columns[0]
[searchable]=true&search[value]=myserach
在该函数返回后,“video_schedule_list_json”将操纵“$query_param”变量,然后调用“getAllVideoTasks”函数:
“getAllVideoTasks”函数执行SQL查询:
如前所述,用户可以控制order、like和select键,这就会引起一些安全问题。通常,键值是不会被正确清理的,因为它们并非来自用户控制的数据。遗憾的是,我们没有“mysqlInstance”对象实现的源代码,因为它是使用IonCube编码的,其许可证禁止我们接触到类文件。我们唯一的选择是通过黑盒测试,对负责处理受控制的值的函数进行测试。经过一些测试后,我们发现,传递给orderby、select和like函数的键值很容易受到SQL注入***。当我们控制查询中的键值时,我们可以进行盲注,或反射型SQL注入。
总而言之,该漏洞的根本原因是“prepareDataTableParams”函数允许用户控制的数据影响此后未经正确处理的键值。此外,从代码中的多个位置都会调用此函数,这也就意味着可以从其他位置触发此漏洞。
接下来,我们将这个SQL注入漏洞与一个更加强大的原语相连接。
未经身份验证的对象注入
实际上,允许用户提供的数据进入“unserialize”函数是非常危险的。调用“unserialize”的控制器的私有函数之一是来自“VideoClubController”的“setLinksForVideoLog”:
这个函数从“video_logs_json”函数调用,同样来自“VideoClubController”:
该函数容易受到身份验证绕过漏洞的影响,并且还会调用易受SQL注入***的“prepareDataTableParams”。
随后,在这个函数中,这些行被调用:
“$query_param”变量由“prepareDataTableParams”的结果构造,然后传递给“getVideoLog”函数。我们可以在这里执行一个反射型SQL注入,结果将会返回我们想要“$response[‘data’]”的任何数据。
该数据将在稍后被传递给“setLinksForVideoLog”函数,该函数使用“unserialize”函数。因此,在这里我们就找到了一个经典的SQL注入导致对象注入漏洞。
任意文件写入(远程代码执行)
我们在下一步,可以看看如何利用这个PHP对象,注入更强大的原语。利用对象注入时,需要做的第一件事就是寻找魔术方法。然后,在我们尝试实例化的对象上调用这些方法。例如,在对象的销毁过程中调用方法“__destruct”。我们搜索了对这个函数的引用,并在SwiftMailer库类(Swift_Transport_SendmailTransport)中找到了一个关键的接收器:
我们可以看到,在“__destruct”实现中,调用了“stop”函数。
根据类名,我们知道它用于处理与SMTP相关的功能。我们可以假设,当调用“__destruct”函数时,它将会结束SMTP会话。我们可以看到,调用“executeCommand”函数可能会将“QUIT”命令发送至SMTP服务器,以确保会话的正确关闭。
通过调用“write”函数,系统会尝试通过套接字发送“$command”,或将其写入文件。但是,由于我们控制“$this->_buffer”属性,所以我们可以将它设置为想要实现“write”函数的任何对象。在搜索实现此函数的类之后,我们发现了“Swift_ByteStream_FileByteStream”类,其父级实现了“write”函数:
由于我们还控制了这个对象的属性,我们可以将“$this->_writeBuffer”设置为我们想要的任何值。我们来看看“_doWrite”:
“_doWrite”函数调用“_filter”函数,但我们可以通过将“$this->_filters”设置为空值来忽略这种情况。接下来,它使用我们的控制器值调用“_commit”。
非常有趣,它使用受我们控制的数据调用了“fwrite”函数(用于将数据写入文件)。但是,句柄来自哪里呢?
我们可以看到,如果没有设置“$this->_writer”,则会打开一个句柄来处理“$this->_path”中的文件路径。正如我们之前所说,我们可以控制这个类的所有属性:可以将“$this->_writer”设置为False,将“$this->_path”设置为我们想要的任意路径。
最后,我们可以控制文件的路径和内容。使用此原语,我们可以编写任意PHP文件,并在服务器上执行远程代码。需要注意的一点是,上面的write函数将“QUIT”附加到内容的末尾。因此,要获得有效运行的PHP代码,最好在数据末尾添加一个注释符号(//)。
在这里,我们发现了一个有趣的事实,我们使用的所有类都与SwiftMailer相关。因此,我们找到了一个通用文件写入的小工具。我们现在可以使用PHPGGC(SwiftMailer/FW4)生成这个小工具。
演示视频:https://youtu.be/jqXPePSefss
总结
在这篇文章中,我们展示了一个微小的逻辑错误,有时可能导致一个关键的安全问题。在这种特殊情况下,我们在服务器上实现了身份验证绕过,从而执行SQL注入。在掌握了这些知识的基础之上,我们将此漏洞升级为对象注入漏洞,而这反过来又允许我们在服务器上执行任意代码,不仅可能会影响供应商,还可能影响供应商的客户。
这些漏洞已经在5.4.1版本(Stalker / Ministra)中得到修复,但我们强烈建议供应商将其系统更新到最新版本。
Check Point***防御产品(IPS)针对Infomir经销商提供了针对此威胁的保护:
Infomir Ministra SQL注入远程代码执行