Vulnerability Title: Command Injection Vulnerability in DHCP Service of D-Link DIR-860LB1_v203b03

Discovered by: tzh00203

Contact Information: [email protected]

Affected Version: DIR-860LB1 firmware version v203b03 (and possibly earlier versions)

Component: udhcpd DHCP server


1. Vulnerability Overview

Command Injection Vulnerability has been discovered in the DHCP daemon service of D-Link DIR-860LB1_v203b03. The vulnerability exists in the lease renewal processing logic where the DHCP hostname parameter is directly concatenated into a system command without proper sanitization. When a DHCP client renews an existing lease with a malicious hostname, arbitrary commands can be executed with root privileges.


2. Detailed Description

The vulnerability occurs in the DHCP lease renewal processing code when handling DHCP REQUEST messages for existing IP addresses. When a client sends a DHCP request to renew a previously assigned IP, the function does not properly sanitize the provided hostname parameter (DHCP Option 12), allowing command injection sequences to be executed as shell commands.

Specifically, in the vulnerable code:

744bcfd117c62a9e1aed042815de7743.png

When processing a DHCP lease renewal, the server takes the client-provided hostname and directly concatenates it into a command string that is passed to the system() function. This allows attackers to inject arbitrary commands by including shell metacharacters (such as semicolons, ampersands, or pipe symbols) in the hostname field.

The affected DHCP daemon (udhcpd) runs with root privileges as part of the BusyBox networking utilities. This enables successful attackers to execute any command with the highest level of system access, potentially reading sensitive files like /etc/passwd and /etc/shadow, modifying system configurations, installing backdoors, or completely taking over the router.



Vulnerable Code:

       {
            v21 = (_BYTE *)get_option(v48, 53);
            if ( v21 )
            {
              static_lease_by_chaddr = find_static_lease_by_chaddr(v50);
              lease_by_chaddr = static_lease_by_chaddr;
              if ( !static_lease_by_chaddr )
                lease_by_chaddr = find_lease_by_chaddr(v50);
              sprintf(v44, "%02x:%02x:%02x:%02x:%02x:%02x", v50[0], v50[1], v50[2], v50[3], v50[4], v50[5]);
              switch ( *v21 )
              {
                case 1:
                  syslog(229, "DHCP: Server receive DISCOVER from %s.", v44);
                  sendOffer(v48);
                  continue;
                case 3:
                  v30 = (int *)get_option(v48, 50);
                  v51 = get_option(v48, 54);
                  v31 = get_option(v48, 12);
                  v32 = v51;
                  v33 = (const char *)v31;
                  if ( v31 )
                  {
                    memcpy(v46, v31, *(unsigned __int8 *)(v31 - 1));
                    v46[*((unsigned __int8 *)v33 - 1)] = 0;
                    v32 = v51;
                    v33 = v46;
                  }
                  v51 = v32;
                  syslog(229, "DHCP: Server receive REQUEST from %s.", v44);
                  if ( v30 )
                    v41 = *v30;
                  if ( v51 )
                    v42 = *(_DWORD *)v51;
                  if ( lease_by_chaddr )
                  {
                    if ( v51 )
                    {
                      if ( server_config != v42 )
                        goto LABEL_58;
                      v35 = *(_DWORD *)(lease_by_chaddr + 16);
                      if ( !v30 )
                        goto LABEL_59;
                      v34 = *(_DWORD *)(lease_by_chaddr + 16);
                      if ( v35 != v41 )
                        goto LABEL_59;
LABEL_71:
                      sendACK(v48, v34);
                      v35 = *(_DWORD *)(lease_by_chaddr + 16);
                      goto LABEL_59;
                    }
                    v34 = *(_DWORD *)(lease_by_chaddr + 16);
                    if ( v30 )
                    {
                      if ( v34 == v41 )
                      {
                        sendACK(v48, v34);
LABEL_58:
                        v35 = *(_DWORD *)(lease_by_chaddr + 16);
                        goto LABEL_59;
                      }
                    }
                    else if ( v34 == v49 )
                    {
                      goto LABEL_71;
                    }
                    sendNAK(v48);
                    v35 = *(_DWORD *)(lease_by_chaddr + 16);
LABEL_59:
                    v36 = (const char *)inet_ntoa(v35, v34);
                    if ( v33 )
                      sprintf(v47, "usockc /var/mydlinkeventd_usock NEW_DEVICE,%s,%s,%s\\n", v44, v36, v33);
                    else
                      sprintf(v47, "usockc /var/mydlinkeventd_usock NEW_DEVICE,%s,%s,unkown hostname\\n", v44, v36);
                    system(v47);
                  }

The vulnerability is in the DHCP REQUEST message handler.