虹科案例|虹科Vdoo安全性防护平台-海康威视摄像机中的重大漏洞

虹科Vdoo的安全研究团队对领先的物联网产品和安全设备进行了大规模的安全研究,为了提高效率和透明度,此过程设备供应商也参与其中。

这项研究的一部分是研究人员在多家供应商的设备中发现了零日漏洞。这些漏洞我们已经负责任地以最佳方式向供应商披露,并将在披露期限结束后逐步分享。

我们发现易受攻击设备的供应商之一是海康威视。研究团队在海康威视安全摄像机中发现了一个漏洞。攻击者利用该漏洞能成功获取摄像机IP地址,并且使用摄像机的root特权(通过LAN或Internet)远程执行代码。虹科Vdoo负责任地披露了此漏洞(CVE-2018-6414),并与海康威视的安全团队合作解决了此问题。

该漏洞并未在现场得到利用,因此不会对海康威视客户造成任何具体的隐私侵犯或安全威胁。海康威视团队迅速采取了行动,修补了此漏洞,并将其他易受攻击的产品也安装了补丁。

技术概述

摄像机运行Linux操作系统。davinci进程包括摄像机的许多功能,比如Web服务器,并以使用者ID 0特权运行(用户ID名为“admin”,当使用者ID为0时,它有效地赋予了root特权)。摄像头的Web界面基于Embedthis appweb 3 Web服务器,海康威视为其添加了一些代码。

海康威视添加了Web服务器的一些特殊页面来控制摄像机的设置,通常这些特殊页面仅在HTTP身份验证通过后运行,但是其中一些页面不需要身份验证。

在处理对不需要HTTP身份验证的页面的请求的代码中,存在对sscanf的非安全调用,当使用特制请求时,该调用会导致缓冲区溢出,从而损坏内存和导致任意代码执行或进程崩溃。

技术挑战

此漏洞使攻击者可以在相机的固件中执行他们选择的一段代码。当用户使用登录网页登录时,将发送一个POST请求,其中也可以包含GET参数。

在解析特定GET参数的代码中,有一个对isoc99_sscanf的调用。该isoc99_sscanf函数类似于已知的scanf函数,但不是从stdin读取它的输入,而是从一个字符串输入。在这种情况下,输入的字符串包含请求查询字符串:

函数的格式字符串由参数名称组成,后面连接“ =%s”。这意味着函数期望字符串以参数名称开头,后面连接“ =”,然后将其后的任何字符串读入上图中名为“ s1”的堆栈变量中。这允许我们向堆栈中写入任意数量的字节,%s没有限制。唯一的限制是Web服务器应用于整个URI(包括查询字符串)的限制。

在页面背后的任何逻辑发生之前,首先应用Web服务器的限制,如appweb 3源代码所示(可以在github上查找):

通过查看相关功能,可以找到海康威视摄像机分配给maxUrl的值:

将伪代码与原始代码进行比较时,很容易理解“ v3 [52]”代表conn-> http-> limits,并且该值的偏移量是48。当找到用于初始化值的函数时我们将看到该值设置为0x400(这与原始appweb 3源代码中找到的值不同):

当使用GET变量从0x400中减去URI的长度时,我们得到了可以在变量的值中使用的有效负载的限制。我们仍然需要从该值中减去一个字节,因为还检查了URI的长度是否相等。现在,我们可以检查可用字节可以做什么。

回到漏洞的函数,我们将观察堆栈框架并检查其中的“ s1”变量的偏移量。在此特定固件中,变量位于与堆栈起始位置足够近的偏移量处,这意味着我们可能会溢出到堆栈帧的起始位置。但是,在我们检查的某些其他固件版本中,该变量位于堆栈的较低地址,这不允许我们到达堆栈帧的起始位置。在这种情况下,如果通过覆盖驻留在堆栈框架上的变量,漏洞可能仍会部分被利用。

由于调用函数的返回地址位于堆栈帧的起始位置,因此通过覆盖它,我们可以控制接下来要运行的代码(在函数返回时)。

