0x00 前言
我最近经常上网(ri)(zhan)。当我看到各种各样的狗和盾牌时,我很沮丧。许多蜜壳已被杀死。我也想研发出这样一把杀马刀。顺便说一句,工作完成了。
如果你不知道如何进攻,你怎么知道如何防守?我们先来看看贝壳是如何逃避检测的:加密、变形、回调、隐藏关键字……总之一句话,让自己毫无特色,这样就可以躲避狗和盾的检测。 。但一切仍不忘初心,无论如何改造,最终都会回归到类似这样的格式:
#!php
$_GET($_POST)
分为执行数据部分($_GET)和数据传输部分($_POST)。也就是说,无论怎么改造,在执行过程中都会变成这样。接下来还是会执行类似 ()、exec()、eval() 之类的函数,那么我们就直接定位到这里来检测脚本是否调用了危险函数,或者分析脚本何时调用这些函数来判断脚本是否是非法用户的外壳。我们会得到很多信息。防御效果好。
0x01 如何占据上风
现在问题的根本原因已经分析出来了,下一步就是控制这些危险函数的入口点,即()等函数的底层入口点。就像挂钩API中的zw系列函数一样,我们也需要挂钩()这些函数。
这里我们需要用到PHP,即PHP扩展,它位于PHP内核zend和PHP应用程序代码之间。显然,扩展可以监控应用层代码的执行细节,还可以调用内核提供的ZEND API接口,包括禁用的类、禁用的函数等。该图展示了 PHP 的基本结构以及其他必要组件的结合。
ZEND为我们提供了执行此类操作的接口,通过这个就可以达到目的。据某位专家介绍,只需要三个钩子即可。
#!c
处理 eval() 等。
函数执行()等
E 变量函数执行 $func = ""; $func(); ETC。
例如,在 MINIT 中,替换:
#!c
(,);
然后定义自己的处理函数,这里就是。
10
11
12
13
14
15
16
#!c
整数(参数)
/* 检查是否是合法的调用*/
if(/*非法调用*/)
/*拦截但不执行。 */
别的
/*合法调用,继续执行*/
;
这个骨架就完成了,剩下的内容可以自己添加。这样,每当调用()这样的函数时,都会经过你自己的,这样你就可以检查上层代码的执行情况。
0x02 上面的方法太粗暴了
上面的方法虽然不错,但是会出现很多误判,甚至是普通的函数调用都会被直接禁止。这样的WAF如果放在业务中肯定会受到诟病。我们需要以不同的方式思考。
前面说过,无论你如何变换、加密、隐藏关键字等,最终都需要调用 () 和 eval() 等函数。毕竟,你无法逃避这些。那么我们就改变一下刚才的想法吧。不要直接挂钩那些,而是上升一级。
eval()函数调用了底层的函数,那么我们是否可以重载底层的函数或者用我们自己的函数替换它呢?答案是肯定的,我们只需重写自己的函数即可。
但对于 来说有点不同。我们把上面的钩子去掉了,但是这样太粗鲁了。我们可以在这里删除它,并用我们自己的函数注册该函数,这样就可以实现实时检查。如果是合法调用,则可以调用旧函数并继续执行。
显然这样做确实会降低误杀的风险,但同时也会增加风险,因为除了()之外还有很多可以用来执行命令的函数。除了执行命令之外,还存在遍历目录、读取敏感文件等问题。需要考虑很多方面,包括远程函数、PHP SPL 等方面。
0x03 说了这么多,我们来看看实际结果吧。
我们来看看三种hook方法的效果。首先,我们在 MINIT 函数中用我们自己的函数替换这三个处理函数。
10
11
12
13
14
15
16
17 号
18
19
20
21
22
23
24
#!c
()
/*
* 摘钩
* 处理功能等
*/
(,);
/*
* 脱钩 E
* 处理 $func='';$func();和其他类型
*/
(E、ME);
/*
* 摘钩
* 处理eval等
*/
(,L);
;
、ME和L有相似的内容。它们都确定脚本文件是否在目录中。如果是,则禁止执行危险功能,否则允许执行。这里我们解释一下:
10
11
12
13
14
15
16
17 号
18
19
20
21
22
#!c
/* */
整数(参数)
字符*;
= ();
(“[调试]:%s\n
”,);
如果((,”//”))
/* 非法调用,拦截 */
("[] 通过 () 等\n
”);
;
否则/*未找到*/
/* 合法调用、释放*/
;
这里我们看到,一旦检测到在目录中,就返回URN。实际效果是不继续执行危险函数。如果不在目录中,则返回 PATCH。实际效果是继续执行该函数。
扩展写好后,就可以编译得到so文件了。如果您对PHP扩展开发和编译不熟悉,请参考本扩展开发教程的第五章: ,开发知识超出了本文的内容,这里不再讨论。没有更多细节。
编译完成后,将获得的.so文件复制到PHP的扩展目录中。我的例子是/usr/local/php/lib/php//,根据自己的实际情况进行调整。接下来,修改 php.ini 让 PHP 自动加载我们的扩展,并在其中添加一行:
=/路径/到/我们的/.so
我在这里:
=/usr/local/php/lib/php//.so
根据之前放置so文件的位置,请自行修改路径。
最后我们重启PHP服务,使设置生效。 PHP重启后,在终端执行php -m,验证扩展是否加载成功。如果在结果中看到它,则说明加载成功。 (请忽略视图中的错误信息,是我本地环境的问题,对PHP没有影响。)
加载成功后,我们来看看实际效果。有一个上传文件的页面。您可以上传任何类型的文件,并将上传的文件保存在目录中。现在模拟这个过程。
让我们写一个包含以下内容的小马:
#!php
上传并访问shell,结果如下:
可以看到已经成功拦截了。好吧,我们换一匹更强大的马试试反射式吧。
#!php
继续上传访问查看结果:
还是被拦截了,不过这次触发的是E。接下来我们看看正常的文件是否会被拦截。在目录下写一个test.php来模拟正常的业务文件。内容如下:
#!php
访问并查看结果:
可以看到ls命令执行成功,也就是说我们的普通文件不会被截获,而只会截获目录下的文件。这将导致另一个缺点。如果攻击者使用某种方法将shell写入正常文件或者与业务结合起来,这种防御方法就很难发挥作用。具体的防御方法必须结合其他特征进行检测。并不是没有办法。在实际应用中,我们不能仅仅依靠检测文件路径的规则。我们需要结合业务来部署防御解决方案。
另一种方法与三钩法类似,只是麻烦一点。有兴趣的同学可以查看以下参考资料: ,里面描述了更详细的钩子函数的思路。
0x04 不谈业务安全简直就是流氓行为
综上所述,拦截的方式大概就是以上两种,但是拦截的依据还没有确定。如何判断一个调用()的脚本是否是?如果我们的WAF放到生产环境中,无论如何都被杀了,那么很可能正常的业务就无法进行了。我自己总结了几种方法,结合起来可能会更有效。
0x05 那么这个WAF有什么用呢?
安全需要与业务结合起来。不讲商业安全的人就是流氓。由于是扩展级别的WAF,部署时可能需要重新编译、修改配置文件等。批量部署看似不方便,必须根据业务需求进行各种细微的调整。如果只有很少的服务器,我相信这个WAF还是很好的,而且非常容易调整。
如果能够开发出适合批量部署的基于扩展的WAF,可能更容易普及。毕竟,在业务中部署WAF并不是一件简单的事情。
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。