科研记录0x01

两个CVE的漏洞分析

根据课题研究方向搜到的2个CVE,师叔让写一个漏洞分析文档,在这留档记录下。

CVE-2011-4860

相关设备:施耐德PLC工控设备

设备型号:NOE71101

漏洞描述:NOE 771设备(又名Quantum 140NOE771* 模块)上的施耐德电气Quantum 以太网模块中的ComputePassword 功能通过对MAC 地址执行计算生成fwupgrade 帐户的密码,这使得远程攻击者更容易获得访问权限通过(1) ARP 请求消息或(2) 邻居请求消息。”

固件下载地址:https://github.com/ameng929/NOE77101_Firmware

漏洞分析

在目录 \FLASH0\wwwroot\conf\exec 下,NOE77101.bin 就是要分析的固件。

使用binwalk提取过后,可以看到固件是Vxworks操作系统,PowerPC架构大端序

img

最后一行信息能看到符号表的地址是0x301E74,在后边恢复符号表时会用到。

image-20230401211315697

使用IDA32打开385文件,选择PowerPC big endian,之后会让填写ROM的起始地址,这里得到是0x10000(好像也是固件常用基址)。在ROM start address和Loading address 处填入后,一路默认。

image-20230401213102913

进入到主界面后,导入符号表重建脚本重建符号表,上边已经得到了符号表起始地址0x301E74,再通过HxD找到符号表终止地址0x3293B4,idc脚本见rebuild.idc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* rebuild.idc */
/* Ruben Santamarta - IOActive */
/* Rebuild VxWorks Symbol Table */

#include <idc.idc>

static main()
{
auto load_addr;
auto ea;
auto offset;
auto sName;
auto eaStart;
auto eaEnd;

// You'll need to adjust these values
load_addr = 0x10000; /* 加载地址 */
eaStart = 0x301E74 + load_addr; /* 符号表起始地 */
eaEnd = 0x3293b4 + load_addr; /* 符号表结束地址 */

SetStatus(IDA_STATUS_WORK);
ea = eaStart;

while( ea < eaEnd) {
MakeDword( ea );
offset = 0;
if ( Dword( ea ) == 0x900 || Dword( ea ) == 0x500)
{
offset = 8;
}
else if( Dword( ea ) == 0x90000 || Dword( ea ) == 0x50000 )
{
offset = 0xc;
}
if( offset )
{
MakeStr( Dword( ea - offset ), BADADDR);
sName = GetString( Dword( ea - offset ), -1, ASCSTR_C ) ;
if ( sName )
{
if( Dword( ea ) == 0x500 || Dword( ea ) == 0x50000)
{
if ( GetFunctionName( Dword( ea - offset + 4) ) == "" )
{
MakeCode( Dword( ea - offset + 4) );
MakeFunction( Dword( ea - offset + 4), BADADDR );
}
}
MakeName( Dword( ea - offset + 4 ), sName );
}
}
ea = ea + 4;
}

SetStatus(IDA_STATUS_READY);
}

修复好后可以在函数栏看到修复后的函数名称,这个固件的漏洞发生在 ComputePassword 函数中,这个函数在 usrAppInit 函数内被调用。首先进入 usrAppInit 函数,使用IDA反汇编后,得到的伪代码如下:

img

v12 通过调用 GetEthMAC 函数获得设备的 mac 地址,然后下边的 sprintf 函数把 mac 地址赋值给了v13,接着做为 ComputePassword 函数的参数。这里用IDA反汇编的不是特别好,在博客上看到别人用 Ghidra 反汇编得到的结果要比IDA直观些,于是在 ghidra 上进行反汇编,同样要重建符号表,Github上有别人写好的 ghidra 脚本,根据 readme 将脚本导入 ghidra ,运行脚本(vxhunter_firmware_init.py)进行自动修复和分析,反编译后 usrAppInit 的伪代码如下所示:

image-20230401213235219

v12 对应 local_50(mac地址),v13 对应 acStack72 ,从 ghidra 反汇编的结果中 sprintf 函数的参数可以看到,mac 地址是通过数组的形式分段存放的。

进入到 ComputePassword 函数中,反编译查看源码如下:

img

同样在 ghidra 中看一下:

img

ComputePassword 函数首先用 strcpy 给 param_2 赋了一个值,这个值可以看到为 0x :

img

然后用 strcat 函数,把 param_2 和 *(param_1+3) 拼接在一起。param_1 对应 acStack72(mac),接着,函数对包含 mac 的 param_2 经过一些运算后,最后将结果保存在 param_2(也就是 acStack56 )中并返回。

紧接着,usrAppInit 函数调用 loginDefaultEncrypt 函数,参数为 acStack56 和 &DAT_00342044 ,查看该函数:

img

这个函数看的也不是特别懂,但是大致功能是对 acStack56(通过 ComputePassword 计算得到的)做一些操作,然后保存到 &DAT_00342044 这个地方。紧接着在 loginUserAdd 函数中,将 &DAT_00342044 作为账户 s_fwupgrade 的密码。

整个过程概括下来就是,ComputePassword 函数接收mac地址作为参数输入,计算得到账户 s_fwupgrade 的密码,函数内部的计算过程也不算复杂,从而导致了漏洞的产生。

参考链接:

https://blog.csdn.net/qq_35029061/article/details/125884395

https://blog.csdn.net/qq_35029061/article/details/125884434

CVE-2017-8416

相关设备:摄像头

设备型号:D-Link DCS-1100/1130

漏洞描述:设备在UDP端口5978上运行一个自定义守护进程,称为 “dldps2121”,监听设置为255.255.255.255的报文或广播报文。这个守护进程处理自定义 Dlink 基于UDP的协议,允许 Dlink 移动应用程序和桌面应用程序发现本地网络上的 Dlink 设备。这主要是有用的设置设备使用这些应用程序,并提供用户友好性方面。二进制以 “main” 功能处理从任何设备发送的UDP数据包。函数中的一条路径遍历处理数据包的代码块,该代码块执行无界复制操作,允许溢出缓冲区。

Dlink创建的自定义协议遵循以下模式:

1
Packetlen, Type of packet; M=MAC address of device or broadcast; D=Device Type;C=base64 encoded command string;test=1111

dldps2121程序中,从地址 0x0000DBF8 开始的地址函数处理整个UDP数据包,并使用地址 0x0000DC88 的 strcpy 函数执行不安全拷贝。

固件下载地址:http://legacyfiles.us.dlink.com/DCS-1130/REVA/FIRMWARE/DCS-1130_REVA_FIRMWARE_1.08.8707.ZIP

漏洞分析

使用 binwalk 提取固件文件系统,固件为 cramfs 文件系统,32位 arm 架构,dldps2121 程序位于 /cramfs-root-0 目录下,导入到IDA32进行分析。

根据漏洞信息的提示,程序在DBF8函数处理UDP数据包,查看DBF8函数的反编译后的伪代码:

img

a1 参数应该是接收到的UDP数据包数据,函数首先将数据赋值给 v10 ,然后通过strstr函数找到字符串“D=”在UDP数据包中第一次出现的位置并赋值给 v5,然后将 “D=” 后边的内容通过不安全的strcpy函数复制到 v6 处,这里由于 strcpy 函数本身的不安全性,导致存在缓冲区溢出漏洞。根据UDP数据包的格式:

1
Packetlen, Type of packet; M=MAC address of device or broadcast; D=Device Type;C=base64 encoded command string;test=1111

“D=” 前边是包的类型和设备的 MAC 地址,所以,只要我们获得了设备的 MAC 地址,我们就能利用 strcpy 函数存在的缓冲区溢出漏洞,对该设备发送构造好的UDP数据包执行攻击。

采用文档里的说法:此处的 strcpy 函数会导致在1060个字符之后溢出堆栈指针,从而允许控制PC寄存器并导致代码执行。任何进程都可以发起相同形式的通信,包括手机或桌面上的攻击者进程,这允许设备上的第三方应用程序通过发送一个带有自定义 base64 编码的UDP数据包在设备上执行命令,而无需任何身份验证。

漏洞是在通过对移动应用程序 dink lite 进行渗透测试,并逆向设备上存在的 “dldps2121” 二进制文件发现的。