欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

CVE-2017-9765:深入分析一个影响数百万IoT设备的漏洞

来源: 作者: 时间:2019-02-24 19:29 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

一、前言
在另一篇文章中,我们初步介绍了Devil’ Ivy这个漏洞的整体情况及影响范围,本文从技术角度深入分析了这一漏洞的细节。
从去年起,我们开始分析远程配置类服务的安全性,彼时我们并不知道我们会发现那么多漏洞,也不知道这些漏洞会影响那么多用户。我们一直在研究远程配置类服务中漏洞的普遍性及共同特性,因此当我们接触到M3004这个设备时,我们自然会去寻找这类服务。首先我们枚举了M3004设备的开发端口,检查负责处理输入数据的那些代码。我们发现了一个名为wsd的服务,该服务会从gSOAP中导入一个第三方库。我们利用IDA Pro这个逆向分析工具来检查负责将输入数据写到栈缓冲区中的那些代码,最终在这些代码中发现了一个漏洞。

图1. IDA Pro中正在分析的某个函数
作为一款安全摄像头,M3004在80端口上提供了一个ONVIF服务,如果向该服务发送一个POST命令就会触发存在漏洞的代码。该设备内部预置了gdbserver工具,我们通过Web界面启用SSH接口,然后利用SSH接口对设备服务进行远程调试,通过这种方式,我们得以观察服务的内部工作流程以及我们代码的输出结果。我们在栈上设置了一个断点,当溢出数据覆盖掉栈上保存的某个返回指针时,我们观察到程序会发生崩溃,进而验证了漏洞的存在。接下来我们需要做的就是实现目标设备上的代码执行。
虽然将数据写入栈上时我们没有受到字节数的限制,但仅凭这一点我们还是无法实现代码执行,并且设备存在过滤机制,要求我们发送的数据值必须大于31。我们使用了一种名为ROP(Return Oriented Programming,返回导向编程)的技术,以便将地址信息写入栈中,强迫程序执行libc中的代码片段,从而实现对栈上代码执行限制条件的规避。通过这种技术,我们分配了可以执行的空间,将我们的shellcode复制到该空间中,然后将执行过程引向此地址。虽然我们所使用的地址中包含的值必须大于31,这在某种程度上的确给我们造成一些限制,但我们仍然可以完成代码执行目标。
一旦我们研究到这一步,我们就可以编写shellcode(当然所有值都应该大于31),利用shellcode打开端口,使远程用户可以连接到设备的shell。此时我们利用Devil’s Ivy(CVE-2017-9765)已经拿到了代码执行权。由于Axis做了些安全设置,利用这个漏洞我们只能在M3004上以非特权用户身份访问shell。然而,我们可以执行ONVIF中包含的某些命令,而通常情况下只有特权用户能够执行这些命令。我们可以将摄像头恢复到出厂设置状态,可以控制摄像头,可以重启摄像头防止操作员监控视频,也可以更改网络设置。
读者可以继续阅读下文的技术细节,也可以直接拉到文章末尾,观看演示视频。
二、访问设备
首先我们从Axis的官网上下载了M3004设备的最新版固件。官网的确要求注册账户才能下载固件,但并没有去验证用户是否是合法的客户。我们构造了一个Nate Johnson身份,使用了一个可达的邮箱地址,然后非常顺利地下载到了设备固件。我们使用binwalk以及专用于JFFS2文件系统的Jefferson提取器提取了固件中的文件系统以及Linux内核。

图2. binwalk的输出结果
我们运行nmap来扫描摄像头开放的端口,发现1900(upnp)、3702(ws-discover)以及5353(mdns)开放。对文件系统做了一些分析后,我们发现ws-discover与处理SOAP协议的wsd有关。wsd需要导入libsoap.so库(来自于Genivia提供的gSOAP产品)来解析输入的SOAP消息,我们仔细检查了负责将输入数据写入栈中的那些代码,然后使用IDA Pro查找栈缓冲区,手动跟踪复制到缓冲区中的那些数据的来源。通过这种方法,我们只花了1天时间,就从汇编代码中找到了这个漏洞。

