D-Link DIR-3060 授权RCE漏洞(CVE-2021-28144)


# Advisory: D-Link DIR-3060 Authenticated RCE (CVE-2021-28144) MARCH 11, 2021 # **Overview** The [D-Link DIR-3060](https://www.dlink.com/en/products/dir-3060-exo-ac3000-smart-mesh-wi-fi-router) (running firmware versions below v1.11b04) is affected by a post-authentication command injection vulnerability. Anybody with authenticated access to a DIR-3060 would be able to run arbitrary system commands on the device as the system “admin” user, with root privileges. D-Link has released a patched firmware version [v1.11b04 Hotfix 2](https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10208) to address this issue. Affected users are advised to apply the patch. | Affected vendor & product | D-Link DIR-3060 ([www.dlink.com](https://www.dlink.com/)) | | ------------------------- | ------------------------------------------------------------ | | Vulnerable version | v1.11b04 & below | | Fixed version | [v1.11b04 Hotfix 2](https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10208) | | CVE Number | CVE-2021-28144 | | Impact | 8.8 (high) [CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H&version=3.1) | | Credit | T. Shiomitsu, IoT Inspector Research Lab | # **Vulnerable Component** Web management functionality on the DIR-3060 is mainly handled by the `prog.cgi` binary. The `lighttpd` `fastcgi` server configuration is such that requests made to `/HNAP1/` or files with the `.fcgi` extension are handled by `/etc_ro/lighttpd/www/web/HNAP1/prog.fcgi`, which is a symlink to `/bin/prog.cgi`. ``` // ... fastcgi.server = ( ​ "/HNAP1/" => ​ (( ​ "socket" => "/var/prog.fcgi.socket-0", ​ "check-local" => "enable", ​ "bin-path" => "/etc_ro/lighttpd/www/web/HNAP1/prog.fcgi", ​ "idle-timeout" => 10, ​ "min-procs" => 1, ​ "max-procs" => 2 ​ )), ​ ".fcgi" => ​ (( ​ "socket" => "/var/prog.fcgi.socket-0", ​ "check-local" => "enable", ​ "bin-path" => "/etc_ro/lighttpd/www/web/HNAP1/prog.fcgi", ​ "idle-timeout" => 10, ​ "min-procs" => 1, ​ "max-procs" => 2 ​ )), ​ "/common/" => ​ (( ​ "socket" => "/var/myinfo.fcgi.socket-0", ​ "check-local" => "disable", ​ "bin-path" => "/sbin/myinfo.cgi", ​ "idle-timeout" => 10, ​ "min-procs" => 1, ​ "max-procs" => 1 ​ )) ) // ... ``` By default, configuration changes are made by issuing SOAP requests to the web management interface at `http://[ROUTER]/HNAP1/` – these are then all then handled by `prog.cgi`. # **The** **Vulnerability** When a SOAP request is made to the `SetVirtualServerSettings` SOAP endpoint, the function at `00461918` in `prog.cgi` is invoked. This function traverses the SOAP XML request body, stores expected SOAP field values, and takes different paths depending on the values. If a request with a non-null `LocalIPAddress`, `Enabled` set to “true”, an `InternalPort` of “9” and a `ProtocolType` of “UDP” is sent, the function `CheckArpTables` (named by me, based at `0046163c`) is invoked. ``` // ...snip ​ iVar5 = strcmp(Enabled,"true"); ​ **if** ((((iVar5 == 0) && (LocalIPAddress != (**char** *)*0x0*)) && ​ (iVar5 = strcmp(InternalPort,"9"), iVar5 == 0)) && ​ (iVar5 = strcmp(ProtocolType,"UDP"), iVar5 == 0)) { ​ local_4154 = local_4154 + 1; ​ iVar5 = CheckArpTables(LocalIPAddress, InternalPort, ProtocolType, *0xdc*, local_4154); ​ **if** (iVar5 == -1) { ​ local_4160 = *0xb*; ​ **goto** LAB_00462504; ​ } ​ } // ...snip ``` Interestingly, UDP/9 correlates to the canonical [Discard Protocol](https://en.wikipedia.org/wiki/Discard_Protocol), which is the TCP/UDP/IP equivalent of `/dev/null`. The `CheckArpTables()` function attempts to check the device ARP records, by calling the `arp` system command and `grep`’ing the output. However, the user-controlled value passed as the `LocalIPAddress` is written directly into the command line format string with `snprint()`. This string is then passed directly to a function called `FCGI_popen()`, which is a library function imported from `libfcgi.so`. ``` undefined CheckArpTables(**char** *LocalIPAddress, **char** *InternalPort, **char** *ProtocolType, undefined param_4, **int** param_5) { ​ // ...snip... ​ memset(buffer, 0, *0x40*); ​ // ...snip... ​ snprintf(buffer, *0x40*, "arp | grep %s | awk \'{printf $4}\'", LocalIPAddress); ​ iVar1 = FCGI_popen(buffer, "r"); ​ // ...snip... } ``` We can see in `libfcgi.so` that `FCGI_popen()` is essentially only a thin wrapper around the stdio `popen()` library function. Arguments passed to `FCGI_popen()` get passed directly to `popen()`. ``` **int** FCGI_popen(**char** *param_1, **char** *param_2) { FILE *__stream; **int** iVar1; __stream = popen(param_1,param_2); iVar1 = FCGI_OpenFromFILE(__stream); **if** ((__stream != (FILE *)*0x0*) && (iVar1 == 0)) { ​ pclose(__stream); } **return** iVar1; } ``` Since the `LocalIPAddress` value is not sanitized or checked in any way, a crafted command injection string can be passed as the `LocalIPAddress`, which will then be written to the `arp` command format string, and passed (almost) directly to `popen()`. # **Key Takeaways** Abstraction of common library functions with potential security implications is common in embedded device development. Many embedded developers attempt to do this in order to easily “drop-in” common library functions with more secure analogues. However, D-Link, in this case, did not do this. They had abstracted (and used) the `FCGI_popen()` function as a drop-in replacement for `popen()` – presumably in order to ensure that the implementation could be standardized for code cleanliness (and perhaps security) purposes. However, there was no extra checking or sanitization in place in the actual `FCGI_popen()` function. Therefore, there was no particular security benefit to this abstraction. From our perspective (we’re in the business of automating security analysis of embedded device firmware, in case you didn’t know) this is an interesting case. Vendors often use such drop-in replacement functions, imported from external libraries. When running our automated security analyses of ELF executables, we have to take into account which imported functions are used within an ELF, as well as how exposed potentially dangerous library functions are within these functions. This can help us drill down more intentionally into these executables to flag potential security issues. This kind of automation can considerably speed up recognition of potential security issues. # **Disclosure Timeline** *2020-11-16*: Initial contact made to ipsecure@dlinkcorp.com to request keys for encryption. *2020-11-20*: No reply received, so follow-up e-mail sent. *2020-11-27*: No reply received, so advisory sent by e-mail without encryption. *2021-02-03*: No reply received, so follow-up e-mail sent. *2021-02-12*: No reply received, so inquiry sent using the forms at support.dlink.com and eu.dlink.com/uk/en/contact-d-link. *2021-02-17*: Response from the US D-Link support team, pointing us towards the US-specific D-Link security page. *2021-02-17*: Sent e-mail to this new US-specific D-Link security e-mail address. *2021-02-19*: Response from a member of the D-Link USA SIRT. *2021-02-19*: We request a public key from D-Link USA for transmission of the advisory. *2021-02-19*: PGP public key is provided by D-Link USA. *2021-02-19*: Advisory is sent to D-Link USA with encryption. *2021-02-19*: Receipt of advisory is confirmed by D-Link USA SIRT. *2021-02-19*: We reply and ask for D-Link USA to keep us updated. *2021-02-20*: D-Link “ipsecure” finally answers our e-mail, saying that security@dlink.com should be the official e-mail, and the ipsecure@dlinkcorp.com e-mail (the only one listed on the main D-Link security disclosure page) is only a backup address. *2021-02-22*: D-Link USA responds, confirming that the e-mail address listed on the main D-Link security page has been changed. *2021-03-02*: We e-mail D-Link USA to ask for a status update. *2021-03-02*: D-Link USA responds with status update. *2021-03-08*: D-Link USA provides patched firmware for testing. *2021-03-08*: We respond asking for assigned CVE number. *2021-03-08*: D-Link USA notes that they do not apply for, or manage CVE numbers related to their own products. *2021-03-08*: We apply for a [CVE number](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-28144) for this issue. *2021-03-08*: [D-Link USA publishes public advisory](https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10208). *2021-03-11*: CVE is assigned & IoT Inspector Research Lab publishes advisory.