protobuf脱壳二进制漏洞总结
字数 1500 2025-08-22 12:22:15

Protocol Buffers (Protobuf) 二进制漏洞分析与利用

1. Protobuf 基础

1.1 简介

Protocol Buffers (简称 Protobuf) 是由 Google 开发的一种语言中立、平台中立的可扩展序列化结构数据的方法。它是一种高效的协议,常用于网络通信、数据存储和应用程序间的数据传输。

1.2 环境搭建

sudo apt-get update
sudo apt-get install -y protobuf-compiler libprotobuf-dev
sudo apt-get install libprotobuf-c-dev protobuf-c-compiler

编译为C代码:

protoc --c_out=. user.proto

生成文件:

  • user.pb-c.h:头文件,定义消息类型及其相关函数
  • user.pb-c.c:源文件,实现序列化和反序列化等操作

编译为Python代码:

protoc --python_out=. demo.proto

生成 demo_pb2.py 文件

1.3 基本语法

// demo.proto
syntax = "proto3";
package tutorial;

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
  
  enum PhoneType {
    PHONE_TYPE_UNSPECIFIED = 0;
    PHONE_TYPE_MOBILE = 1;
    PHONE_TYPE_HOME = 2;
    PHONE_TYPE_WORK = 3;
  }
  
  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }
  
  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

2. Protobuf 逆向分析

2.1 关键逆向点

在生成的 demo-pb-c.c 文件中,反序列化函数:

Tutorial__AddressBook * tutorial__address_book__unpack (
    ProtobufCAllocator *allocator, 
    size_t len, 
    const uint8_t *data)
{
  return (Tutorial__AddressBook *)
    protobuf_c_message_unpack(&tutorial__address_book__descriptor, 
                            allocator, len, data);
}

2.2 Descriptor 结构体

struct ProtobufCMessageDescriptor {
  uint32_t magic;                /**< 1 */
  const char *name;              /**< 2 */
  const char *short_name;        /**< 3 */
  const char *c_name;            /**< 4 */
  const char *package_name;      /**< 5 */
  size_t sizeof_message;         /**< 6 */
  unsigned n_fields;             /**< 7 */
  const ProtobufCFieldDescriptor *fields; /**< 8 */
  const unsigned *fields_sorted_by_name; /**< 9 */
  unsigned n_field_ranges;       /**< 10 */
  const ProtobufCIntRange *field_ranges; /**< 11 */
  ProtobufCMessageInit message_init; /**< 12 */
  void *reserved1;              /**< 13 */
  void *reserved2;              /**< 14 */
  void *reserved3;              /**< 15 */
};

关键字段:

  • magic:通常为 0x28AAEEF9
  • n_fields:结构体中的字段数量
  • fields:指向字段描述符结构体

2.3 ProtobufCFieldDescriptor 结构体

struct ProtobufCFieldDescriptor {
  const char *name;             /**< 1 */
  uint32_t id;                  /**< 2 */
  ProtobufCLabel label;         /**< 3 */
  ProtobufCType type;           /**< 4 */
  unsigned quantifier_offset;   /**< 5 */
  unsigned offset;              /**< 6 */
  const void *descriptor;       /**< 7 */
  const void *default_value;    /**< 8 */
  uint32_t flags;               /**< 9 */
  unsigned reserved_flags;      /**< 10 */
  void *reserved2;              /**< 11 */
  void *reserved3;              /**< 12 */
};

字段说明:

  • name:字段名
  • id:唯一字段编号
  • label:修饰符(required/optional/repeated)
  • type:数据类型
  • offset:字段在结构体中的偏移量

2.4 ProtobufCLabel 枚举

typedef enum {
  PROTOBUF_C_LABEL_REQUIRED,  //1
  PROTOBUF_C_LABEL_OPTIONAL,  //2
  PROTOBUF_C_LABEL_REPEATED,  //3
  PROTOBUF_C_LABEL_NONE,      //4
} ProtobufCLabel;

