PHP代码审计入门(一)
字数 3178 2025-08-15 21:32:20

PHP代码审计入门教程

0x00. 代码审计目的

代码审计指的是对源代码进行检查,寻找代码中的bug以及安全缺陷(漏洞)。这是一项需要多方面技能的技术,需要掌握以下知识:

  • 编程能力
  • 安全工具使用
  • 漏洞原理
  • 漏洞修复方式
  • 函数缺陷
  • 设计模式和编程思想
  • MVC框架和常见框架

核心原则:"一切存在用户输入的地方都有可能存在漏洞"

0x01. 代码审计基础

必备基础知识

  1. 基础语法

    • HTML/JS基础语法
    • PHP基础语法
    • 面向对象思想
  2. 开发经验

    • PHP小项目开发(Blog、注册登录、表单、文件上传、留言板等)
  3. 安全知识

    • Web漏洞挖掘及利用
    • Web安全工具基本使用(burpsuite、sqlmap等)
    • 代码审计工具(seay审计系统、zend studio+xdebug等)

代码审计基本方式

  1. 通读全文源码

    • 最全面但最麻烦的方法
    • 适合了解整个Web应用的业务逻辑
    • 能挖掘到更多有价值的漏洞
  2. 功能点审计

    • 根据漏洞对应发生函数进行审计
    • 常用逆向溯源数据流方法

代码审计基本方法

  1. 正向追踪数据流

    • 跟踪用户输入参数 → 代码逻辑 → 审计缺陷 → 构造payload
  2. 逆向溯源数据流

    • 搜索指定操作函数 → 跟踪可控参数 → 审计缺陷 → 构造payload

CMS分类

  1. 单入口CMS

    • 所有模块使用同一个入口文件
    • 常见于MVC框架
  2. 多入口CMS

    • 每个模块有独立入口文件
    • 如前端index.php,后端admin.php

0x02. 代码审计思路

  1. 三个层次

    • 确定审计源码的语言
    • 确定是单入口还是多入口
    • 确定该语言的各种漏洞函数
  2. 建议路径

    • 先做"程序员"再做审计
    • 学习面向对象/面向过程编程
    • 编写项目提升代码理解能力
    • 掌握漏洞挖掘利用和危害理解

0x03. PHP核心安全配置

重要安全配置项

  1. safe_mode

    • 限制文档存取、环境变量存取、外部程序执行
    • PHP5.4.0已移除
  2. safe_mode_allowed_env_vars

    • 指定PHP可改变的环境变量前缀
  3. safe_mode_exec_dir

    • 限制exec()函数执行的可执行文件目录
  4. disable_functions

    • 禁止敏感函数使用
    • 注意要包含dl()函数
  5. com.allow_dcom

    • 建议设置为false防止COM()函数创建系统组件
  6. register_globals

    • 建议设置为off
    • 防止自动注册全局变量
  7. magic_quotes_gpc

    • 自动转义SQL查询中的特殊字符
    • PHP5.4.0已移除
  8. allow_url_include

    • 建议设置为off
    • 防止远程文件包含
  9. allow_url_open

    • 控制是否允许通过URL打开文件
  10. expose_php

    • 建议设置为off
    • 防止通过HTTP头泄漏PHP版本信息
  11. upload_tmp_dir

    • 设置文件上传临时目录
  12. open_basedir

    • 限制PHP脚本访问目录
  13. display_errors

    • 生产环境建议设置为off
    • 防止错误信息泄露
  14. error_reporting

    • 设置错误报告级别
    • 部署时可设为E_ALL & ~Enotice

0x04. 代码审计环境

推荐工具

  1. PHP源码部署环境

    • Phpstudy 2018
  2. 集成开发环境

    • Zend Studio
    • Phpstorm
  3. 数据库工具

    • Navicat for MySQL 12
    • MySQLMonitor
  4. 文本编辑工具

    • Sublime_Text3
  5. 代码审计辅助工具

    • Seay源代码审计系统
    • Search and Replace
    • Rips 0.55
  6. 安全工具

    • 渗透版火狐
    • BurpSuite
    • Sqlmap

0x05. 手动调试代码

常用调试方法

  1. 输出调试:

    echo exit();
    print_r();
    var_dump();
    debug_zval_dump();
    debug_print_backtrace();
    
  2. 弹窗调试:

    echo "<script>alert($estr);</script>";
    die("<script>alert($estr);</script>");
    

0x06. PHP的弱类型问题

1. 比较符号 == 与 ===

  • ==:会进行类型转换

    var_dump(0=="admin"); //true
    var_dump(1=="1admin"); //true
    var_dump(1=="admin1"); //false
    var_dump(0=="admin1"); //true
    
  • ===:先判断类型是否相同

    var_dump("0e123456"=="0e4456789"); //true
    var_dump("1e1"=="10"); //true
    

2. array_search与is_array

if(!is_array($_GET['test'])){ exit(); }
$test = $_GET['test'];
for($i = 0;$i<count($test) ;$i++ ){
    if($test[$i] === "admin"){
        echo "error";
        exit();
    }
    $test[$i] = intval($test[$i]);
}
if(array_search("admin",$test) === 0){
    echo "flag";
}else{
    echo "false";
}

