
1. PHP内置类漏洞初探最近在审计一个PHP项目时遇到了一个有趣的安全限制绕过场景。目标代码使用了__wakeup魔术方法进行严格的条件检查但通过PHP内置的Error和Exception类我成功绕过了这些限制。这种技术在实际渗透测试中非常实用特别是当遇到需要绕过md5和sha1比较的场景时。PHP内置类指的是PHP语言本身提供的类比如Error、Exception这些处理错误和异常的类。它们有一些特殊的行为特性比如当对象被当作字符串使用时会自动调用__toString方法。这个特性在特定场景下可以被利用来绕过安全检查。我最早是在分析一个CTF题目时发现这个技巧的当时题目设置了多重条件限制常规方法根本无法突破。2. 漏洞原理深度解析2.1 __wakeup魔术方法的陷阱让我们先看一个典型的漏洞代码示例class SYCLOVER { public $syc; public $lover; public function __wakeup(){ if( ($this-syc ! $this-lover) (md5($this-syc) md5($this-lover)) (sha1($this-syc) sha1($this-lover)) ){ if(!preg_match(/\?php|\(|\)|\|\/, $this-syc, $match)){ eval($this-syc); } else { die(Try Hard !!); } } } }这段代码看起来做了多重防护首先比较两个属性是否不同然后检查它们的md5和sha1值是否相同最后用正则过滤危险字符常规思路是用数组绕过md5/sha1比较因为数组的哈希值是NULL。但这里有个陷阱eval参数不能是数组。这就是内置类派上用场的地方。2.2 Error/Exception类的神奇特性PHP的Error和Exception类有个关键特性当对象被当作字符串使用时比如在比较或哈希计算时会自动调用__toString方法。更妙的是我们可以控制这些类的message属性而这个属性会出现在__toString的输出中。实验发现即使两个Error/Exception对象不同比如错误代码不同只要它们的message相同md5和sha1值就会相同。这是因为哈希计算的是字符串形式而字符串形式主要由message决定。3. 实战绕过技巧3.1 构造有效payload下面是我在实际测试中使用的payload构造方法$str ??include~.urldecode(%D0%99%93%9E%98).?; $a new Exception($str, 1); $b new Exception($str, 2); $c new SYCLOVER(); $c-syc $a; $c-lover $b; echo urlencode(serialize($c));这段代码有几个关键点使用相同的message创建两个Exception对象设置不同的错误代码使对象不同通过序列化将对象注入3.2 为什么这样能绕过让我们拆解条件判断$this-syc ! $this-lover因为错误代码不同对象确实不同md5($this-syc) md5($this-lover)字符串形式相同哈希值相同sha1($this-syc) sha1($this-lover)同上payload中的??是为了闭合可能存在的PHP标签~操作符用于取反操作绕过字符限制。这种技术在文件包含漏洞中也很常见。4. 版本兼容性与变种利用4.1 PHP版本差异处理在实际测试中我发现不同PHP版本有些差异需要注意PHP 5.x只能使用Exception类PHP 7可以使用Error或Exception类Error类是PHP 7引入的在更早版本不可用我曾经在一个PHP 5.4.1环境测试时遇到问题因为尝试使用Error类导致报错。后来切换到Exception类就成功了。所以实际利用时要先确认目标PHP版本。4.2 替代方案与变种除了直接包含文件还可以用其他方式构造payload使用$_GET参数动态包含$str ??include $_GET[_]?;使用反引号执行命令$str ??whoami?;组合多种绕过技术应对更严格的过滤需要注意的是现代PHP环境可能有更多限制比如禁用危险函数、开启安全模式等。在实际渗透测试中需要根据目标环境调整策略。