代码审计入门总结
字数 2146 2025-08-29 08:31:47

PHP代码审计入门与常见漏洞总结

0x00 简介

本文是基于seay《PHP代码审计》一书的学习总结,旨在为代码审计初学者提供一个系统的学习框架和常见漏洞函数参考。通过学习,读者应能够独立完成对CMS系统的代码安全检测。

0x01 代码审计整体思路

  1. 通读全文代码:从功能函数代码开始阅读,如include文件夹下的common_fun.php等关键文件。

  2. 查看配置文件:查找带有config关键字的文件,特别是数据库连接文件如mysql.class.php中的connect()函数。

  3. 跟踪首页文件:从index.php入手,了解程序运作时调用的函数和文件。

  4. 扩展阅读:以index.php为起点,层层扩展阅读包含的文件,了解其功能后进入功能文件夹的首页文件继续深入。

0x02 常见漏洞类型及审计方法

A. 文件操作漏洞

安全原则:

  • 尽量避免使用用户可控的文件名参数
  • 严格区分用户权限
  • 禁止传入../\等特殊字符
  • 对传入参数进行检查和限制

1. 文件包含漏洞

  • 本地文件包含:常见于模块加载、模板加载、cache调用

    • 关键函数:include()/include_once()require()/require_once()
    • 审计重点:寻找可控变量
  • 远程文件包含:需allow_url_include = on

  • 文件包含截断

    • PHP版本<5.3时可用
    • 截断方式:问号(伪截断)、点(.)、反斜杠(/)

2. 文件读取(下载)漏洞

  • 关键函数:
    file_get_contents(), highlight_file(), fopen(), readfile(), 
    fread(), fgetss(), fgets(), parse_ini_file(), show_source(), file()
    

3. 文件上传漏洞

  • 关键函数:move_uploaded_file()

  • 常见绕过方式:

    • 未过滤或本地过滤:直接上传PHP文件
    • 黑名单绕过
      • 利用IIS默认支持的扩展名(.asp, .cdx, .asa, .cer等)
      • 文件名后加空格(如1.php )
    • 文件头验证绕过
      • 伪造GIF89a文件头绕过getimagesize()
      • 控制$_FILES["file"]["type"]
  • 防范措施

    • 使用in_array()===严格比较扩展名
    • 重命名规则:md5(time() + rand(1,1000))

4. 文件删除漏洞

  • 关键函数:unlink()
  • 经典案例:Metinfo任意文件删除漏洞
    target.com/recovery.php?&action=delete&filename=../../index.php
    

B. 代码执行漏洞

1. 代码执行函数

  • 关键函数:

    eval(), assert(), preg_replace(), call_user_func(), 
    call_user_func_array(), array_map()
    
  • 特殊用法:

    • preg_replace()e修饰符:$replacement会被当作PHP代码执行
    • call_user_func():第一个参数为回调函数,第二个为参数
    • eval()assert()区别:
      eval("phpinfo();");  // 正确
      assert("phpinfo();"); // 正确
      eval("phpinfo()");   // 错误(缺少分号)
      assert("phpinfo()");  // 正确
      

2. 动态函数执行

  • 后门示例:
    <?php $_GET['a']($_GET['b']); ?>
    

3. 命令执行函数

  • 关键函数:

    system(), exec(), shell_exec(), passthru(), 
    pcntl_exec(), popen(), proc_open()
    
  • 特殊用法:

    • popen()示例:
      popen('whoami >> /path/1.txt', 'r');
      
    • 反引号执行:echo `whoami`;
  • 双引号与单引号区别:

    $a = 1;
    echo "$a";  // 输出1(解析变量)
    echo '$a';  // 输出$a(不解析)
    

C. 变量覆盖漏洞

1. 危险函数

  • extract():从数组导入变量到当前符号表
  • parse_str():将字符串解析为多个变量
  • import_request_variables():导入GET/POST/Cookie变量

2.

