php反序列化漏洞利用
一个`serialize()`把对象变成字符串,序列一个`unserialize()`把字符串变回对象。化漏就这么两个函数,洞利在PHP世界里搅出了无数血案。序列攻击者根本不需要知道源码长什么样,化漏只要往参数里塞一段精心构造的洞利字符串,服务器就乖乖执行了攻击者想执行的序列代码。 拿ThinkPHP框架来说,化漏曾经有个漏洞,洞利攻击者构造一个恶意对象,序列利用`__destruct()`方法在对象销毁时触发文件删除。化漏就一行代码的洞利事,整个网站被删得干干净净。序列这不是化漏理论推导,是洞利真实发生过的灾难。 原理其实不复杂。PHP在反序列化时,如果类中定义了`__wakeup()`或`__destruct()`这样的魔术方法,就会自动调用。攻击者控制的是整个对象的结构,包括属性值。这些属性值一旦在魔术方法中被使用,比如拼接到SQL语句、文件路径、命令执行参数里,就完蛋了。 我见过最骚的操作是构造一个对象,让它的属性名恰好是某个类的私有属性名。PHP反序列化不检查访问权限,直接往里灌值。那些原本被封装得严严实实的内部状态,瞬间被攻击者捏成想要的形状。 利用链这东西,说白了就是找一串能串联起来的魔术方法。一个类的`__toString()`里调用了另一个类的方法,那个方法里又用了某个属性去执行命令。攻击者像拼乐高一样,把不同类拼成一条执行链。有些框架代码量大,类多,这种链子就特别好找。 防护手段倒是不少。最简单的,别反序列化用户输入。但现实是很多老项目图省事,把用户会话直接序列化存cookie。这时候只能靠白名单过滤类名,或者用`allowed_classes`参数限制反序列化范围。 PHP 7以后加了`unserialize()`的`allowed_classes`选项,能指定允许反序列化的类。但很多开发者根本不知道这参数存在,或者嫌麻烦不写。默认情况下,PHP反序列化任意类,就像把家门钥匙挂门口。 还有个坑是`__wakeup()`绕过。CVE-2016-7124这个漏洞,当序列化字符串中属性数量大于实际数量时,`__wakeup()`就不执行了。攻击者利用这点跳过安全检查,直接进入危险逻辑。 有个真实案例让我印象很深。某CMS系统,后台有个功能能导出数据,导出前把对象序列化存到临时文件。攻击者发现这个临时文件路径可控,就构造恶意序列化数据塞进去,然后诱导管理员触发反序列化。就这一下,服务器被提权了。整个攻击链没用到任何0day,全是代码里现成的功能拼起来的。 写代码的人当时肯定没想那么多。他只觉得序列化方便,传参省事。哪知道几年后,这些方便成了别人的后门。 排查这类漏洞时,我最喜欢看那些带`__destruct()`的类。这个魔术方法在对象生命周期结束时必然触发,不需要额外调用,是最稳定的利用点。配合文件操作函数,能玩出删库、写马、覆盖配置各种花样。 说实话,PHP这门语言在类型处理上太随意了,弱类型比较加上自动类型转换,给反序列化漏洞提供了不少土壤。攻击者可以用字符串代替数组,用数字代替布尔值,把类型混淆玩得飞起。 修复这类漏洞没有银弹。代码审计得仔细,反序列化入口要少开,数据要过滤。真要给个建议,那就是把用户能控制的任何输入都当敌人,包括那些藏在cookie和session里的序列化内容。
-
上一篇
-
下一篇
- 随机阅读
- 搜索
-
- 友情链接
-