PHP反序列化字符串溢出
目录
- 0x01:Track
- 0x02:字符串逃逸的特点
- 0x03:过滤后导致序列化字符串变长
- 0x04:过滤后导致序列化字符串变短
反序列化字符串逃逸常见于CTF中,所以在这里记录下
导致反序列化字符串逃逸的原因:是因为对序列化后的字符进行过滤,导致用户可控字符溢出,从而控制序列化内容,配合对象注入导致RCE。
0x01:Track
在学习反序列化字符串逃逸之前,首先要了解反序列化的一些小Track:
php在反序列化时,底层代码是以
;
作为字段的分隔,以;}
作为结尾,并且是根据长度判断内容的 ,同时反序列化的过程中必须严格按照序列化规则才能成功实现反序列化 。class A{public $T1 = '123';public $T2 = 'abc'; }$a = new A(); $b = serialize($a); echo $b; echo "\n"; var_dump(unserialize($b)); echo "\n";$bad = 'O:1:"A":2:{s:2:"T1";s:3:"123";s:2:"T2";s:3:"abc";}s:2:"T3";s:4:"test";}'; echo $bad; echo "\n"; var_dump(unserialize($bad));
可以看到,超出的部分并不会被反序列化成功,而是只序列化O:1:"A":2:{s:2:"T1";s:3:"123";s:2:"T2";s:3:"abc";}
的内容,这也就说明了在反序列化的时候是有一定的识别范围的,在这个范围之外的字符都会被忽略,不会影响反序列化的正常进行。而且可以看到反序列化字符串都是以";}
结束的,那如果把";}
添入到需要反序列化的字符串中,就能让反序列化提前闭合结束,后面的内容也就自然读取不到,从而添加我们想要反序列化的数据。元素长度必须一致,这是因为反序列化时,反序列化引擎是根据长度来判断的,比如在反序列化的时候php会根据s所指定的字符长度去读取后边的字符。如果指定的长度错误则反序列化就会失败
反序列化是可以反序列化原本不存在的元素
0x02:字符串逃逸的特点
1.在数据进行序列化后进行了过滤
或者是字符替换
2.通过过滤或者字符替换导致字符串长度发生变化
0x03:过滤后导致序列化字符串变长
示例代码:
<?php
highlight_file(__FILE__);
#error_reporting(0);
function filter($str){return preg_replace( '/i/','ww', $str);
}
$login['name'] = $_GET['name'];
$login['money'] = '999';
$new = filter(serialize($login));
printf($new."</br>");
$last = unserialize($new);
var_dump($last);
if($last['money']<1000){echo "You need more money";
}else{echo file_get_contents('flag.php');
}
?>
以上代码的流程为,先序列化代码,然后再对不希望出现的字符进行过滤,将i替换成ww,然后进行反序列化,如果反序列化之后,money>1000,则读取flag.php。我们的要求是如何在不直接修改$money值的情况下间接修改$money的值,从而去读取flag。
我们先正常输入去触发过滤看看
可以看到,可以看到我们输入whoami被过滤替换为whoamww,但是长度还是6,这就导致后面的报错,因为我们在上面也提到:在反序列化的时候php会根据s所指定的字符长度去读取后边的字符。如果指定的长度s错误则反序列化就会失败。 而s
取决我们最原始的输入长度。
那我们想去修改money的值,我们就需要构造序列化后的字符,";s:5:"money";s:4:"1000";}
去闭合前面的序列化字符串,由于序列化字符串是以 ;}
作为结尾的,那么我们就可以去构造序列化字符串进行闭合,使得后面的字符";s:5:"money";s:3:"999";}
不被识别。
但是s指定长度必须与后面字符长度相匹配
,而我们构造的序列化字符";s:5:"money";s:4:"1000";}
,长度为26,我们分析代码已经知道了当输入一个i会替换成bb,如果我们输入26个i,那么就会被替换成52个bb,那么我们可以原始输入26个i,加上构造的反序列化字符串";s:5:"money";s:4:"1000";}
,刚好是52位。
原始输入:iiiiiiiiiiiiiiiiiiiiiiiiii";s:5:“money”;s:4:“1000”;} //52位字符
过滤替换:wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww //52位字符
可以看出,过滤的序列化字符已经被52个w填充了,使得构造的反序列化字符串";s:5:"money";s:4:"1000";}
成功逃逸,通过后续的反序列化修改了money的值,而原来的序列化字符";s:5:"money";s:3:"999";}
则会被忽略,因为序列化字符串是以 ;}
作为结尾的,我们已经在构造的字符串中进行闭合。
payload:
http://127.0.0.1/flag/index2.php?name=iiiiiiiiiiiiiiiiiiiiiiiiii";s:5:“money”;s:4:“1000”;}
由于file_get_contents读取到的是php代码的话,就只会返回源码,查看源代码,找到flag
0x04:过滤后导致序列化字符串变短
修改下源码
<?php
show_source("index.php");
#error_reporting(0);
function filter($str){return preg_replace( '/abc|zxhh/','', $str);
}
$login['name'] = $_GET['name'];
$login['pwd'] = $_GET['pwd'];
$login['money'] = '999';
$new = filter(serialize($login));
printf($new."</br>");
$last = unserialize($new);
var_dump($last);
if($last['money']<1000){echo "You need more money";
}else{echo file_get_contents('flag.php');
}
?>
可以看到,会通过数组的形式接收通过GET方式传进来的参数name和pwd,而money还是固定的,接着会将序列化后的字符进行过滤,这次是替换为空,也就是说,如果触发过滤,那么序列化字符串就会变短,这题还是考怎样去间接修改money的值,从而读取flag。
首先我们正常输入看看
首先我们会想到的还是通过";}
在";s:5:"money";s:3:"999";}
前去闭合,然后构造我们想要的序列化字符,将原始的money值挡在序列化字符串之外。
构造测试语句:http://127.0.0.1/flag/index.php?name=123&pwd=123";s:5:"money";s:4:"1000";}
发现并没有将我们构造的语句拼接到序列化中去,而是变成字符的形式,可以发现pwd的长度为29。这时,我们就要想到序列化的字符会进行过滤,当遇到abc或zxhh敏感字符就会替换为空。那我们这里就可以故意将敏感字符作为name的输入,通过替换为空来实现字符逃逸,如果输入7个abc后,name指定的字符依然不变,也就是说会空出24个字符,而这24个字符则会往后进行填充。那我们就可以在pwd补充字符,来将前面的序列化字符串变成name的内容,接着再在后面构造我们需要的序列化字符。
payload:
http://127.0.0.1/flag/index.php?name=abcabcabcabcabcabcabc&pwd=123";s:5:“money”;s:4:“1000”;s:8:“Keepb1ue”;s:4:“1000”;}
构造payload我们只需要算出需要填充多少字符即可,";s:3:"pwd";s:
长度是不变的,我们需要考虑的是pwd的值的长度,比如我们输入的是8个abc,那就是会空出24个字符,那么就需要往name值填充24个字符,而";s:3:"pwd";s:
已经占了14个字符,加上s指向的长度,整条payload的长度一般是没有超过100的,也就是长度为2,所以也就是";s:3:"pwd";s:xx:"
,长度为18,所以我们只需要在pwd输入6个字符即可。
构造payload:
http://127.0.0.1/flag/index.php?name=123abcabcabcabcabcabcabcabc&pwd=123456";s:5:“money”;s:4:“1000”;s:5:“mone3”;s:4:“1000”;}
这里有人会发现多出来个s:5:"mone3";s:4:"1000"
,这是因为序列化元素为3个,而pwd元素我们已经填充到name的值中去了,所以需要在加一个元素。
PHP反序列化字符串溢出相关推荐
- php反序列化--字符串逃逸
php反序列化–字符串逃逸 PHP反序列化的字符串逃逸,一共分有两种情况,情况一:过滤后字符串变多,情况二:过滤后字符变少(本篇文章默认已有反序列化相关知识基础) 过滤后字符串变多 以ctfshow- ...
- 浅析php反序列化字符串逃逸
前言: php反序列化字符串逃逸之前没有详细的学习过,所以遇到题目看的有点懵,这次好好学习一下. 反序列化的特点 首先要了解一下反序列化的一些特点: php在反序列化时,底层代码是以 ; 作为字段的分 ...
- [0CTF 2016]piapiapia php反序列化字符串逃逸
一.php反序列化字符串逃逸 <?phpclass user{public $user = 'admin';public $pass = 'passwd'; }$a = new user(); ...
- 序列化 与 反序列化 字符串 实例
转自:http://www.cnblogs.com/sky1024/articles/917108.html 一个实体类 [Serializable] public class MyObject { ...
- PHP反序列化字符串逃逸
例题可看:https://www.cnblogs.com/v2ish1yan/articles/16118319.html 今天才学的,做个记录. 字符串逃逸分为两种,减少和增多. 主要是通过一个pr ...
- java 自定义反序列化_java – 使用类字段中指定的自定义反序列化器反序列化字符串...
我需要编写一个方法,它接受一些对象,一些字段名称fieldName存在于给定对象的类中,以及一些字段值.该值是字段的 JSON序列化形式.该方法应取值并相应地反序列化,如下所示: static voi ...
- 关于atoi和atol转换超过10位数字字符串溢出问题
一.问题 atoi( const char *str )和atol(const char *str )转换超过10位的字符串,转换失败 二.分析 atoi函数返回的int取值范围:-214748364 ...
- Newtonsoft 反序列化字符串
string json="[{"name":"zhangsan","age":"12"},{"nam ...
- c#将对象序列化为字符串和将字符串反序列化为对象
asp.net开发中,页面间传值最长用到的是url显式传参,session,application和cookie传值等.对于复杂对象页面传值,如果不考虑性能影响的话,通常可以使用session或者ap ...
- php序列化中文,详解之php反序列化
1 前言 最近也是在复习之前学过的内容,感觉对PHP反序列化的理解更加深了,所以在此总结一下 2 serialize()函数 "所有php里面的值都可以使用函数serialize()来返回一 ...
最新文章
- Scrum中文网-疫情之下2021敏捷年度状态报告十大看点
- Nodejs学习笔记之复制文件
- 如何让Jupyter Notebook支持pytorch、tensorflow
- 【luogu P1558 色板游戏】 题解
- 近期“速卖通母婴行业需求暴增”,带你了解母婴行业选品趋势
- CVPR 2022 | 利用域自适应思想,北大、字节跳动提出新型弱监督物体定位框架
- 【渝粤教育】国家开放大学2018年春季 7397-21T家庭教育咨询与辅导 参考试题
- 低幼年龄段在线教育白皮书
- Azure SQL Database (1) 用户手册
- linux 测试网络_Linux后台开发:Linux命令系列18-ping测试网络
- BZOJ 2243: [SDOI2011]染色(树链剖分)
- 负载均衡算法及手段(转)
- python3.6 asyncio_python3.6以上 asyncio模块的异步编程模型 async await语法
- linux支持ext2格式吗,linux正统标准文件系统ext2详解
- PHP图片与文字合成
- iec61508最新2020_IEC61508标准
- 石家庄地铁线路查询系统(补)
- 数学建模学习(98):CHIO优化算法
- 如何使用MATLAB绘制ggplot风格图片(散点图及折线图)
- 信道特征(码元、比特、波特率等概念)