\[变量覆盖 - 示例: ```php foreach($_GET as $key => $value) { \]

key = $value; // 可能导致变量覆盖
}


### D. 逻辑漏洞

#### 1. 等于与存在判断绕过
- `in_array()`:比较前自动转换类型
- `is_numeric()`:HEX输入可通过检查
- `==`与`===`区别:双等于会类型转换,三等于严格比较

#### 2. 越权问题
- **水平越权**:同权限用户间的越权
- **垂直越权**:低权限用户获取高权限

#### 3. 常见问题
- 缺少`exit`/`return`/`die`:
```php
if(file_exists('install.lock')) {
    header("Location:xxx.com");
    // 缺少exit
}
echo "test";  // 仍会执行

4. 支付漏洞

  • 客户端修改单价/总价/数量
  • 服务端未严格校验
  • 重复发包利用时间差

5. 危险函数

  • str_replace()可能被绕过:
    $a = addslashes($_GET['a']);
    $b = addslashes($_GET['b']);
    $c = str_replace($a,'',$b);  // 可能被绕过
    

E. 会话认证漏洞

1. COOKIE验证问题

  • 敏感信息直接保存在COOKIE中
  • 加密算法可逆

2. 安全建议

  • 优先使用SESSION而非COOKIE
  • SHA1比MD5更安全(解密网站更少)
  • 限制用户单IP登录

F. 二次漏洞

1. 特点

  • 不是逻辑问题,而是可信问题
  • 业务越复杂,触发率越高
  • 常见场景:购物车、订单、引用数据、文章编辑

2. 常见技巧

  • GPC转义绕过

    • $_SERVER不受GPC保护
    • GBK宽字节注入:%df'運'
  • 字符串问题

    • 空字符截断(PHP<5.3)
    • iconv转换截断:
      $a = '1'.chr(130).'2';
      echo iconv("UTF-8", "GBK", $a);  // 输出1
      
  • php://流利用

    include($_GET['file']);
    // 利用:file=php://filter/convert.base64-encode/resource=example.txt
    

3. PHP解析标签

  • <script language="php">...</script>
  • <?...?>(PHP3.0.4+)
  • <%...%>(需asp_tags=on

4. 正则问题

  • 缺少^$限定匹配位置
  • 特殊字符未转义

5. 报错注入

  • Windows FindFirstFile利用:
    • 搜索12345.txt可用1<<12<<代替
    • 不能单独使用<>

0x03 总结

代码审计需要结合开发知识,理解业务逻辑和代码执行流程。本文总结了PHP代码审计中的常见漏洞类型、危险函数和审计方法,可作为初学者入门参考。实际审计时应结合具体代码上下文,灵活运用这些知识。

PHP代码审计入门与常见漏洞总结 0x00 简介 本文是基于seay《PHP代码审计》一书的学习总结,旨在为代码审计初学者提供一个系统的学习框架和常见漏洞函数参考。通过学习,读者应能够独立完成对CMS系统的代码安全检测。 0x01 代码审计整体思路 通读全文代码 :从功能函数代码开始阅读,如 include 文件夹下的 common_fun.php 等关键文件。 查看配置文件 :查找带有 config 关键字的文件,特别是数据库连接文件如 mysql.class.php 中的 connect() 函数。 跟踪首页文件 :从 index.php 入手,了解程序运作时调用的函数和文件。 扩展阅读 :以 index.php 为起点,层层扩展阅读包含的文件,了解其功能后进入功能文件夹的首页文件继续深入。 0x02 常见漏洞类型及审计方法 A. 文件操作漏洞 安全原则: 尽量避免使用用户可控的文件名参数 严格区分用户权限 禁止传入 .. 、 / 、 \ 等特殊字符 对传入参数进行检查和限制 1. 文件包含漏洞 本地文件包含 :常见于模块加载、模板加载、cache调用 关键函数: include() / include_once() 、 require() / require_once() 审计重点:寻找可控变量 远程文件包含 :需 allow_url_include = on 文件包含截断 : PHP版本 <5.3时可用 截断方式:问号(伪截断)、点(.)、反斜杠(/) 2. 文件读取(下载)漏洞 关键函数: 3. 文件上传漏洞 关键函数: move_uploaded_file() 常见绕过方式: 未过滤或本地过滤 :直接上传PHP文件 黑名单绕过 : 利用IIS默认支持的扩展名(.asp, .cdx, .asa, .cer等) 文件名后加空格(如 1.php ) 文件头验证绕过 : 伪造 GIF89a 文件头绕过 getimagesize() 控制 $_FILES["file"]["type"] 值 防范措施 : 使用 in_array() 或 === 严格比较扩展名 重命名规则: md5(time() + rand(1,1000)) 4. 文件删除漏洞 关键函数: unlink() 经典案例:Metinfo任意文件删除漏洞 B. 代码执行漏洞 1. 代码执行函数 关键函数: 特殊用法: preg_replace() 的 e 修饰符: $replacement 会被当作PHP代码执行 call_user_func() :第一个参数为回调函数,第二个为参数 eval() 与 assert() 区别: 2. 动态函数执行 后门示例: 3. 命令执行函数 关键函数: 特殊用法: popen() 示例: 反引号执行: echo `whoami`; 双引号与单引号区别: C. 变量覆盖漏洞 1. 危险函数 extract() :从数组导入变量到当前符号表 parse_str() :将字符串解析为多个变量 import_request_variables() :导入GET/POST/Cookie变量 2. $$变量覆盖 示例: D. 逻辑漏洞 1. 等于与存在判断绕过 in_array() :比较前自动转换类型 is_numeric() :HEX输入可通过检查 == 与 === 区别:双等于会类型转换,三等于严格比较 2. 越权问题 水平越权 :同权限用户间的越权 垂直越权 :低权限用户获取高权限 3. 常见问题 缺少 exit / return / die : 4. 支付漏洞 客户端修改单价/总价/数量 服务端未严格校验 重复发包利用时间差 5. 危险函数 str_replace() 可能被绕过: E. 会话认证漏洞 1. COOKIE验证问题 敏感信息直接保存在COOKIE中 加密算法可逆 2. 安全建议 优先使用SESSION而非COOKIE SHA1比MD5更安全(解密网站更少) 限制用户单IP登录 F. 二次漏洞 1. 特点 不是逻辑问题,而是可信问题 业务越复杂,触发率越高 常见场景:购物车、订单、引用数据、文章编辑 2. 常见技巧 GPC转义绕过 : $_SERVER 不受GPC保护 GBK宽字节注入: %df' → 運' 字符串问题 : 空字符截断(PHP <5.3) iconv 转换截断: php://流利用 : 3. PHP解析标签 <script language="php">...</script> <?...?> (PHP3.0.4+) <%...%> (需 asp_tags=on ) 4. 正则问题 缺少 ^ 和 $ 限定匹配位置 特殊字符未转义 5. 报错注入 Windows FindFirstFile利用: 搜索 12345.txt 可用 1<< 或 12<< 代替 不能单独使用 < 或 > 0x03 总结 代码审计需要结合开发知识,理解业务逻辑和代码执行流程。本文总结了PHP代码审计中的常见漏洞类型、危险函数和审计方法,可作为初学者入门参考。实际审计时应结合具体代码上下文,灵活运用这些知识。