绕过方法:传入test[]=0

3. in_array()函数

$array=[0,1,2,'3'];
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true

4. is_number()函数

$temp = $_GET['password'];
is_numeric($temp) ? die("no numeric") : NULL;
if($temp>9999){
    echo '我giao';
}

绕过方法10000+

5. strcmp()函数

$pd = "6666";
if(strcmp($_GET['pwd'],$pd) == 0){
    echo "giao";
}else{
    echo "?";
}

绕过方法:传入数组

6. switch()语句

$pwd = "1ad";
switch($pwd){
    case 1: echo "giao"; break;
    case 2: echo "?"; break;
}

问题:会将参数转换为int类型

7. md5()函数

var_dump(md5('240610708') == md5('QNKCDZO'));//true

$array1=[1,2,3];
$array2=[4,5,6];
var_dump(md5($array1)===md5($array2)) //true

8. sha1()函数

$array1=[1,2,3];
$array2=[4,5,6];
var_dump(sha1($array1)===sha1($array2)); //true

9. empty与isset

$a = null; $b = 0; $c = "";
var_dump(empty($a)); //true
var_dump(empty($b)); //true
var_dump(empty($c)); //true
var_dump(isset($a)); //false
var_dump(isset($b)); //true
var_dump(isset($c)); //true

0x07. 漏洞函数学习

1. 全局变量/超全局变量

  • 全局变量:定义在函数外部,作用域到文件结尾
  • 超全局变量:始终可用,包括:
    • $GLOBALS
    • $_SERVER
    • $_REQUEST
    • $_POST
    • $_GET
    • $_FILES
    • $_ENV
    • $_COOKIE
    • $_SESSION

2. SQL注入相关

  • SQL语句:
    • select
    • update
    • insert into
    • delete

3. 代码执行函数

  • eval()
  • usort()
  • uasort()
  • assert()
  • array_map()
  • preg_replace()
  • array_filter()
  • call_user_func()
  • create_function()
  • call_user_func_array()
  • 动态函数:$_GET['a']($_GET['b'])

4. 命令执行函数

  • system()
  • exec()
  • passthru()
  • shell_exec()

5. XSS相关函数

  • print
  • print_r
  • echo
  • printf
  • die
  • var_dump
  • var_export

6. 文件上传漏洞

  • move_uploaded_file()

7. 文件包含漏洞

  • include()
  • include_once()
  • require()
  • require_once()

伪协议

  • file://
  • http://
  • ftp://
  • php://
  • zlib://
  • data://
  • glob://
  • phar://
  • ssh2://
  • rar://
  • ogg://
  • expect://

8. 任意文件下载

  • fopen()
  • readfile()
  • file_get_contents()

9. 任意文件删除

  • unlink()

10. 任意文件读取

  • file()
  • fgets()
  • fgetss()
  • fopen()
  • readfile()
  • fpassthru()
  • parse_ini_file()
  • file_get_contents()

11. 变量覆盖

