服务器端包含注入(SSI)

之前没见过这种漏洞(菜鸡……),运维赛遇到了正好学习下,记录下来。

1、关于SSI

SSI是英文"Server Side Includes"的缩写,翻译成中文就是服务器端包含的意思。SSI是嵌入HTML页面中的指令,在页面被提供时由服务器进行运算,以对现有HTML页面增加动态生成的内容,而无须通过CGI程序提供其整个页面,或者使用其他动态技术。从技术角度上来说,SSI就是在HTML文件中,可以通过注释行调用的命令或指针,即允许通过在HTML页面注入脚本或远程执行任意代码。

在网站上,每个网页都有重复的材料。例如,每个讲义页面顶部都有一个导航栏,其中包含指向网站主要组件的链接。当然可以将重复的项目复制/粘贴到每个页面,但这使维护变得非常困难:如果决定更改公共内容,必须编辑每一页,必须确保不会错过任何一个页面并且以同样的方式编辑它们。例如,在您的网站上添加可从导航栏访问的新部分需要更改每一页!对于一个小网站来说,这很糟糕,但对于一个大型网站来说,这是完全不合理的。

比较理想的解决方案是将页面分成多个部分,每个部分存储在不同的文件中,并让服务器在响应网页请求时将它们拼凑在一起。该技术称为 服务器端包含也就是SSI。如何使用它取决于服务器软件,在CS Web服务器上,使用Apache来提供Web页面。假设我们有三个页面,A,B和C,所有页面都应该共享一个公共页眉和页脚,每个页面都在一个单独的文件中。这些共享的部分将包含在主页中。因此,我们有五个文件,其中没有一个是完整的页面:

  • SSI / A.html
  • SSI / B.html
  • SSI / C.html
  • SSI / header.part
  • SSI / footer.part

在上面的列表中,有两种文件:

  • .html这种文件包含 另一个文件作为其自身的一部分。这些.html文件是容器文件,因此它们具有所有常用的基础结构:它们以doctype元素开头并具有类似的标记htmlhead等等。
  • .part这种文件包含 在另一个文件中。它只是网页的一个片段,例如只是导航栏或只是页脚。它不会有一个doctype元素,因此,它不是一个有效的HTML文档。

在HTML文件A,B和C的源代码中,我们放置了一个特殊的标记,称为指令,服务器将查找并替换所包含文件的内容。该指令看起来像一个HTML注释,因此如果SSI由于某种原因没有发生,该指令将不会弄乱您的代码。看看A的源代码页面:

<!--#include virtual="header.part" -->

<p>Here is some content that is unique to <strong>page A</strong> of the website.

<!--#include virtual="footer.part" -->

virtual之后的引号中的文本是要包含在主文件中该点的文件的相对URL。

注意,如果查看源文件ssi/A.html,并不会看到这些指令。相反,将看到包含的内容。服务器服从指令并从部件构造页面并将其发送出去,浏览器无法知道原始文件是什么,甚至根本不涉及SSI也就是说SSI完全不可见。

2、SSI漏洞

Server-side Includes服务器端包含提供了一种对现有HTML文档增加动态内容的方法。apache和iis都可以通过配置支持SSI,在网页内容被返回给用户之前,服务器会执行网页内容中的SSI标签。在很多场景中,用户输入的内容可以显示在页面中,比如一个存在反射XSS漏洞的页面,如果输入的payload不是xss代码而是ssi的标签,服务器又开启了ssi支持的话就会存在SSI漏洞。

3、SSI注入的条件

当符合下列条件时,攻击者可以在 Web 服务器上运行任意命令:
A. Web 服务器已支持 SSI(服务器端包含)。
B. Web 应用程序在返回 HTML 页面时,嵌入用户输入。
C. 参数值未进行输入清理。
例如,如果脚本接收文本输入,供 Web 服务器稍后处理,下列由 SSI 命令组成的输入便会侵害服务器的安全:
<!--#include file=""...""-->(会显示给定的文件)
<!--#exec cmd=""...""-->(会执行给定的 shell 命令)

4、SSI注入命令

命令格式:

<!--#directive parameter=value parameter=value -->

https://www.owasp.org/index.php/Server-Side_Includes_(SSI)_Injection

几个常用的命令:

<!--#include file="included.html" -->
<!--#include virtual="/directory/included.html" -->
<!--#exec cmd="ls" -->
<!--#exec cmd="ls -l" -->
<!--#exec cmd="ls.." -->

用到最多的是包含命令,也就是我们前边网站例子中提到的,详细说一下包含命令:

include命令的标题下有两个参数。这些参数与HTML标记下的属性非常相似。一个例子是FONT标签下的SIZE属性。

