第二十九题——[网鼎杯 2020 青龙组]AreUSerialz

题目地址:https://buuoj.cn/challenges

解题思路,

第一步:进入题目,看到提示源码

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

}

第二步:代码审计

  1. 前一部分是对FileHandler这个类进行定义,注意这里的process函数,对op参数进行判断,为1调用写函数,为2调用读函数,并将读的结果输入到输出函数中。
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!");
        }
    }
  1. 由于我们需要获取flag,需要进入到读函数中,而读函数会将类里面的filename参数指定的文件进行读取。
private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }
  1. 后半段则是本页面的参数传递,传递一个str参数,并对参数里的值进行is_valid函数检测,从看看里面的每个值的ascii是否在32-125之间,通过后进行反序列化,注意这里反序列化会调用析构函数__destruct(),将op值置为1

第三步:构造str参数

  1. 我们需要让类里面的op保持为2,且filename=flag.php,为此需要绕过析构函数,析构函数里面使用的是===(全等),数值类型以及大小都相等才等,而process里面使用的是==,值相等就行,php自动将类型转化为一致的,所以我们需要让FileHandler类里面的op为int型2即可,因为2!===‘2’但是2==‘2’
  2. 生成序列化,由于要进行is_valid函数检测,但是FileHandler类成员变量为protect,生成序列化时会有\0*\0无法通过检测。解决办法:可以使用public代替protect,因为php7+对成员类型检测不是很严谨。最终序列化结果:O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";},flag值为:flag{f4a045b0-1e20-4ec7-a49e-272211f8a2c7}
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值