\[ - extract() - parse_str() - import_request_variables() (PHP4.1~PHP5.4) ### 12. 反序列化漏洞 - unserialize() **魔术方法**: - __construct() - __destruct() - __call() - __callStatic() - __get() - __set() - __isset() - __unset() - __sleep() - __wakeup() - __toString() - __invoke() - __set_state() - __clone() - __debuginfo() ## 0x08. 审计入门总结 ### 学习路径 1. 理解Web漏洞原理 2. 学习漏洞挖掘利用 3. 学习PHP开发 4. 掌握漏洞对应函数 5. 学习正则表达式 ### 审计路线 Demo → 综合漏洞靶场 → 网上审计过的CMS → 多入口CMS → 单入口CMS → 框架 → 函数缺陷 ### 推荐练习 - 从简单Demo开始 - 综合漏洞靶场练习 - 审计已知漏洞的CMS - 逐步挑战更复杂的系统\]

PHP代码审计入门教程 0x00. 代码审计目的 代码审计指的是对源代码进行检查,寻找代码中的bug以及安全缺陷(漏洞)。这是一项需要多方面技能的技术,需要掌握以下知识: 编程能力 安全工具使用 漏洞原理 漏洞修复方式 函数缺陷 设计模式和编程思想 MVC框架和常见框架 核心原则 :"一切存在用户输入的地方都有可能存在漏洞" 0x01. 代码审计基础 必备基础知识 基础语法 : HTML/JS基础语法 PHP基础语法 面向对象思想 开发经验 : PHP小项目开发(Blog、注册登录、表单、文件上传、留言板等) 安全知识 : Web漏洞挖掘及利用 Web安全工具基本使用(burpsuite、sqlmap等) 代码审计工具(seay审计系统、zend studio+xdebug等) 代码审计基本方式 通读全文源码 : 最全面但最麻烦的方法 适合了解整个Web应用的业务逻辑 能挖掘到更多有价值的漏洞 功能点审计 : 根据漏洞对应发生函数进行审计 常用逆向溯源数据流方法 代码审计基本方法 正向追踪数据流 : 跟踪用户输入参数 → 代码逻辑 → 审计缺陷 → 构造payload 逆向溯源数据流 : 搜索指定操作函数 → 跟踪可控参数 → 审计缺陷 → 构造payload CMS分类 单入口CMS : 所有模块使用同一个入口文件 常见于MVC框架 多入口CMS : 每个模块有独立入口文件 如前端index.php,后端admin.php 0x02. 代码审计思路 三个层次 : 确定审计源码的语言 确定是单入口还是多入口 确定该语言的各种漏洞函数 建议路径 : 先做"程序员"再做审计 学习面向对象/面向过程编程 编写项目提升代码理解能力 掌握漏洞挖掘利用和危害理解 0x03. PHP核心安全配置 重要安全配置项 safe_ mode : 限制文档存取、环境变量存取、外部程序执行 PHP5.4.0已移除 safe_ mode_ allowed_ env_ vars : 指定PHP可改变的环境变量前缀 safe_ mode_ exec_ dir : 限制exec()函数执行的可执行文件目录 disable_ functions : 禁止敏感函数使用 注意要包含dl()函数 com.allow_ dcom : 建议设置为false防止COM()函数创建系统组件 register_ globals : 建议设置为off 防止自动注册全局变量 magic_ quotes_ gpc : 自动转义SQL查询中的特殊字符 PHP5.4.0已移除 allow_ url_ include : 建议设置为off 防止远程文件包含 allow_ url_ open : 控制是否允许通过URL打开文件 expose_ php : 建议设置为off 防止通过HTTP头泄漏PHP版本信息 upload_ tmp_ dir : 设置文件上传临时目录 open_ basedir : 限制PHP脚本访问目录 display_ errors : 生产环境建议设置为off 防止错误信息泄露 error_ reporting : 设置错误报告级别 部署时可设为E_ ALL & ~Enotice 0x04. 代码审计环境 推荐工具 PHP源码部署环境 : Phpstudy 2018 集成开发环境 : Zend Studio Phpstorm 数据库工具 : Navicat for MySQL 12 MySQLMonitor 文本编辑工具 : Sublime_ Text3 代码审计辅助工具 : Seay源代码审计系统 Search and Replace Rips 0.55 安全工具 : 渗透版火狐 BurpSuite Sqlmap 0x05. 手动调试代码 常用调试方法 输出调试: 弹窗调试: 0x06. PHP的弱类型问题 1. 比较符号 == 与 === == :会进行类型转换 === :先判断类型是否相同 2. array_ search与is_ array 绕过方法 :传入 test[]=0 3. in_ array()函数 4. is_ number()函数 绕过方法 : 10000+ 5. strcmp()函数 绕过方法 :传入数组 6. switch()语句 问题 :会将参数转换为int类型 7. md5()函数 8. sha1()函数 9. empty与isset 0x07. 漏洞函数学习 1. 全局变量/超全局变量 全局变量:定义在函数外部,作用域到文件结尾 超全局变量:始终可用,包括: $GLOBALS $_ SERVER $_ REQUEST $_ POST $_ GET $_ FILES $_ ENV $_ COOKIE $_ SESSION 2. SQL注入相关 SQL语句: select update insert into delete 3. 代码执行函数 eval() usort() uasort() assert() array_ map() preg_ replace() array_ filter() call_ user_ func() create_ function() call_ user_ func_ array() 动态函数: $_GET['a']($_GET['b']) 4. 命令执行函数 system() exec() passthru() shell_ exec() 5. XSS相关函数 print print_ r echo printf die var_ dump var_ export 6. 文件上传漏洞 move_ uploaded_ file() 7. 文件包含漏洞 include() include_ once() require() require_ once() 伪协议 : file:// http:// ftp:// php:// zlib:// data:// glob:// phar:// ssh2:// rar:// ogg:// expect:// 8. 任意文件下载 fopen() readfile() file_ get_ contents() 9. 任意文件删除 unlink() 10. 任意文件读取 file() fgets() fgetss() fopen() readfile() fpassthru() parse_ ini_ file() file_ get_ contents() 11. 变量覆盖 $$ extract() parse_ str() import_ request_ variables() (PHP4.1~PHP5.4) 12. 反序列化漏洞 unserialize() 魔术方法 : __ construct() __ destruct() __ call() __ callStatic() __ get() __ set() __ isset() __ unset() __ sleep() __ wakeup() __ toString() __ invoke() __ set_ state() __ clone() __ debuginfo() 0x08. 审计入门总结 学习路径 理解Web漏洞原理 学习漏洞挖掘利用 学习PHP开发 掌握漏洞对应函数 学习正则表达式 审计路线 Demo → 综合漏洞靶场 → 网上审计过的CMS → 多入口CMS → 单入口CMS → 框架 → 函数缺陷 推荐练习 从简单Demo开始 综合漏洞靶场练习 审计已知漏洞的CMS 逐步挑战更复杂的系统