【工控安全】从固件逆向看工控安全
2022-10-1 00:0:53 Author: 白帽子(查看原文) 阅读量:28 收藏

工控漏洞挖掘方法有很多种,常见的方法包括:基于工控协议的模糊测试漏洞挖掘方法、基于固件逆向分析的漏洞挖掘方法、基于工控软件ActiveX控件的漏洞挖掘方法、基于VxWorks操作系统的漏洞挖掘方法等。

笔者近期正在接触一些逆向的基础知识,为了达到学以致用的目的,本文作者参考了威努特工控安全的《工控漏洞挖掘方法之固件逆向分析》及各位知名大佬的博客,以施耐德NOE 771固件为例进行逆向分析,并总结了一些固件逆向的基础知识及工控安全学习指南,希望能给工控安全入门者提供帮助,也希望能够得到大佬们宝贵的建议。

2.1 工控安全研究方向划分

2.2 工控安全学习阶段划分

3.1 固件是什么?

简单来说,固件是软件的一种,也是一种程序。

固件(Firmware)就是写入EPROM(可擦写可编程只读存储器)或EEPROM(电可擦可编程只读存储器)中的程序(来自:百度百科)。

固件是指设备内部保存的设备“驱动程序”,通过固件,操作系统才能按照标准的设备驱动实现特定机器的运行动作,比如光驱、刻录机等都有内部固件(来自:百度百科)。

固件是存储在可由CPU直接或间接读取指令/数据并可运行的FLASH/ROM芯片里的二进制数据集合,这些指令/数据集合是根据CPU内核架构及型号,将高级编程语言(如C、C++等)由对应的编译器、链接器、装载器生成并通过对应的烧写器将指令/数据集合烧写到对应设备里的存储芯片中。固件之所以和软件程序区分开来,是为了强调固件侧重于智能设备、嵌入式设备、工控设备里运行的程序,而非PC电脑、服务器、手机内部的程序(只是侧重并非绝对,很多场合手机里的程序也被称为固件)。

3.2 固件分析是什么?

固件分析,一种深入硬件底层(芯片级)的技术破解方法,经常被用于系统攻防对抗、硬件破解、逆向分析等实际工作中,相对其它技术破解攻击方法,科学有效的固件分析因其扒开了破解攻击对象的“外衣”,直接深入“骨髓”对其逻辑代码、数据存储、数据类别、数据属性等全方面分析,可找出其它攻击方法无法找出的严重漏洞,可对破解攻击对象形成“致命级杀伤力”。

3.3 固件运行机制

不同种类的设备,其内部固件运行的细节都不一样,但其运行机制大体类似,一般比较常见的运行机制是:上电boot->uboot->cos->applet,针对不带操作系统的运行机制一般是:上电-> boot-> applet或上电-> applet

3.4 固件的获取

1.设备官网下载;

2.通过组态软件、工程程序设计软件,更新固件处、截取;

3.拆卸设备;通常待值得分析的固件,其设备都会拥有USB,如果没有可以撬芯片!

3.5 固件分析工具

  • binwalk
  • Ghrida
  • ubi_reader
  • yaffshiv
  • jefferson
  • Ida_pro
  • jd-gui
  • LuacGUI

3.6 固件分析思路

1、解压固件,获取文件系统;

2、查看系统中相关组件、服务配置及敏感文件(/etc/passwd、/usr/bin、/usr/sbin等);

3、逆向分析固件文件,查看是否存在版本漏洞;

4、查找固件应用目录;

5、分析固件应用服务等默认配置安全问题;

6、对固件应用进行反编译或者解密;

7、逆向分析固件应用安全问题;

8、结合实际设备进行综合性安全测试;

固件下载:链接: https://pan.baidu.com/s/1nODpSNnAKCPYTtUoolvaMQ  密码: cip3

4.1 固件的识别和解压

下载到固件之后,unzip noe77101_OS.bin_.zip解压固件,得到FLASH0文件夹和一个commandList.lst文件,FLASH0的文件目录如:

