无参数读文件和RCE

姿势一

题目背景:ctfshow命令执行 web40

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGFtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

<?php
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}

 

仔细看一下题目会发现过滤的是中文的括号!!!下面来一个个拆开说一下payload,首先看看需要用到的函数

localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
pos():返回数组中的当前元素的值。
array_reverse():数组逆序
scandir():获取目录下的文件
next(): 函数将内部指针指向数组中的下一个元素,并输出。

第一步,先用 pos(localeconv())获得点号(.)

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

第二步scandir(pos(localeconv())),即scandir(.),意思是获取当前目录下的文件。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

第三步,明确flag.php所在的地方为倒数第二个数组,利用array_reverse(),将数组逆序,即

array_reverse(scandir(pos(localeconv())))

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

第四步用next()函数将指针指向数组的下一个元素,并输出,即指向flag.php 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

最后用 highlight_file高亮该文件就ok了。

 

下面的东西也是参照yu师傅博客得到的一些做题的思想,利用session,开始前先来了解游一些函数吧。

session_start()  启动新会话或者重用现有会话

session_id()      获取/设置当前会话 ID

在cookies处将PHPSESSID的值修改为ls

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 然后输出?c=session_start();system(session_id());获取当前目录下的文件名

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16 

然后再把PHPSESSID的值修改为flag.php,传入我们的payload:

?c=session_start();highlight_file(session_id());

 其它题可以这样子,但是这题是行不通的,受php版本影响 5.5 -7.1.9均可以执行。

session_id规定为0-9,a-z,A-Z,-中的字符。在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的。
 

姿势二

题目背景:长安战疫杯的RCE_No_Para

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

代码解析:

preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])

preg_replace是执行正则搜索,如果搜索到则替换为空。

\W是匹配非数字、字母、下划线, [^\W]则是非\W的东西,即数字、字母、下划线,相当于小写的\w。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

正则表达式 – 元字符 | 菜鸟教程

 

然后难点是(?R)?,意思为递归整个匹配模式。

举个例子:

a()      #递归零次

a(b())     #递归一次

a(b(c)())   #递归两次

上面这些都可以被匹配到

所以该正则的含义是将匹配到的数字、字母、下划线替换为空,内部可以无限嵌套相同的模式,最后是否剩下;

做着题的时候也只是想到利用

?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));这种方式来

(详解在另一篇博客,ctfshow 命令执行的web40)

但是scandir被禁用了,想着想着换成getcwd试试,不过这个函数只返回路径

然后找着php文档搜函数,期间搜到过get_defined_vars(),发现有个返回全局get变量的地方,但是不会用.......

 

最后还是看了师傅们的wp得了正确的解法: 

利用get_defined_vars()函数返回可控的值。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

该函数会返回全局变量的值,get、post、cookie...的数据 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

有一个要注意的点,因为a=>phpinfo()是在GET这个数组里面,所以用pos取两次数组得得到值。

PHP pos() 函数 | 菜鸟教程

 

第一次,取出GET数组:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

第二次,在GET数组中取出a的值:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAWnJlZGVtYW5K,size_20,color_FFFFFF,t_70,g_se,x_16

 

到这里差不多就ok了,既然这个phpinfo()可控,pos(pos(get_defined_vars()));又可以过正则,那我们直接把phpinfo()换成system执行命令就好了。

payload:

?a=system('cat flag.php');&code=eval(pos(pos(get_defined_vars())));

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值