2.5 ProtobufCType 枚举

typedef enum {
  PROTOBUF_C_TYPE_INT32,      /**< int32 */        // 0
  PROTOBUF_C_TYPE_SINT32,     /**< 有符号 int32 */  // 1
  PROTOBUF_C_TYPE_SFIXED32,   /**< 有符号 int32(4 字节) */ // 2
  PROTOBUF_C_TYPE_INT64,      /**< int64 */        // 3
  PROTOBUF_C_TYPE_SINT64,     /**< 有符号 int64 */  // 4
  PROTOBUF_C_TYPE_SFIXED64,   /**< 有符号 int64(8 字节) */ // 5
  PROTOBUF_C_TYPE_UINT32,     /**< 无符号 int32 */  // 6
  PROTOBUF_C_TYPE_FIXED32,    /**< 无符号 int32(4 字节) */ // 7
  PROTOBUF_C_TYPE_UINT64,     /**< 无符号 int64 */  // 8
  PROTOBUF_C_TYPE_FIXED64,    /**< 无符号 int64(8 字节) */ // 9
  PROTOBUF_C_TYPE_FLOAT,      /**< 浮点数 */       // 10
  PROTOBUF_C_TYPE_DOUBLE,     /**< 双精度浮点数 */  // 11
  PROTOBUF_C_TYPE_BOOL,       /**< 布尔类型 */     // 12
  PROTOBUF_C_TYPE_ENUM,       /**< 枚举类型 */     // 13
  PROTOBUF_C_TYPE_STRING,     /**< UTF-8 或ASCII 字符串 */ // 14
  PROTOBUF_C_TYPE_BYTES,      /**< 任意字节序列 */  // 15
  PROTOBUF_C_TYPE_MESSAGE,    /**< 嵌套消息 */     // 16
} ProtobufCType;

3. Protobuf 脱壳技术

3.1 工具分析

使用 pbtk 工具:

sudo apt install python3-pip git openjdk-11-jre libqt5x11extras5 python3-pyqt5.qtwebengine python3-pyqt5
sudo pip3 install protobuf pyqt5 pyqtwebengine requests websocket-client
git clone https://github.com/marin-m/pbtk
cd pbtk
./gui.py

3.2 手动分析步骤

  1. 根据 magic 值 0x28AAEEF9 定位 descriptor 结构体
  2. 按照字节逆向还原 descriptor 结构体
  3. 根据 fields 指针定位 ProtobufCFieldDescriptor 结构体
  4. 逐个分析字段描述符
  5. 根据参数个数判断是 proto2 还是 proto3(proto3 删除了预留值)

4. 漏洞案例分析

4.1 2023ciscn-talkbot 漏洞分析

逆向结构体

syntax = "proto2";
message devicemsg {
  required sint64 actionid = 1;
  required sint64 msgidx = 2;
  required sint64 msgsize = 3;
  required bytes msgcontent = 4;
}

漏洞点

  • free 函数置零位置错误,导致 UAF 漏洞
  • 利用 mprotect + setcontext_61 + magic_addr 进行攻击
  • 2.31 版本 setcontext 变为 rdx,需用 magic_addr 转换

利用思路

  1. 泄露 libc 和堆地址
  2. 构造 ROP 链
  3. 利用 UAF 修改 free_hook
  4. 执行 shellcode 获取 flag

4.2 ciscn2024-ezbuf 漏洞分析

逆向结构体

syntax = "proto2";
message devicemsg {
  required bytes whatcon = 1;
  required sint64 whattodo = 2;
  required sint64 whatidx = 3;
  required sint64 whatsize = 4;
  required uint32 whatsthis = 5;
}

漏洞点

  • free 没有置零,存在 UAF
  • strtok 使用 ABS_got(libc 的 got 表)
  • 劫持 strtok 跳转到 system 函数

