BUUCTF:[安洵杯 2019]easy_serialize_php 反序列化字符串逃逸漏洞深度解析
1. 漏洞背景与场景还原这道来自BUUCTF安洵杯2019的题目典型地展示了PHP反序列化漏洞中一个精妙的攻击手法——字符串逃逸。题目环境模拟了一个简单的图片查看功能用户可以通过show_image功能查看指定图片。表面上看系统对用户输入进行了严格过滤但实际上存在致命的设计缺陷。我们先来看关键代码逻辑当访问/index.php?fhighlight_file时服务器会返回源码。核心漏洞点出现在filter()函数中它使用preg_replace过滤了包含php、flag等关键词的内容。而extract($_POST)这个危险函数使得攻击者可以通过POST请求覆盖已有变量。最致命的是系统先将$_SESSION序列化经过过滤后再反序列化这个处理流程为字符串逃逸创造了条件。我曾在实际渗透测试中遇到过类似场景某CMS系统在保存用户配置时先序列化数据然后进行关键词替换结果导致攻击者可以通过精心构造的payload突破原有数据结构。这种漏洞往往被开发者忽视因为它需要同时满足多个条件才会触发。2. 反序列化字符串逃逸原理2.1 序列化字符串结构解析PHP的序列化字符串有严格的格式要求。比如一个数组序列化后是这样的a:3:{s:4:user;s:5:guest;s:8:function;s:10:show_image;s:3:img;s:20:Z3Vlc3RfaW1nLnBuZw;}其中a:3表示这是一个包含3个元素的数组s:4:user表示键是长度为4的字符串users:5:guest表示值是长度为5的字符串guest这种结构化的数据格式使得PHP在反序列化时会严格按照长度标识来解析数据。如果我们在过滤过程中改变了字符串的实际长度但不更新长度标识就会导致反序列化程序误读后续内容。2.2 过滤函数导致的长度不一致题目中的filter()函数会移除所有匹配/php|flag|php5|php4|fl1g/i的内容。比如字符串phphacker经过过滤后会变成hacker长度从9变成了6。但序列化字符串中的长度标识s:9:phphacker仍然保持原样这就产生了3个字节的差异。这种长度标识与实际内容的不匹配就是字符串逃逸漏洞的核心。攻击者可以利用这个差异精心构造payload使得反序列化时解析边界发生偏移从而注入恶意数据。3. 漏洞利用链完整分析3.1 关键利用点梳理通过审计源码我们发现几个关键利用点extract($_POST)允许覆盖$_SESSION中的变量filter()函数会对序列化后的字符串进行内容过滤最终通过file_get_contents读取图片内容攻击链可以这样构造通过POST传入精心设计的$_SESSION数据这些数据在序列化后会被过滤处理过滤导致的字符串长度变化引发解析错位最终控制img参数实现任意文件读取3.2 实际漏洞利用过程让我们通过具体payload来理解这个漏洞。假设我们传入以下POST数据_SESSION[flagphp];s:6:mochu7;s:3:img;s:20:L2V0Yy9wYXNzd2Q;}这个payload经过序列化后会变成a:3:{s:7:flagphp;s:49:;s:6:mochu7;s:3:img;s:20:L2V0Yy9wYXNzd2Q;};...}当filter()函数处理时如果flagphp中的某些字符被过滤比如包含php就会导致实际字符串变短但长度标识不变。例如过滤掉php后字符串实际长度可能减少了3个字节但s:49这个长度标识仍然存在。这种错位会导致反序列化时后续的内容被错误解析。原本属于值的部分可能被当作新的键值对来解析。通过精心设计我们可以逃逸出原有的数据结构注入一个新的img键从而控制文件读取路径。4. 漏洞防御与修复方案4.1 安全编码建议针对这类漏洞我总结了几点防御建议避免危险函数组合不要在使用serialize()后对结果进行内容替换。如果必须过滤应该在序列化前处理原始数据。严格处理用户输入extract()函数极其危险应该避免使用。必须使用时要设置EXTR_SKIP等安全选项。使用JSON替代序列化对于简单数据传输JSON是更安全的选择它没有PHP序列化的那些特性。实施完整性校验可以在序列化数据后添加HMAC签名确保数据未被篡改。4.2 实际修复案例在某次代码审计中我发现类似漏洞后建议的修复方案是// 修复前 $data filter(serialize($_SESSION)); // 修复后 function safe_filter($array) { foreach($array as $k$v) { $array[$k] preg_replace(/php|flag/i, , $v); } return serialize($array); } $data safe_filter($_SESSION);这个修复的关键点是先过滤内容再序列化避免了序列化后字符串被修改导致的结构破坏。5. CTF解题技巧与实战心得在CTF比赛中这类反序列化题目很常见。我总结了一些解题技巧关注过滤函数看到preg_replace等过滤函数要特别注意计算过滤前后字符串长度变化构造精确payload使用占位符计算好逃逸所需的字符数比如需要逃逸20个字节就构造能产生20字节差异的payload分步验证先在本地测试payload效果确认反序列化后的数据结构是否符合预期利用注释符有时候在payload末尾添加}或;可以帮助闭合数据结构记得有一次比赛我花了3小时才意识到长度计算错误。后来发现用这个公式很有效需要逃逸的字节数 原始payload长度 - 过滤后payload长度掌握这个计算技巧后构造payload就变得容易多了。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2528847.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!