靶场 PHP 函数整理与漏洞防御方式总结


第一部分 靶场中用到的 PHP 函数

一、一句话木马 / 代码执行相关

函数 / 语句 作用 靶场中的用法
eval($code) 把字符串当作 PHP 代码执行 一句话木马核心:<?php @eval($_POST['cmd']); ?>
assert($code) 断言,传入字符串时也会执行 PHP 代码 一句话木马变体
call_user_func($func, $arg) 回调方式动态调用函数 call_user_func('system', $_GET['cmd']),常用于绕过对 system 关键字的过滤
call_user_func_array() 同上,参数以数组形式传递 回调绕过变体
preg_replace() 正则替换;PHP<5.5 时 /e 修饰符会执行替换结果中的代码 历史代码执行点(面试常考)
create_function() 动态创建函数(PHP<7.2),可注入代码 历史代码执行点

区别要点(7.27 课堂重点):eval 执行的是 PHP 代码,system 执行的是操作系统命令。

二、命令执行相关

函数 作用 特点
system($cmd) 执行系统命令并直接输出结果 页面直接显示命令结果(如 whoami → www-data)
exec($cmd, $output) 执行命令,结果放入数组,只返回最后一行 不自动输出,需配合 echo
shell_exec($cmd) 执行命令,返回完整输出字符串 无回显时需 echo shell_exec(...)
passthru($cmd) 执行命令并原样输出(含二进制) 适合输出原始数据
popen() / proc_open() 以进程方式执行命令,返回句柄 进阶/绕过场景

三、文件包含相关

1. 四个包含函数

函数 文件找不到时 重复包含
include 警告(Warning),继续执行 允许
include_once 警告,继续执行 同一文件仅一次
require 致命错误,程序终止 允许
require_once 致命错误,程序终止 同一文件仅一次

典型漏洞代码:include $_GET['page'];

2. 相关 php.ini 配置项

  • allow_url_include:是否允许包含远程 URL(RFI、php://input、data:// 的前提)
  • allow_url_fopen:是否允许 URL 方式的文件操作
  • open_basedir:限制 PHP 可访问的目录范围

第二部分 各类型漏洞的防御方式

一、文件上传漏洞

成因: 对上传文件的类型、后缀、内容校验不严,或校验逻辑存在时序/逻辑缺陷,导致可执行脚本落地服务器。

缺陷类型 典型绕过 防御方式
仅前端 JS 校验 禁用 JS / Burp 改包 服务端必须重新校验,前端校验只做体验
仅校验 Content-Type Burp 改 MIME MIME 可被伪造,只能作为辅助,不能作为唯一依据
黑名单 php3/php5/大小写/双写/末尾点/::$DATA 改用白名单(只允许 jpg/png/gif 等)
单次替换 pphphp 双写 白名单;或循环替换至无匹配
路径参数可控 save_path + %00 截断 过滤 ../%00,用 basename() 取纯文件名,保存路径由服务端写死
文件内容检测 图片马 + 文件包含 二次渲染(GD 重编码);上传目录与包含白名单隔离
先保存后校验 条件竞争 先校验后保存;使用临时随机名,校验通过再改名(原子化)
用户可控文件名 save_name 大小写/末尾点/数组 is_string() 强制类型检查;服务端统一重命名

通用加固清单:

  1. 扩展名、MIME、文件内容(图片二次渲染)三重校验,以白名单为准;
  2. 服务端随机重命名,攻击者无法预测路径与文件名;
  3. 上传目录禁止脚本解析(Apache/Nginx 配置关闭该目录 PHP 执行),最好存放到 Web 根目录之外或独立域名/对象存储;
  4. 完整清理链且顺序正确:trim → deldot → strtolower → 去::$DATA先清理再检查
  5. 限制文件大小,Web 服务低权限运行。

二、文件包含漏洞

成因: include/require 的参数来自用户输入且未严格限制,导致包含预期外文件(敏感文件、日志、Session、上传的图片马、远程恶意文件)。

  1. 首选:白名单映射——用户只提交业务标识,真实路径由服务端决定:
    $pages = ['home'=>__DIR__.'/pages/home.php', 'news'=>__DIR__.'/pages/news.php'];
    $key = $_GET['page'] ?? 'home';
    if (!isset($pages[$key])) { http_response_code(404); exit('页面不存在'); }
    include $pages[$key];
    
  2. 必须传路径时做规范化校验realpath() 解析 ../ 和符号链接后,确认最终路径仍在允许目录内(strpos($target, $base)===0)。
  3. 配置加固:生产环境关闭 allow_url_include;按需评估关闭 allow_url_fopen;配置 open_basedir 限制访问范围。
  4. 切断组合利用链:上传、日志、Session 目录不可被包含;上传目录禁止 PHP 解析。
  5. 最小权限 + 不泄露信息:Web 进程低权限运行;关闭 display_errors,错误页不泄露绝对路径。
  6. 不用字符串替换黑名单(过滤 ../php:// 易被变形绕过)。

三、代码执行 / 命令执行漏洞

成因: 用户可控数据进入 evalsystemexecshell_execpassthrucall_user_func 等函数。

  1. 删除危险用法:生产代码不使用 eval() 执行用户输入;不把用户输入传给命令执行函数。
  2. 白名单替代动态调用:用固定业务逻辑/白名单映射,不让用户提供函数名或代码:
    $actions = ['show_user' => function(){ /* 固定业务代码 */ }];
    if (isset($actions[$action])) { echo $actions[$action](); }
    
  3. 必须执行系统命令时:参数用 escapeshellarg() / escapeshellcmd() 转义,命令白名单化。
  4. 纵深防御:Web 服务低权限账户运行;结合容器、SELinux/AppArmor 限制影响范围;在 php.ini 中用 disable_functions 禁用 system,exec,shell_exec,passthru,eval 等高危函数。

四、CSRF 跨站请求伪造

成因: 服务端只验证 Cookie 中的登录状态,不验证请求是否由用户本人主动发起,攻击者诱导已登录用户访问恶意页面,以其身份执行非预期操作。

  1. CSRF Token:表单/请求中嵌入服务端生成的随机 Token,提交时校验(攻击者无法预知 Token)——最有效
  2. 校验 Referer / Origin:确认请求来源是本站点;
  3. SameSite Cookie:设置 SameSite=Strict/Lax,阻止跨站携带 Cookie;
  4. 二次验证:敏感操作(改密、转账)要求重新输入密码、短信/图形验证码;
  5. 关键操作使用 POST 而非 GET,并配合自定义请求头(如 X-Requested-With)。

五、越权攻击

成因: 服务端只判断"是否登录",不判断"该用户是否有权操作这条数据/这个功能"。

类型 说明 防御
水平越权 同等级用户间越权访问数据(改 id 看他人信息) 服务端对每个请求校验数据归属:操作对象必须与当前会话用户绑定;不使用可猜测的连续 ID(用随机/加密 ID)
垂直越权 普通用户执行管理员功能 基于角色的访问控制(RBAC);服务端对每个接口做权限等级校验;管理接口不对普通用户开放;前端隐藏按钮不算防御

核心原则:所有权限判断必须在服务端完成,前端隐藏、参数信任都不可靠。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