任何include命令行的格式如下所示:

<!--#include file="included.html" -->

命令(如“include”)之后是参数(如“file”),然后是“file”表示的内容。

遵循以下规则:

  • 命令和参数使用小写字母
  • 该值附近的双引号是必需的
  • 没有空间,直到命令后
  • 哈希标记(#)是必需的
  • 在第二个双引号之后,在第二个双连字符之前有一个空格(在结尾处)

为什么使用“file =”?当将包含的文件保存在与调用它的文件相同的目录中时,使用“file =”。当文件位于包含调用它的文件的目录的子目录中时,也可以使用file参数。

关于虚拟参数:

如果要调用的文件位于需要从服务器根目录开始的地址的位置,则可以使用virtual参数。这是一种学术方式,说该文件与调用它的页面不在同一目录中。也许会设置一个包含所有包含文件的目录,如果是这样,那么将使用虚拟参数将SSI命令附加到文件。只需给出命令从服务器根目录(域名)的路径。像这样:

<!--#include virtual="/directory/included.html" -->

在第一个目录之前的正斜杠代表域名(服务器根目录)。通过使用该前导斜杠,服务器将添加域名到地址的前面。

其他:

Directive Parameters Description Example
include file or virtual This is probably the most used SSI directive, allowing the content of one document to be transcluded in another. The file or virtual parameters specify the file (HTML page, text file, script, etc.) to be included. Includes the contents of another file or the result of running a CGI script. If the process does not have access to read the file or execute the script, the include will fail. "virtual" specifies the target relative to the domain root, while "file" specifies the path relative to the directory of the current file. When using "file" it is forbidden to reference to absolute paths. Higher directories (..) are usually forbidden, unless explicitly configured. The Apache documentation recommends using "virtual" in preference to "file". <!--#include virtual="menu.cgi" -->
or
<!--#include file="footer.html" -->Apache tutorial on SSI stipulates the format requires a space character before the "-->" that closes the element.
exec cgi or cmd This directive executes a program, script, or shell command on the server. The cmd parameter specifies a server-side command; the cgi parameter specifies the path to a CGIscript. The PATH_INFO and QUERY_STRING of the current SSI script will be passed to the CGI script, as a result "exec cgi" should be used instead of "include virtual". <!--#exec cgi="/cgi-bin/foo.cgi" -->
or
<!--#exec cmd="ls -l" -->
echo var This directive displays the contents of a specified HTTP environment variable. Variables include HTTP_USER_AGENT, LAST_MODIFIED, and HTTP_ACCEPT. <!--#echo var="REMOTE_ADDR" -->
config timefmt, sizefmt, or errmsg This directive configures the display formats for the date, time, filesize, and error message (returned when an SSI command fails). <!--#config timefmt="%y %m %d" -->
or
<!--#config sizefmt="bytes" -->
or
<!--#config errmsg="SSI command failed!" -->
flastmod or fsize file or virtual These directives display the date when the specified document was last modified, or the specified document's size. The file or virtual parameters specify the document to use. The file parameter defines the document as relative to the document path; the virtual parameter defines the document as relative to the document root. <!--#flastmod virtual="index.html" -->
or
<!--#fsize file="script.pl" -->
printenv This directive outputs a list of all variables and their values, including environmental and user-defined variables. It has no attributes. <!--#printenv -->
Directive Parameters Description Example
if expr Used for condition tests that may determine and generate multiple logical pages from one single physical page. <!--#if expr="${Sec_Nav}" -->
<!--#include virtual="" -->
<!--#endif -->
elif expr Serves the same purpose as further conditioning in programming languages. <!--#if expr="${Sec_Nav}" -->
<!--#include virtual="secondary_nav.txt" -->
<!--#elif expr="${Pri_Nav}" -->
<!--#include virtual="primary_nav.txt" -->
<!--#endif -->
else If none of the if and elif directive catches the present condition, things in here should happen. <!--#if expr="${Sec_Nav}" -->
<!--#include virtual="secondary_nav.txt" -->
<!--#else -->
<!--#include virtual="article.txt" -->
<!--#endif -->
endif See above for example.
set var, value Sets the value of a SSI variable. (Not supported by all implementations, although present in Apache httpd.) <!--#set var="foo" value="bar" -->

 

参考:

http://cs.wellesley.edu/~cs110/reading/SSI.html

https://www.cnblogs.com/jokermoon/p/6708691.html

https://en.wikipedia.org/wiki/Server_Side_Includes

https://www.htmlgoodies.com/beyond/webmaster/article.php/3473341/SSI-The-Include-Command.htm

http://httpd.apache.org/docs/current/howto/ssi.html