当一个网站被攻击之后,攻击者通常会留一个后门或者webshell,便于将来继续控制该网站。通常会对这些webshell做一些混淆来躲避检测。并且也需要认证,保证只有攻击者能通过它控制网站。首先,我会还原混淆处理了的webshell,并演示如何在只有源代码而没有密码的情况下绕过认证。
preg_replace有三个参数,正则表达式,替换字符串,被替换的对象。因为正则表达式中有e修饰符,它会把替换后的字符串当做PHP代码来执行。这与下面的代码类似:
preg_replace("/.*/", eval("/x65/x76/x61…/x29/x3B"), ".");
现在我们知道第二个参数被执行了,但是它看上去不像是PHP代码,这是因为代码被用十六进制编码了。一个双引号引起的字符串可以包含一些PHP能解释的转义字符。/x就是其中之一,可以在字符串中使用十六进制符号插入字符。比如,/x65就是e,因为在ASCII码表中就是这样的。手工转换这个字符串很费力,所以我使用PHP来完成:
echo "/x65/x76/x61…/x29/x3B";
结果
eval(gzinflate(base64_decode('5b19f…Z9P8C')));
在这里,base64_decode把文本转换为二进制,gzinflate解压这个二进制,eval把它作为PHP代码执行。要查看执行了什么PHP代码,我们用echo替换eval:
echo gzinflate(base64_decode('5b19f…Z9P8C'));
最终完成了我们的反混淆webshell工作。最后显示他是一个名为“WSO”的webshell,在GitHub上有它的 源代码 。
这样的手工反混淆PHP代码的过程,已经被Sucri在 PHP decoder 中实现了自动化,它可以自动完成上面的所有步骤。
代码中的$auth_pass变量说明这个webshell有认证机制。$auth_pass的格式是32个十六进制字符,说明它是明文密码的MD5值。现在我们有了webshell的源代码,我们可以确定:
if(!empty($auth_pass)) { if(isset($_POST['pass']) && (md5($_POST['pass']) == $auth_pass)) WSOsetcookie(md5($_SERVER['HTTP_HOST']), $auth_pass); if (!isset($_COOKIE[md5($_SERVER['HTTP_HOST'])]) || ($_COOKIE[md5($_SERVER['HTTP_HOST'])] != $auth_pass)) wsoLogin(); }
它对post过来的pass参数做了一个MD5,并与$auth_pass相比较。单纯的MD5不是一个安全的保存密码的方式。首先,MD5非常快,你可以每秒计算数十亿个hash来暴力破解密码。第二,许多弱口令的MD5已经在互联网上公布,可以用 Google搜索 到。但是,这名黑客选择了一个非常好的密码,我们无法破解它。但是因为我们有了源代码,可以有另外一种方法获得webshell的访问权限。
正如你在代码中看到的,如果你的密码正确,它会设置一个特定的cookie。它会检查这个cookie,如果不正确,它会调用wsoLogin显示一个登录页面并退出脚本。否则它会继续执行webshell代码。cookie的key是主机名的MD5,其内容是$auth_pass的值。幸运的是,这两个值我们都有,所以能创建一个我们自己的cookie来访问webshell。
首先,计算主机名的MD5,这里的-n防止在MD5中出现换行符。
$ echo -n example.com | md5sum 5ababd603b22780302dd8d83498e5172 -
然后,设置一个cookie,key为5ababd603b22780302dd8d83498e5172,值为64a113a4ccc22cffb9d2f75b8c19e333,是$auth_pass的值。我使用Chrome的插件 EditThisCookie 来编辑cookie。现在,你可以在不知道密码的情况下登录这个webshell了。
*译者:felix,翻译自:http://www.sjoerdlangkemper.nl/2016/02/04/circumventing-authentication-of-a-webshell,转载须注明来自FreeBuf黑客与极客(FreeBuf.COM)