命令执行漏洞学习笔记
原理
应用中用到外部命令或程序,参数需要用户输入时,没有对用户的输入做检查,造成执行了预期之外的命令。举个栗子,下面是一个返回ping结果的程序,直接将用户可控的ip这个参数拼接进了命令,就可以提交其他的命令,从而造成命令执行
1 |
|
相关函数
php中能调用外部命令的常见函数如下:
1 |
|
利用方法
分号;
用分号可以分隔多条命令,命令按照从左到右的顺序执行。当一条命令执行失败时,不会中断其他命令的执行
1 |
|
管道命令|
管道符可以将前一个命令的标准输出变成后一个命令的标准输入,当前一个命令执行失败后,会执行后一个命令。ip的位置输入1是为了让ping报错,从而立即执行后一条命令。
1 |
|
后台任务符号&
此符号的作用是使shell在后台执行该条命令,这个命令有个缺陷就是两个命令的输出会混淆在一起
1 |
|
逻辑与&&
按顺序执行命令,命令之间是逻辑与关系,只有前面的命令执行成功后才会执行后面的命令
1 |
|
逻辑或||
按顺序执行命令,命令之间是逻辑或关系,前面的命令执行失败后才会执行后面的命令
1 |
|
反引号`
将一个命令将被执行时,会首先解析反引号之间的内容,比如”echo `whoami`“,会先执行whoami
,再echo
出来
$(command)命令执行
作用同反引号,也是先执行括号中的内容,再将结果和前面的命令一起执行
1 |
|
win命令连接符
| & || &&
跟linux一样
回显敏感信息
win下
1 |
|
linux下
1 |
|
无回显利用方法
碰到命令执行,有回显的情况是少数,大多数情况都是无回显。这里分享一些无回显时的攻击方法。首先要判断是否存在命令执行漏洞,可以利用sleep命令,payload比如ip=|sleep 5
,如果延迟5秒返回了结果,则存在漏洞。
带外通信 - dnslog
dnslog是一个通过dns查询将信息外传的方法。简单的说,将需要外传的信息附在dns查询上,最终的查询肯定会请求到自己掌控的dns域上,就可以看到相应的dns请求,从而获得附在dns查询上的信息。并且dns查询不像http请求那样容易被检测到,隐蔽性好。
1 |
|
发起ping命令即可发出dns请求,就能在dnslog平台上看到外传的信息
写webshell
如果存在漏洞的页面是web服务或者说存在漏洞的服务器上运行着web服务器,且有权限写入,可以利用shell命令写入webshell后门到网站目录,访问即可获得webshelll
1 |
|
这里用了base64将一句话木马加密了,可以绕过部分waf的检查
http访问日志
最基础的一种方法,在自己的服务器上起一个http服务器,只要有请求访问就有日志,把要外传的信息跟在http请求中访问自己的http服务器,即可在访问日志中查看到要接收的信息。http服务器话,可以用python起一台小型web服务器,非常方便。
1 |
|
如下图,用curl发起http请求,带上whoami
的查询结果。下面web访问日志中的www-data
就是对应whoami
的执行结果。
1 |
|
同样也可以用wget
1 |
|
nc传文件
一般服务器上都有netcat命令,可以利用这个命令发送文件到远程服务器上。比如,在自己的服务器上运行监听9999端口的命令:
1 |
|
在存在命令执行漏洞的服务器上执行发送文件的命令:
1 |
|
nc反弹shell
反弹shell是从内部的受控端(也就是存在命令执行漏洞的服务器),主动连接外部远程服务器,所以防火墙一般不会拦截。
自己的服务器上nc监听命令:
1 |
|
存在命令执行漏洞的服务器上反弹shell,每种编程语言都可以用sock发送请求,这里只演示最基础的bash反弹shell
1 |
|
如果有waf拦截,可以把语句base64加密后再在存在漏洞的服务器上执行
上面语句用base64做一下变形:
1 |
|
vps上监听并得到一个反弹shell:
极端情况
- 服务器未联网
- 无回显
- 无法利用上述的无回显命令执行姿势
- 无写入权限
- 各种未知原因无法getshell
- 等等…
如果不幸碰到上述情况,那么最后只有一种方法,尝试一下枚举or二分法爆破文件内容,主要利用sleep命令时间盲注,自己写个脚本跑一下
防御方案
- 不执行外部的应用程序或命令,尽量使用自定义的函数或开源的函数库来实现相应的功能
- php可以使用
escapeshellarg
和escapeshellcmd
这两个函数来转义用户的输入 - 使用safe_mode_exec_dir设置可执行的文件目录。将php.ini中的safe_mode设置为On,然后将允许执行的可执行文件放入一个目录,并使用safe_mode_exec_dir指定这个可执行的文件路径。这样在执行相应的外部程序时,比如在safe_mode_exec_dir指定目录中才会允许执行,否则将执行失败
- 把
system
、exec_shell
等命令加入disable_functions(也会被绕过)
命令相关知识
()和{}
把几个命令合在一起执行,shell中有两种方法:
- (command1;command2;command3;…)
- { command1;command2;command3;…command;}
注意使用{}时第一条命令必须与左边括号有一个空格,最后一条命令一定要有分号。
并且()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令。
不同点是:()是重新开一个子shell执行命令,{}在当前shell执行。
1 |
|
shell输入输出重定向
大多数 UNIX 系统命令从终端接受输入并将所产生的输出发送回到终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。
命令说明:
- command > file:输出重定向到file。
- command < file:输入重定向到file。
- command >> file:输出以追加的方式重定向到file。
- n > file:将文件描述符为n的文件重定向到file。
- n >> file:将文件描述符为n的文件以追加的方式重定向到file。
- n >& m:将输出文件m和n合并。
- n <& m:将输入文件m和n合并。
- << tag:将开始标记tag和结束标记tag之间的内容作为输入。
此外,文件描述符通常是这样的:
- 0:标准输入(STDIN)
- 1:标准输出(STDOUT)
- 2:标准错误输出(STDERR)
正则
- ^:匹配输入字符串的开始位置
- $:匹配输入字符串的结束位置
- *:匹配前面的子表达式零次或多次
- +:匹配前面的子表达式一次或多次
- ?:匹配前面的子表达式零次或一次
- {n}:n是一个非负整数,匹配确定的n次
- {n,}:n是一个非负整数,至少匹配n次
- {n,m}:m、n均是非负整数,并且n<=m,最少匹配n次,最多匹配m次
- .:匹配除换行符(\n,\r)以外的任何单个字符
- [xyz]:字符集合,匹配所有包含的任意一个字符
- 非贪婪?:当?紧跟在任何一个其他限制符(*,+,?,,{n},{n,},{n,m})后面时,匹配是非贪婪的,非贪婪模式是指尽可能少地去匹配。
1 |
|
{xxx}和[xxx]有个重要区别,如果匹配的文件不存在,[xxx]会失去模式的功能,变成一个单纯的字符串,而{xxx}还是可以展开。
1 |
|
内置通用字符簇
也是shell正则的知识
- [[:alpha:]]:任何字母
- [[:digit:]]:任何数字
- [[:alnum:]]:任何字母和数字
- [[:space:]]:任何空白字符
- [[:upper:]]:任何大写字母
- [[:lower:]]:任何小写字母
- [[:punct:]]:任何标点符号
- [[:xdigit:]]:任何16进制的数字,相当于[0-9a-fA-F]
绕过姿势
空格绕过
- <>
1 |
|
- $IFS(IFS的默认值是空白,也包括空格,tab,新行)
1 |
|
关键词绕过
- $
1 |
|
- 反斜杠
1 |
|
- 变量拼接
1 |
|
- 利用切割字符串拼凑
1 |
|
特殊变量
$1到$9、$@和$*等,相当于空字符串
1 |
|
base64编码
1 |
|
16进制
1 |
|
8进制
1 |
|
双引号和单引号
1 |
|
幂符号^
这种方法只是用于win的cmd下,用法和引号类似,也是加在命令字符之间不会影响命令的执行,但我测试发现在两个字符之间只能插入一个^
,不然执行命令会报错
1 |
|
花括号{}
1 |
|
cat绕过
读取文件的命令cat被禁时,有很多同替的命令
1 |
|
上边的命令执行后,都可以在输出结果中看到flag
而od命令可通过添加-c
选项输出字符串内容:
1 |
|
通配符绕过
1 |
|
其他
1 |
|
命令长度限制绕过
比如服务器代码如下:
1 |
|
嵌套eval
payload如下:
1 |
|
文件构造绕过
通常利用ls -t
、>
、>>
和换行符\
绕过长度限制
使用ls -t命令,可以将文件名按照时间顺序排列出来(后创建的排在前面)
使用>,可以将命令结果存入文件中
使用>>,可以将字符串添加到文件内容末尾,不会覆盖原内容
使用换行符\,可以将一条命令写在多行
组合起来原理如下:
1 |
|
- 先创建文件名可以连接成要执行命令的空文件(由于ls -t命令,所以要倒序创建文件)
1 |
|
注意这里使用两个反斜杠是因为,前面说到了在命令后面加上一个反斜杠可以将一条命令写在多行,而第一个反斜杠就是为了转义这个反斜杠,从而让文件名中存在一个反斜杠
- 执行
ls -t aaa>cmd
,将目录下的文件名按时间排序后写进cmd文件中,如果创建空文件时,创建了点.开头的文件,上边命令要添加-a选项将隐藏文件也写入cmd,即ls -at aaa>cmd
可以查看cmd文件的内容如下,组合起来就是cat flag.php
- 执行
sh cmd
命令,从cmd文件中读取命令来执行
内联命令绕过关键词
可以使用反引号ls的输出作为cat的输入来绕过文件关键词,比如当前目录下有一个flag,但flag
这个关键词被禁用了,就在可以这样绕过
1 |
|
审计技巧
待填坑…