| Title | D-Link DIR-868L Hardware rev B1, firmware 2.01b05 (web interface / HNAP, component /htdocs/cgibin) Command Injection |
|---|
| Description | A pre-authentication OS command injection exists in the HNAP web interface of
the D-Link DIR-868L rev B1 router, firmware 2.01b05 (component
/htdocs/cgibin, MD5 64a37f67c57dc25b3678dbcc8554c10e, ARM).
The HNAP CGI handler authorizes requests by checking whether the SOAPACTION
HTTP header *contains* the string "http://purenetworks.com/HNAP1/GetDeviceSettings"
using an unanchored strstr(). Because the check is a substring match, any
request whose SOAPACTION merely contains that prefix bypasses the whole
authentication block (the HNAP-AUTH HMAC verification is never called). The
handler then takes the "action name" as the text following the last '/' of
the same header and passes it to system() without any filtering:
sprintf(s, "sh /var/run/%s.sh > /dev/console", action); /* 0x1AA34 */
system(s); /* 0x1AA40 */
Shell metacharacters in the action name therefore execute arbitrary commands
as root. The injected command inherits the CGI's stdout, so its output is
returned in the HTTP response body when prefixed with a CGI header
("echo Content-Type: text/plain; echo;"), giving a full read-back channel.
Proof of concept (GET, no credentials):
GET /HNAP1/ HTTP/1.1
Host: <target>
SOAPACTION: "http://purenetworks.com/HNAP1/GetDeviceSettings/; sleep 10;"
The server sleeps exactly 10 seconds (measured 10.02 s; a non-spoofed
unknown action returns 401, proving the auth gate is otherwise active).
With output retrieval:
SOAPACTION: "http://purenetworks.com/HNAP1/GetDeviceSettings/; echo Content-Type: text/plain; echo; cat /proc/self/status;"
the response body contains "Uid: 0 0 0 0" (root).
Payload constraints (documented from testing): the payload must follow the
last '/' of the header, so it cannot contain '/' itself (runtime-construct
it with e.g. s=`echo $PATH | busybox cut -c1`; cat ${s}proc${s}self${s}status);
the character '(' in the header value is rejected by the web server.
Verification chain (all by the reporter):
1. Static analysis of the ARM binary (IDA) - substring auth gate at
sub_1A57C+0xC8, unfiltered action into system() at +0x4C4.
2. Unicorn emulation of the real firmware code - HMAC verification function
never called; system() receives the attacker string verbatim.
3. qemu-arm user-mode execution - strace shows
execve("/bin/sh", ["sh","-c","sh /var/run/; touch ..."]) and the injected
command runs as uid=0; timing oracle exact (10.018 s).
4. FirmAE full-system emulation over HTTP - dose-dependent sleep timing
(10.02 s / 5.02 s), 401 control case, command output returned, root
confirmed via /proc/self/status. |
|---|
| Source | ⚠️ https://github.com/Walnut1337/Command-Injection-DIR-868L/blob/main/poc/poc_hnap_injection.py |
|---|
| User | Walnut1337 (UID 100856) |
|---|
| Submission | 09/28/2026 09:43 (1 month ago) |
|---|
| Moderation | 10/14/2026 15:00 (16 days later) |
|---|
| Status | Duplicate |
|---|
| VulDB entry | 419825 [D-Link DIR-868L 2.01b05 HNAP CGI /htdocs/cgibin system SOAPACTION os command injection] |
|---|
| Points | 0 |
|---|