利用思路

  1. 泄露 libc 地址
  2. 构造 fastbin attack
  3. 修改 libc got 表
  4. 劫持程序流执行 system("/bin/sh")

5. 防御建议

  1. 确保 free 操作正确置零指针
  2. 检查 Protobuf 反序列化边界
  3. 使用最新版本的 Protobuf 库
  4. 启用堆保护机制(如 ASLR、NX 等)
  5. 对输入数据进行严格验证

6. 总结

Protobuf 相关的二进制漏洞主要集中在:

  • 反序列化过程中的内存管理问题
  • 指针处理不当导致的 UAF
  • 结构体解析错误
  • 版本差异导致的兼容性问题

通过逆向 descriptor 结构体可以还原原始 protobuf 定义,进而分析漏洞点并构造利用链。在实际漏洞利用中,需要结合堆管理和程序流劫持技术实现攻击。

Protocol Buffers (Protobuf) 二进制漏洞分析与利用 1. Protobuf 基础 1.1 简介 Protocol Buffers (简称 Protobuf) 是由 Google 开发的一种语言中立、平台中立的可扩展序列化结构数据的方法。它是一种高效的协议,常用于网络通信、数据存储和应用程序间的数据传输。 1.2 环境搭建 编译为C代码: 生成文件: user.pb-c.h :头文件,定义消息类型及其相关函数 user.pb-c.c :源文件,实现序列化和反序列化等操作 编译为Python代码: 生成 demo_pb2.py 文件 1.3 基本语法 2. Protobuf 逆向分析 2.1 关键逆向点 在生成的 demo-pb-c.c 文件中,反序列化函数: 2.2 Descriptor 结构体 关键字段: magic :通常为 0x28AAEEF9 n_fields :结构体中的字段数量 fields :指向字段描述符结构体 2.3 ProtobufCFieldDescriptor 结构体 字段说明: name :字段名 id :唯一字段编号 label :修饰符(required/optional/repeated) type :数据类型 offset :字段在结构体中的偏移量 2.4 ProtobufCLabel 枚举 2.5 ProtobufCType 枚举 3. Protobuf 脱壳技术 3.1 工具分析 使用 pbtk 工具: 3.2 手动分析步骤 根据 magic 值 0x28AAEEF9 定位 descriptor 结构体 按照字节逆向还原 descriptor 结构体 根据 fields 指针定位 ProtobufCFieldDescriptor 结构体 逐个分析字段描述符 根据参数个数判断是 proto2 还是 proto3(proto3 删除了预留值) 4. 漏洞案例分析 4.1 2023ciscn-talkbot 漏洞分析 逆向结构体 漏洞点 free 函数置零位置错误,导致 UAF 漏洞 利用 mprotect + setcontext_ 61 + magic_ addr 进行攻击 2.31 版本 setcontext 变为 rdx,需用 magic_ addr 转换 利用思路 泄露 libc 和堆地址 构造 ROP 链 利用 UAF 修改 free_ hook 执行 shellcode 获取 flag 4.2 ciscn2024-ezbuf 漏洞分析 逆向结构体 漏洞点 free 没有置零,存在 UAF strtok 使用 ABS_ got(libc 的 got 表) 劫持 strtok 跳转到 system 函数 利用思路 泄露 libc 地址 构造 fastbin attack 修改 libc got 表 劫持程序流执行 system("/bin/sh") 5. 防御建议 确保 free 操作正确置零指针 检查 Protobuf 反序列化边界 使用最新版本的 Protobuf 库 启用堆保护机制(如 ASLR、NX 等) 对输入数据进行严格验证 6. 总结 Protobuf 相关的二进制漏洞主要集中在: 反序列化过程中的内存管理问题 指针处理不当导致的 UAF 结构体解析错误 版本差异导致的兼容性问题 通过逆向 descriptor 结构体可以还原原始 protobuf 定义,进而分析漏洞点并构造利用链。在实际漏洞利用中,需要结合堆管理和程序流劫持技术实现攻击。