紫金桥组态软件是某工控系统的上位机控制软件,官方网站:http://www.realinfo.com.cn/
此漏洞发布于 2020-12-03,CNVD 链接:https://www.cnvd.org.cn/flaw/show/CNVD-2020-59818
基本信息
漏洞评分:高
漏洞描述:紫金桥监控组态软件是一款专业的紫金桥监控组态软件,采用C/S体系结构,拥有数据库处理技术和图形系统。紫金桥监控组态软件存在远程栈溢出漏洞。攻击者可利用漏洞导致web服务崩溃。
漏洞分析
工控系统简介
工控设备和一些常见的 IoT 设备有很多相似的地方,工控系统通常分为上位机和下位机,下位机负责直接控制设备或者获取设备状况,一般是一些 PLC 或者单片机,它们的计算能力较弱,只负责数据的采集和简单控制。
上位机可以直接发出操控命令,充当控制者的角色,通常由 PC 构成。
我们分析的漏洞就出现在上位机控制软件中,紫金桥组态软件官网宣称其用户包括中国石油、中国石化、中船重工等。
由于上位机充当整个系统的控制管理角色,其地位是比较重要的,一旦恶意用户掌握了上位机的操控权限,即可对整个生产流程进行修改,这将对工业生产造成极大的威胁。
软件下载地址(紫金桥监控组态软件 V6.5):http://www.realinfo.com.cn/html/software/Realinfo/index.html
下载完成之后运行 Setup.cmd 安装。
漏洞描述中提到了触发漏洞将导致 web 服务崩溃,我们可以去官方帮助文档中查找关于 Web 服务的资料,在这里搜索 Web,可以找到相关文章:http://www.realinfo.com.cn/html/technology/technical/342.html,根据其中的描述,软件的 Web 功能主要用于数据展示,可以实时查看所需的信息。
帮助文档中提到 Web 发布程序是根目录下的 WebSvr.exe,双击运行可以看到如下界面
Web 发布有两种方式,一是使用 IIS,二是用软件自带的 WEB 服务器,自带的 Web 服务默认运行在 80 端口,在浏览器中可以正常访问,默认的 Web 目录是程序安装路径下的 DemoApp\DemoFunction(1024_768)\,由于软件需要进行注册,暂时无法新建工程。正常使用过程中,Web 目录可以自行设置。
用浏览器访问的时候抓包,正常的访问请求如下
1 | GET /StartLog.Txt HTTP/1.1 |
服务器响应
1 | HTTP/1.0 200 OK |
访问记录在服务端可以看到。
由于程序代码较多,并且是标准的 Web 服务,所以考虑先对其进行 fuzz,这里用到的工具是 boofuzz,关于 boofuzz 的使用方法网上可以找到很多教程,这里就不赘述了,编写 fuzz 脚本如下
1 | from boofuzz import * |
boofuzz 允许设置监视器,可以在每次 fuzz 之后检查程序是否运行正常,由于目标程序比较简单,没有编写监视器,手动来检测也可以。
运行之后 Web 服务立刻就会崩溃,信息如下
错误代码 c0000409 属于内存访问错误,这里可以确定程序中确实存在一些内存越界问题。
经过测试发现能够稳定触发漏洞的 POC 如下
1 | GET /<payload> HTTP/1.1 |
在 payload 处插入超长的字符串可以导致程序崩溃。
接下来要判断崩溃的原因,经尝试 OD 不能正确的捕获到异常信息,需要使用 IDA 调试。
IDA 运行程序之后发送 payload,提示异常信息如下
程序访问了非法地址 0x00190000,中断位置:
edx 就是非法地址。由于中断位于 kernel32.dll 中,猜测是某个系统 API 函数,想要定位用户程序中哪里调用了此函数,可以进行栈回溯,首先找到 EBP 的值为 0018EDE0,查看返回地址 0018EDE4 内容为
1 | 0018EDE4 0040297E sub_4028A0:loc_40297E |
这样就找到了 Web 服务器中可能存在问题的代码段,在 IDA 中转到地址 0040297E,发现这里的代码没有被正常识别为函数,在地址 004028A0 按 P 键创建函数,F5 就可以看到反编译代码
1 | void __stdcall vuln(int a1, _DWORD *a2) |
显然其中引用了多次 lstrcpyA 函数进行字符串拷贝,在拷贝的时候不考虑源字符串长度,当传入超长的字符串之后将导致溢出。不过在静态分析下无法定位到谁使用了这个函数,所以可通过调试看看执行到这里时内存布局情况。
IDA 启动调试,在此函数下断点,当执行到崩溃位置时 lstrcpyA 函数参数如下
源字符串就是我们传入的 payload,目的内存位于栈中,地址是 0018F3C0,进入拷贝函数之后由于源字符串超长,缓冲区指针将不断递增,最终到达 0x00190000 的不可写内存,导致程序崩溃。
值得注意的是当提示程序停止工作的时候,错误模块是 comctl32.dll,它是应用程序共用 GUI 库,当发送一个访问请求之后,程序会在窗口中将访问的 URI 显示出来,在显示的过程中缺少对 URI 长度限制,可能导致在绘制 GUI 的时候发生错误。
POC
1 | import requests |
-
这个漏洞比较简单,目前来看只能造成拒绝服务,暂时不清楚能否对控制系统产生影响,另外在主程序存在数据传输端口 1998,有可能也存在一些问题。
我们使用了简单的 fuzz 技巧来发现这个漏洞,fuzz 的核心就是定义数据格式适配目标程序,如果大家有更好的模糊测试思路欢迎来信讨论。
- 本文作者: CataLpa
- 本文链接: https://wzt.ac.cn/2020/12/04/realinfo/
-
版权声明:
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。