由于攻击是基于%s sscanf格式说明符的,因此我们不能在攻击中使用任何空格,也不能使用NULL字符。这限制了我们,因为代码部分中的所有地址都以NULL字节开头。但是,我们使用了众所周知的技术来克服此限制。

帮助利用此漏洞的一件重要的事是,虽然已将ASLR用于已加载的共享库,但未将其用于固件的主要二进制文件。因此,可以准确知道代码所在的位置,从而使我们可以跳至自己选择的代码段。我们还可以看到没有使用stack canaries,因此我们可以安全地覆盖堆栈的内容,而无需对其进行检查。

完成所有操作后,我们需要选择一个地址跳转至该地址。例如,类似于Foscam PoC,我们选择跳到一段代码来重置设备的凭据,从而使我们能够以管理员身份登录设备。然后,作为设备管理员,我们可以控制任何设置,包括使用自定义固件升级设备的能力。 

考虑到此漏洞带来的风险,我们决定不发布PoC,以保护尚未升级其设备的用户免受恶意攻击。

给设备制造商的建议

攻击者很容易发现并利用相机中的不良体系结构导致的漏洞,因此制造商应该检查其设备研发过程中是否存在以下问题:

1.使用不安全的函数。sscanf是一个潜在的不安全函数,尤其是与%s或%[]一起使用时。可以在支持的API中用sscanf_s替换sscanf,或者可以通过添加长度说明符来安全使用sscanf(需要确保长度小于缓冲区长度,应谨慎使用)。最佳操作是即使在特定情况下也不要使用任何不安全的功能版本,定期使用它们很危险。特别是,建议不要使用sscanf。固件中发现的其他可能不安全的功能包括strcpy(可以替换为strncpy),strcat(可以替换为strncat),sprintf(可以替换为snprintf)等等。

2.主二进制文件缺少ASLR。ASLR已在设备上运行的Linux OS中实现并打开,唯一要做的更改是通过在GCC上添加“ -pie-fPIE”标志来使其与主要二进制文件兼容。使用此功能,攻击者无法猜测他想跳转到的功能地址。

3.缺少stack canaries。这是一个非常简单且重要的安全功能,可以通过在GCC中添加“ -fstack-protector-all”标志来启用该功能,当可执行文件识别出堆栈受到破坏时将崩溃。这将导致短暂的拒绝服务,但至少它不允许攻击者运行其选择的代码。重要的是要注意此功能可能会导致性能下降,因为对每个功能都检查了stack canaries。如果性能下降使其无法使用,则可以控制stack canaries的创建,并将其设置为仅放在极容易遭受基于堆栈的缓冲区攻击的函数上。这可以通过将“ -fstack-protector”标志与“ –param ssp-buffer-size”一起使用来完成。

4.URL参数应该被清理为仅包含ASCII可打印字符。与ASLR结合使用,将降低该漏洞的利用率。

5.使用对称加密对固件文件进行加密。这使攻击者可以打开固件进行研究。

6.固件文件未经过数字签名。这使攻击者可以重新打包恶意固件,供应商应考虑签署其固件,以防止受到这种威胁。

7.在我们研究的固件中,使用了appweb 3,特别是它的旧版本-长期未维护。如https://www.embedthis.com/appweb/download.html 所述,此版本以及一些较新的版本被称为“寿命终止”,这意味着它将不会获得任何安全补丁。

8.该设备的几乎所有逻辑都包含在一个二进制文件中。当所有内容都在一个二进制文件中时,特权分离就会减少,这会增加攻击面。例如,任何设备功能中可能存在的拒绝服务漏洞都将使主进程崩溃,并且许多设备功能也将遭受损失,而不仅仅是使负责特定逻辑的进程崩溃。将摄像机的逻辑划分为不同的二进制文件可能还会使利用代码执行漏洞变得更加困难,因为进程内存中的可用代码更少,无法跳转。