图3. 从libsoap.so中导入的数据
三、代码分析
我们发现soap_get()函数中有一段代码,将输入数据写入大小为0x40字节的栈缓冲区中。这段代码会在一个循环中检查“?”结束符是否存在,或者会检查某个结尾符是否存在,条件成立才会跳出循环,而没有去检查已写入0x40字节堆缓冲区中的实际字节数。

图4. soap_get()中存在漏洞的代码
在上图中,R11为数据计数器,其值被设置栈缓冲区的大小,R7为栈缓冲区指针,R12为从网络中读取的输入字节。如果R11计数器的值小于0,函数会跳过栈缓冲区的写入过程,但会继续使用j_soap_getchar()读入数据。如果我们向wsd写入足够多的数据,就能将计数器的值重新恢复到正整数值,这样一来我们就能绕过0x40字节数的限制,将数据写入栈中。这个过程需要好几分钟,但对输入数据的数量没有作限制,并且在netcat的帮助下我们很容易就能完成这一过程。经过计算,我们发现我们需要发送0x8000000个字节才能将计数器重新恢复到一个正整数值,然后发送0x40个字节来填充大小固定的栈缓冲区,在覆盖返回地址前我们还需要再发送0x30个字节。
我们向80端口上的“onvif/device_service”服务发送了一个POST命令,进而接触到漏洞利用点。为了发送0x80000070个字节,我们构造了一个文本文件,文件开头为“POST /onvif/device_service”,在随后新的一行中使用“

nc [camera_ip] 80
我们需要更多的信息才能确定我们是否能够利用这个漏洞,此时此刻,当我们将全部数据发送完毕后,目标服务已经没有任何响应了。在Asix官方支持中心的指引下,我们通过ssh接口成功连接上摄像头。摄像头内置了一个Web服务器

[1] [2]  下一页

一、前言
在另一篇文章中,我们初步介绍了Devil’ Ivy这个漏洞的整体情况及影响范围,本文从技术角度深入分析了这一漏洞的细节。
从去年起,我们开始分析远程配置类服务的安全性,彼时我们并不知道我们会发现那么多漏洞,也不知道这些漏洞会影响那么多用户。我们一直在研究远程配置类服务中漏洞的普遍性及共同特性,因此当我们接触到M3004这个设备时,我们自然会去寻找这类服务。首先我们枚举了M3004设备的开发端口,检查负责处理输入数据的那些代码。我们发现了一个名为wsd的服务,该服务会从gSOAP中导入一个第三方库。我们利用IDA Pro这个逆向分析工具来检查负责将输入数据写到栈缓冲区中的那些代码,最终在这些代码中发现了一个漏洞。

图1. IDA Pro中正在分析的某个函数
作为一款安全摄像头,M3004在80端口上提供了一个ONVIF服务,如果向该服务发送一个POST命令就会触发存在漏洞的代码。该设备内部预置了gdbserver工具,我们通过Web界面启用SSH接口,然后利用SSH接口对设备服务进行远程调试,通过这种方式,我们得以观察服务的内部工作流程以及我们代码的输出结果。我们在栈上设置了一个断点,当溢出数据覆盖掉栈上保存的某个返回指针时,我们观察到程序会发生崩溃,进而验证了漏洞的存在。接下来我们需要做的就是实现目标设备上的代码执行。

copyright 无奈人生