➜  noe77101_OS.bin_ tree FLASH0/FLASH0/├── bin│   └── $TMP_EMPTY_DIR├── ftp│   └── $TMP_EMPTY_DIR├── fw│   ├── crashlog.txt│   ├── fw.ini│   └── hw.ini├── gdt│   └── $TMP_EMPTY_DIR├── rdt│   └── password.rde├── webloader.ini└── wwwroot    ├── SchneiderTFE.zip    ├── cgi-bin    │   └── $TMP_EMPTY_DIR    ├── classes    │   ├── RDE.jar    │   ├── SAComm.jar    │   ├── SysDiag.jar    │   ├── XMLParser.jar    │   ├── jvmver.jar    │   ├── webcfg.jar    │   ├── webdiag.jar    │   └── xmlrpc-1.1.jar    ├── conf    │   ├── Gcnftcop.sys    │   ├── bootp    │   │   └── $TMP_EMPTY_DIR    │   ├── dhcp    │   │   └── $TMP_EMPTY_DIR    │   ├── diag    │   │   └── $TMP_EMPTY_DIR    │   ├── exec    │   │   ├── NOE77101.bin    │   │   ├── _NOE77101.bin.extracted    │   │   │   ├── 1.txt    │   │   │   ├── 2.txt    │   │   │   ├── 217    │   │   │   ├── 217.id0    │   │   │   ├── 217.id1    │   │   │   ├── 217.nam    │   │   │   ├── 217.til    │   │   │   ├── 217.zlib    │   │   │   └── 3.txt    │   │   └── kerVer    │   ├── fw    │   │   └── fw.ini    │   ├── glbdata    │   │   └── glbdata.ini    │   ├── ioscanner    │   │   └── $TMP_EMPTY_DIR    │   └── snmp    │       └── snmp.ini    ├── html    │   ├── config.js    │   ├── english    │   │   ├── control    │   │   │   ├── index.htm    │   │   │   └── menu.htm    │   │   ├── diagnostic    │   │   │   ├── index.htm    │   │   │   └── menu.htm    │   │   ├── documentation    │   │   │   ├── index.htm    │   │   │   └── menu.htm    │   │   ├── header.htm    │   │   ├── home    │   │   │   ├── home.htm    │   │   │   ├── index.htm    │   │   │   └── menu.htm    │   │   ├── index.htm    │   │   ├── maintenance    │   │   │   ├── index.htm    │   │   │   └── menu.htm    │   │   ├── monitoring    │   │   │   ├── index.htm    │   │   │   └── menu.htm    │   │   └── setup    │   │       ├── index.htm    │   │       └── menu.htm    │   ├── images    │   │   ├── Telemecanique.gif    │   │   ├── TelemecaniquePocketPC.gif    │   │   └── noe77101.jpg    │   └── lib    │       ├── css    │       │   ├── header.css    │       │   ├── main.css    │       │   └── menu.css    │       ├── images    │       │   ├── left.gif    │       │   ├── moins.gif    │       │   ├── plus.gif    │       │   └── right.gif    │       └── js    │           ├── header.js    │           ├── home.js    │           ├── index.js    │           ├── menu.js    │           └── tools.js    ├── images    │   ├── eight_io.gif    │   ├── empty.gif    │   ├── hiendcpu.gif    │   ├── logo.gif    │   ├── miniplc.gif    │   └── module.gif    ├── index.htm    ├── lib    │   ├── home.js    │   ├── main.css    │   └── main.js    ├── secure    │   ├── embedded    │   │   ├── bandwidth.htm    │   │   ├── chkdsk.htm    │   │   ├── classes    │   │   │   └── $TMP_EMPTY_DIR    │   │   ├── dhcp_node_config.htm    │   │   ├── format_flash.htm    │   │   ├── french    │   │   │   └── $TMP_EMPTY_DIR    │   │   ├── ftp_passwd_config.htm    │   │   ├── german    │   │   │   └── $TMP_EMPTY_DIR    │   │   ├── globaldata.htm    │   │   ├── http_passwd_config.htm    │   │   ├── images    │   │   │   └── $TMP_EMPTY_DIR    │   │   ├── ioscanning.htm    │   │   ├── messaging.htm    │   │   ├── reboot.htm    │   │   ├── set_readonly.htm    │   │   ├── smtpconf.htm    │   │   ├── smtpdiag.htm    │   │   ├── spanish    │   │   │   └── $TMP_EMPTY_DIR    │   │   ├── support.htm    │   │   └── web_page_Ver.ini    │   ├── system    │   │   ├── ctrlstat.htm    │   │   ├── ethernet.htm    │   │   ├── plccfg.htm    │   │   ├── rde.htm    │   │   └── riostat.htm    │   └── user    │       └── $TMP_EMPTY_DIR    └── unsecure        └── user            └── $TMP_EMPTY_DIR
45 directories, 107 files

flash0/wwwroot/conf/exec/目录下存在一个NOE77101.bin文件,该文件就是我们需要分析的目标文件。

首先使用binwalk命令对.bin文件进行分析,binwalk NOE77101.bin,结果如图所示:

发现为zlib类型。使用binwalk提取NOE77101.bin中的文件,binwalk -e NOE77101.bin,得到217和217.zlib两个文件。使用binwalk分析217,binwalk 217,分析结果如图,可以看到此固件使用vxworks内核,binwalk还在固件中识别出了符号表。

4.2 固件分析

首先,确定固件的cpu架构、大小端格式。

使用binwalk的-A参数分析217文件,binwalk -A 217

分析得知,固件使用PowerPC架构,大端格式。

其次,还要确定固件的加载地址,vxworks固件的常见加载地址是0x10000,最好还是要验证一下。

使用命令:strings 217 搜索固件中的字符串:

确定字符串表中的最后一个字符串应该是APP_STATION_MODBUS

在010 Editor中搜索字符串APP_STATION_MODBUS,可知字符串表中的最后一个字符串的地址为0x298BD8。

字符串表中的最后一个字符串在符号表中第一个被引用,因此需要定位符号表的第一行,找到该字符串在内存中的地址。前文中已经使用binwalk发现符号表的位置,为0x31EED4。但是这个值不一定是准确的,还需要进一步验证。在010 Editor中定位0x31EED4位置附近,发现符号表真正的起始位置是0x31EEC4。

确定了APP_STATION_MODBUS字符串在固件中的位置和在内存中的位置,就可以计算得到固件的加载地址了,确实是0x10000。

4.3 ida分析固件

处理器选择PowerPC big endian(PPC)

固件加载地址填写0x10000

ida打开后并没有识别到函数,Windows下的ida能够识别到少量的函数。

此处要借助Python脚本进行函数修复。代码如下:

from idaapi import *from idc import *
loadaddress = 0x10000eaStart = 0x31eec4 + loadaddresseaEnd = 0x348114 + loadaddress
ea = eaStarteaEnd = eaEndwhile ea < eaEnd: create_strlit(Dword(ea), BADADDR) sName = get_strlit_contents(Dword(ea)) print sName if sName: eaFunc = Dword(ea + 4) MakeName(eaFunc, sName) MakeCode(eaFunc) MakeFunction(eaFunc, BADADDR) ea = ea + 16

关于符号表的结束地址,可以在010 edit中按照符号表规律往下寻找,最终确定为:0x348114

运行Python脚本函数修复。

4.4 后门漏洞分析

查找后门漏洞的一个入手点就是寻找与用户相关的函数的调用情况,注意到函数loginUserAdd

查看此函数的交叉引用情况,发现有三个函数对它进行了调用,分别是usrSecurity、FTP_USER_ADD和usrAppInit

分别查看以上三个函数,在usrAppInit中发现疑似添加登录用户的操作。在PowerPC中,lis(立即数载入并左移)和addi(立即数加法)的组合是最常见的赋值操作,ida pro的注释中给出了经过赋值之后的结果。

以第一次调用为例,实际上是执行了loginUserAdd(0x22DB7C,0x22DB84),这两个内存地址在固件中的实际地址应是再减去固件的加载地址。

在010 Editor中定位固件的0x21DB7C(0x22DB7C-0x10000),发现此处的字符串出多次出现“user”字样,由此更加验证了前面的操作是添加多个后门账号。

基于工控设备固件分析的漏洞挖掘是比较常用的方式之一,至今在工业控制领域存在着大量的PLC、SCADA、DCS等设备,且主流设备大多来自国外生产制造,这些系统都采用固件升级的方式进行更新。

而固件逆向分析是在不对嵌入式系统进行实际运行的情况下,通过对固件文件进行逆向解析,分析固件中各代码模块的调用关系及代码内容,从而发现嵌入式系统中可能存在的漏洞及后门的一种技术手段。分析过程中,将会涉及到固件的识别和解压、固件的静态分析等技术。

本文复现的漏洞为:CVE-2011-4859,虽然漏洞比较古老,但对于逆向学习入门者和挖掘工控漏洞而言具有普遍的通用性和典型性,希望感兴趣的小伙伴多加尝试,后续能够挖掘更多有关工控设备的固件漏洞!

https://netsecurity.51cto.com/art/202002/610050.htm

https://www.cnblogs.com/yangmzh3/p/11231423.html

https://paper.seebug.org/613/#21noe-771 《威努特工控安全》


文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMDQwNTE5MA==&mid=2650246376&idx=2&sn=dea2b707571fbb86078f25d4893bb13f&chksm=82ea5741b59dde573117ef762296532db8a9340d59e2f0e98bec453c084855a18802bc7f2688#rd
如有侵权请联系:admin#unsafe.sh