导语:海特实验室小伙伴针对2020年2月4日外国研究人员发表了一篇文章《基于Xiongmai的DVR,NVR和IP摄像机的固件后门漏洞》中涉及的漏洞细节进行分析和分享。
前言
2020年2月4日,有外国研究人员发表了一篇文章:基于Xiongmai的DVR,NVR和IP摄像机的固件后门漏洞。最新的固件版本虽然默认禁用了Telnet访问和调试端口(9527/tcp),但打开了9530/tcp端口,攻击者可以利用这个端口发送一个特殊的命令来启动Telnet守护进程,并使用固定密码访问shell。参考文章见文末链接一。
其实这个漏洞疑似是一个海思摄像头组件的历史漏洞,关于详细的漏洞分析可以查看文末参考链接二。
安恒信息「物联网安全监测平台」已集成相关漏洞探测规则。
漏洞测试环境
设备:XMJP IPC 摄像头
型号:XM530
官网固件下载:https://download.xm030.cn/d/MDAwMDAwNjM=
设备图片:
从官网获取固件的下载链接,下载固件文件到本地,使用 binwalk 进行解压:
1. binwalk -Me XMJP_IPC_XM510_RA50X10_WIFIXM712.bin
根据漏洞信息,找到 OpenTelnet:OpenOnce 字符串所在的位置:
1. $ grep -rnl "OpenTelnet:OpenOnce" *
2. grep: etc/localtime: No such file or directory
3. grep: etc/resolv.conf: No such file or directory
4. grep: lib/firmware: No such file or directory
5. grep: mnt/web: No such file or directory
6. usr/bin/dvrHelper
7. usr/bin/netinit
8. grep: usr/bin/ProductDefinition: No such file or directory
9. grep: usr/share/music/customAlarmVoice.pcm: No such file or directory
在 usr/bin 目录下找到 dvrHelper 这个可执行程序,使用 file 命令查看文件信息:
1. $ file usr/bin/dvrHelper
2. usr/bin/dvrHelper: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, stripped
将usr/bin/dvrHelper 这个二进制程序,使用 IDA 进行加载:
搜索 OpenTelnet:OpenOnce 字符串的位置,双击跟进:
在这个函数流程中,可以看到经过了几个判断之后,会执行 system("telnetd") 命令,从而开启一个 telnetd 端口,我们的目的就是需要让程序执行到这个流程分支。
首先程序会根据 socket 套接字中 recv 函数接收的内容,判断前几个字节内容是否为 OpenTelnet:OpenOnce 开头:
1. strncmp(v32, "OpenTelnet:OpenOnce", 0x13u)
如果是的话在下面的 else 判断中就会通过 get_random_code 函数中的 rand 函数随机返回 8 位数字:
· get_random_code 函数
接着再次判断通过 recv 函数接收的内容是否为 randNum 字符串开头,是的话就跳转到 else 分支:
这里的 get_key 函数的作用是返回一个 key 字符串,这里的逻辑为判断 /mnt/custom/TelnetOEMPasswd 文件是否存在,存在的话返回文件的内容(也就是密钥),不存在就返回 2wj9fsa2 字符串。
接着在 126 行,将上一步程序返回的 randNum 随机数字和 key 进行拼接,得到 challengeStr 字符串传入到 encrypt 函数中进行加密,这里就 key 就相当于一个固化在程序中的 PSK 预认证后门密钥。
跟进到 encrypt 函数中,函数中的逻辑较为复杂,根据参考文章 2 中代码的分析可知这里是一个 3DES 加密算法。
· 或者这里使用 Ghidra 工具的 FindCrypt 脚本,可以发现几个目标地址都是 DES 加密所需的 sbox 参数等等。
逆向加密算法,根据参考文章 2 中的代码写出具体的解密算法之后,将这个加密结果拼接在 randNum:字符串之后:
经过程序比较就会输出 “verify:OK” 字符串,这里就通过了这一步的判读。
接着会再次比较接收到的字符串开头是否为 CMD:,是的话就会进入下面的 if 判断:
这里的解密算法对应的上面的加密算法,判断解密后的字符串是否为 “Telnet:OpenOnce” 字符串,那么这里只需要将 “Telnet:OpenOnce” 字符串经过相同的加密算法加密即可,就可以通过 strncmp(&key, "Telnet:OpenOnce", 0xFu) 这个判断。从而执行 system("telnetd") 函数,开启后门。
当我们向 9530 端口发送一个 OpenTelnet:OpenOnce 字符串时,端口会回应一个 randNum,如下图:
· 注意这里需要使用 socket 编程来进行实现:
1. ...
2. connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr);
3. recv(sockfd, netbuf, BUFSIZE - 1, 0);
4. ...
接着我们需要将拼接得到的 challengeStr ,也就是 175727002wj9fsa2 进行加密函数的加密。加密完成之后传送 randNum:加密后的内容 到远程 9530 端口服务。
这里的远程服务就会返回 “verify:OK” 字符串,如下图:
之后将 “Telnet:OpenOnce” 字符串进行同样加密算法的加密,将这个加密的内容拼接到 “CMD:” 字符串后面得到 CMD:加密后的内容,并将其发送到远程服务,设备就会执行 system("telnetd") 语句,并返回 “Open:OK” 字符串,至此 telnet 服务就被打开了。
在成功打开了 telnetd 端口之后,需要使用 root 用户的密码进行登陆。在解压后的固件文件系统的 etc 目录下,查看 passwd 文件的内容:
1. $ cat passwd
2. root:$1$RYIwEiRA$d5iRRVQ5ZeRTrJwGjRy.B0:0:0:root:/:/bin/sh
因为密码采用 des 加密,猜测密码位数较短,可以使用 hackcat 进行暴力破解:
1. hashcat64.bin -a3 -m1500 $1$RYIwEiRA$d5iRRVQ5ZeRTrJwGjRy.B0 -1 ?l?d ?1?1?1?1?1?1
最后可以得到密码为:xmhdipc。雄迈摄像头的几种默认密码的组合已经有人爆破出了一个列表,见下文的图片。
· Full disclosure: 0day vulnerability (backdoor) in firmware for Xiaongmai-based DVRs, NVRs and IP
作者:H4lo@海特实验室
如若转载,请注明原文地址