虽然将数据写入栈上时我们没有受到字节数的限制,但仅凭这一点我们还是无法实现代码执行,并且设备存在过滤机制,要求我们发送的数据值必须大于31。我们使用了一种名为ROP(Return Oriented Programming,返回导向编程)的技术,以便将地址信息写入栈中,强迫程序执行libc中的代码片段,从而实现对栈上代码执行限制条件的规避。通过这种技术,我们分配了可以执行的空间,将我们的shellcode复制到该空间中,然后将执行过程引向此地址。虽然我们所使用的地址中包含的值必须大于31,这在某种程度上的确给我们造成一些限制,但我们仍然可以完成代码执行目标。
一旦我们研究到这一步,我们就可以编写shellcode(当然所有值都应该大于31),利用shellcode打开端口,使远程用户可以连接到设备的shell。此时我们利用Devil’s Ivy(CVE-2017-9765)已经拿到了代码执行权。由于Axis做了些安全设置,利用这个漏洞我们只能在M3004上以非特权用户身份访问shell。然而,我们可以执行ONVIF中包含的某些命令,而通常情况下只有特权用户能够执行这些命令。我们可以将摄像头恢复到出厂设置状态,可以控制摄像头,可以重启摄像头防止操作员监控视频,也可以更改网络设置。
读者可以继续阅读下文的技术细节,也可以直接拉到文章末尾,观看演示视频。

无奈人生安全网


二、访问设备
首先我们从Axis的官网上下载了M3004设备的最新版固件。官网的确要求注册账户才能下载固件,但并没有去验证用户是否是合法的客户。我们构造了一个Nate Johnson身份,使用了一个可达的邮箱地址,然后非常顺利地下载到了设备固件。我们使用binwalk以及专用于JFFS2文件系统的Jefferson提取器提取了固件中的文件系统以及Linux内核。

图2. binwalk的输出结果
我们运行nmap来扫描摄像头开放的端口,发现1900(upnp)、3702(ws-discover)以及5353(mdns)开放。对文件系统做了一些分析后,我们发现ws-discover与处理SOAP协议的wsd有关。wsd需要导入libsoap.so库(来自于Genivia提供的gSOAP产品)来解析输入的SOAP消息,我们仔细检查了负责将输入数据写入栈中的那些代码,然后使用IDA Pro查找栈缓冲区,手动跟踪复制到缓冲区中的那些数据的来源。通过这种方法,我们只花了1天时间,就从汇编代码中找到了这个漏洞。
copyright 无奈人生
图3. 从libsoap.so中导入的数据
三、代码分析
我们发现soap_get()函数中有一段代码,将输入数据写入大小为0x40字节的栈缓冲区中。这段代码会在一个循环中检查“?”结束符是否存在,或者会检查某个结尾符是否存在,条件成立才会跳出循环,而没有去检查已写入0x40字节堆缓冲区中的实际字节数。

图4. soap_get()中存在漏洞的代码
在上图中,R11为数据计数器,其值被设置栈缓冲区的大小,R7为栈缓冲区指针,R12为从网络中读取的输入字节。如果R11计数器的值小于0,函数会跳过栈缓冲区的写入过程,但会继续使用j_soap_getchar()读入数据。如果我们向wsd写入足够多的数据,就能将计数器的值重新恢复到正整数值,这样一来我们就能绕过0x40字节数的限制,将数据写入栈中。这个过程需要好几分钟,但对输入数据的数量没有作限制,并且在netcat的帮助下我们很容易就能完成这一过程。经过计算,我们发现我们需要发送0x8000000个字节才能将计数器重新恢复到一个正整数值,然后发送0x40个字节来填充大小固定的栈缓冲区,在覆盖返回地址前我们还需要再发送0x30个字节。 www.wnhack.com
我们向80端口上的“onvif/device_service”服务发送了一个POST命令,进而接触到漏洞利用点。为了发送0x80000070个字节,我们构造了一个文本文件,文件开头为“POST /onvif/device_service”,在随后新的一行中使用“

nc [camera_ip] 80
我们需要更多的信息才能确定我们是否能够利用这个漏洞,此时此刻,当我们将全部数据发送完毕后,目标服务已经没有任何响应了。在Asix官方支持中心的指引下,我们通过ssh接口成功连接上摄像头。摄像头内置了一个Web服务器 本文来自无奈人生安全网

[1] [2]  下一页 copyright 无奈人生

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。