前言
无参RCE,顾名思义就是当我们不能传入参数的情况下进行命令执行,因为一般情况下命令执行必须是要含有参数的,本文会就着无参RCE问题带大家学习CTF中常见的无参RCE方式及用法,下面我们展开文章来讲解一下。
基础知识
首先我们要了解,什么时候才会考虑无参RCE这种方法,我们先看下面的代码:
<?php
if(';' === preg_replace('/[a-z,_]+((?R)?)/', NULL, $_GET['exp']){
eval($_GET['exp']);
}
?>
简单分析一下代码里面的含义,首先让我们通过GET方式传入exp,之后会进行匹配,若我们传入的值带(),那么会被替换成空,同时正则表达式是递归调用的,我们传入的值会随着匹配次数慢慢变短。
了解了以上知识,我们来学习一下如何绕过吧。
getallheaders()
这个函数根据菜鸟教程里的解释可以理解为包含当前请求所有头信息的数组,当我们传入这个函数后,可以查看回显:
可以看到我们header头信息确实一数组的形式打印出来了,但是数组我们是不能用的,所以要想办法找到可以转换数组的函数,这里也有好几种方法,这里就简单说一下:
impload
该函数将一维数组的值转换成连续的字符串,这里我们就有思路了,因为上面函数是转换报文头为数组,而这个则是讲数组转换成字符串,这不就完美绕过了,只需在报文最后加上恶意代码即可。
end
该函数作用是取出数组的最后一位,以字符串形式返回,可以想到,我们也可以利用这个函数,我们可以用输出函数里包裹这个,只需放在保温最前面或者最后面即可。
get_defined_vars()
根据菜鸟教程里的解释,该函数也是返回所有一定义变量的数组,需要注意的是返回的是一个二维数组,那么我们上面的方法就不能用了,下面介绍一个新的函数current(),该函数可以返回数组中的单元且初始指针指向数组的第一个单元,正好是GET方式传入的第一个元素我们就可以用这个函数先转换成一维数组,在进行POC的构造:
?exp=eval(end(current(get_defined_vars())));&shell=phpinfo();
session_id()
这个方法就跟上面的不太一样了,我们需要将恶意代码卸载cookie的phpsession里,然后通过这个来进行读取,可能有一些抽象,一会会进行演示
我们要先知道必须得先开启session才可以使用该方法,我们常用的payload如下:
hex2bin(session_id(session_start()));
因为session里面的值不能直接传入,这里要加一步16禁止编码才行得通:
于是我们最终的payload如下:
?exp=eval(hex2bin(session_id(session_start())));
其中hex2bin为16进制解码的函数,因为我们之前进行了一次16进制的编码,这里不要忘记了。
例题
题目源码如下:
可以大体的看到分为三关,需要我们分别绕过,首先我们要知道flag文件叫什么,localeconv()函数能够返回包含本地数字及货币格式信息的数组,该数组的第一个元素就是’ . ',我们需要通过
scandir('.')
来查看当前目录文件,既然localeconv函数可以返回数组且第一个元素为我们想要的,所以结合前面知识构造:
?exp=var_dump(scandir(current(localeconv())));
得知flag在flag.php里,接下来考虑如何构造,因为数组索引为3,这里考虑通过next函数配合array_reverses来讲数组倒序,配合高亮函数来进行解题:
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
最终得到flag。
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享