15

CVE-2018-10731:工业交换机漏洞分析

 3 years ago
source link: http://4hou.win/wordpress/?p=45143
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文详细分析了Phoenix Contact交换机中FL SWITCH 3xxx、FL SWITCH 4xxx和FL SWITCH 48xx系列设备的CVE-2018-10731漏洞。此漏洞存在于设备的 Web界面中,可以在不知道设备凭据的情况下执行任意代码,CVSS3.0等级评分为9分。 

漏洞分析

上面提到的Linux,可以使用web界面对其进行配置。与许多其他家用和工业IoT设备一样,web界面由许多处理用户HTTP请求的 CGI应用程序组成。在本文的案例中,CGI应用程序使用cgic 库,这使得处理 HTTP请求更加容易,并且该库的功能内置在设备文件系统中的 libipinfusionweb.so 共享库中。

在处理HTTP请求时,web 服务器将用户请求数据作为一组环境变量传递给 CGI 应用程序。它们的初始处理由 libipinfusionweb 库中的 main 函数执行。接下来, main 函数调用CGI应用程序的 cgiMain 函数,在其中对请求进行进一步处理。

vAFZNbV.jpg!web 图1.    处理HTTP请求     

在其工作过程中, libipinfusionweb 库的main函数调用 get_login_user 函数,该函数确定用户是否已使用传递的Cookie值通过了系统身份验证。     

ymIvqiA.jpg!web 图2. main函数代码片段

函数 get_login_user 使用 cookies_get_value 函数获取 c_session 参数的cookie值,并将其存储在 local_e0 变量中。变量 local_e0 是一个长度为 0×80的单字节字符数组,并且位于距堆栈开头0xE0的距离处。

uqAFje2.jpg!web 图3.  get_login_user 函数代码片段     

但是,从 cookies_get_value 函数的代码中可以看出,使用 cgiCookieString 函数获取的cookie参数值的最大长度为0×400字节。    

zAzUvqU.jpg!web

图4.  cookies_get_value函数代码片段

因此,当传递长度超过0xE0(224)个字符的cookie参数时, get_login_user 函数会将此参数的值保存到其栈中,结果 local_e0 变量后面的栈上的所有信息将被覆盖,包括函数返回地址。 

注意:当一个函数调用另一个函数时,返回地址存储在栈中。当被调用函数完成时,控制权将转移到该返回地址。因此,如果重写此地址,则可以控制程序执行流程。例如,攻击者可以使用位于程序地址空间中的恶意shellcode的地址替换此地址。

请注意,返回地址的覆盖是在身份验证之前进行的,这使得不知道设备账户的攻击者也可能利用此漏洞。

我们考虑了几种方法来证明利用此漏洞的可能性。最简单的方法是将有效负载代码写到堆栈上(0×400-0xE0 =剩下800 字节,对于代码来说足够了),然后用代码地址覆盖返回地址。从理论上讲这是可行的,因为存在该漏洞的交换机处理器不支持NX位功能(也就是说,它允许执行位于包括堆栈在内的任何位置的代码),但实际上存在严重限制。

这些交换机处理器具有MIPS架构,此体系结构中的许多处理器指令均以包含零字节的字节序列进行编码。写入到缓冲区的内容在遇到第一个空字节时结束(由于使用了strcpy函数 ),因此仅能使用不包含空字节的操作码,但这是不可能的,因为任何有效载荷都至少使用几个空字节。

同样,在构建 ROP链 时,也将不得不面对空字节的限制:ROP gadgets的地址不应包含零,这会使地址的搜索大大复杂化。总的来说,我们只能使用由 strcpy函数复制的一个零,这限制了完整ROP链的创建。此外,我们所需的gadgets 也非常少。但是,在搜索libipinfusionweb库的时候发现了以下代码片段:             

Ab6fai3.jpg!web

图5.  libipinfusionweb库的可执行代码片段

假设寄存器$s0的内容受到控制,此代码段使用 mysystem 函数使你可以执行OS命令(该函数最初没有名称,但我们将其重命名,因为它与Linux中的system 函数非常相似)。 

由于我们正在覆盖get_login_user    函数的返回地址,因此该函数将执行到最后。从 get_login_user函数的末尾中,可以看到寄存器$s0的值是从栈上先前保存的值恢复的(从栈顶部偏移0xD8 )。不过此时,栈区域已经在我们的控制之下,也就是说,实际上,我们可以实现对寄存器$s0内容的控制,从而可以使用 mysystem 函数执行任意 OS命令。            

eieeAze.jpg!web 图6.  get_login_user函数可执行代码片段        

因此,为了成功演示此漏洞利用,需要发送的 c_session cookie 参数字符串应包含以下内容:

OS命令字符串,该命令随后将传递给mysystem函数;

OS命令在栈上的地址;

新的返回地址(图5所示的代码片段的地址)

最终的有效负载应如下所示:

vqMrQ3f.jpg!web 图7. 有效负载     

至此,我们已经利用漏洞获取了设备上的shell,该 shell需要管理员权限。因此,我们能够获得有助于后续操作的更多其他信息:

ASLR在此研究设备上被禁用,因此,所使用的gadget和OS命令的地址将始终相同。

3yueMbQ.jpg!web

图8. 被研究设备上的ASLR状态

堆栈可能位于的内存地址范围。为了计算确切的地址,我们遍历了该范围内的所有地址。

作为有效负载,我们实现了web shell—CGI应用程序的加载,其内容如下:

#!/bin/sh
eval $HTTP_CMD 2>&1

由于根据 CGI协议,HTTP标头的内容以名称为HTTP_<Header Name> 的环境变量的形式传输到CGI 应用程序,因此该shell 将使用 eval 命令执行HTTP 标头CMD的内容。下图显示了使用已加载的shell 成功运行和执行ls 命令的结果。                

aieeI3e.jpg!web 图9.  ls命令成功运行和执行的结果     

本文展示了利用此漏洞的能力,正如我们已经提到的,其操作不需要知道密码,因此甚至可以由未经身份验证的攻击者执行。

入侵工业网络交换机可能会破坏整个网络环境,网络交互中断会对进程产生不利影响,直到它完全停止。

译文,原文请参考: https://habr.com/ru/company/pt/blog/493944/

*本文作者:bey0nd,转载请注明来自FreeBuf.COM


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK