Protobuf in Pwn
目录
傻逼国内pwn, 不会出可以不出, 套个 protobuf 断网不给环境打你 🐴
env
emerge dev-libs/protobuf dev-libs/protobuf-c dev-python/protobuf
proto
embed
数据段有出现 .proto
字符串
marin-m/pbtk: A toolset for reverse engineering and fuzzing Protobuf-based apps
ggbound/docker/bin via 🐍 v3.13.5
❯ ./pbtk/extractors/from_binary.py pwn out
[+] Wrote 10 .proto files to "out".
ggbound/docker/bin via 🐍 v3.13.5
❯ t out
out
├── github.com
│ └── golang
│ └── protobuf
│ └── ptypes
│ ├── any
│ │ └── any.proto
│ ├── duration
│ │ └── duration.proto
│ └── timestamp
│ └── timestamp.proto
├── google
│ ├── protobuf
│ │ ├── any.proto
│ │ ├── descriptor.proto
│ │ ├── duration.proto
│ │ └── timestamp.proto
│ └── rpc
│ └── status.proto
├── grpc
│ └── binlog
│ └── v1
│ └── binarylog.proto
└── ggbond.proto
ggbound/docker/bin via 🐍 v3.13.5
❯ head out/ggbond.proto
syntax = "proto3";
package GGBond;
option go_package = "./;ggbond";
service GGBondServer {
rpc Handler(Request) returns (Response);
}
c struct
傻逼 ccb 不给 protobuf-c.so
ida 导入一下 /usr/include/protobuf-c/protobuf-c.h
, 里面头文件注释掉, 否则会递归到一些宏然后报错.
在 rodata 里搜 message 的魔术 0x28AAEEF9, 这个地方就是 ProtobufCMessageDescriptor
.
对着相应的地方是 ProtobufCFieldDescriptor

对着字段写 proto:
syntax = "proto3";
package ${package_name};
message ${short_name} {
${fields}
}
其中 ${fields} 是各个 ProtobufCFieldDescriptor
, 只用看前四个字段, 写成这样的:
${LABEL} ${TYPE} ${name} = ${id};
LABEL 和 TYPE 都是常量后面改成小写就行, LABEL_NONE 直接忽略.
此外, 0x14159BC3 是 ProtobufCServiceDescriptor
的魔术, 也对着恢复结构体.
py
protoc --python_out=. name.proto
能够生成 name_pb2.py
, import 这个包, 可以用 ${short_name}()
构造消息类, 直接实例 .name 就可以修改 fields 了. 之后 SerializeToString
序列化后拿去交互即可. 比如:
msg = giao_pb2.Msgiao()
msg.giaoid = 0x114514
msg.giaosize = 0x415411
msg.giaocontent = shellcode
msg.giaotoken = b"87dd78e1-9025-4d57-9c2e-418608b3bbea"
sa("your giao: ",msg.SerializeToString())
Protocol Buffers (.proto) 文件基础定义参考 by LLM
这文档是 Protocol Buffers (.proto
) 文件的完整基础定义参考,适用于 proto2 和 proto3(默认推荐 proto3)。
1. 基础结构
语法版本
syntax = "proto3"; // 或 "proto2"
package - 命名空间
package my.package.name;
import - 导入其他 .proto 文件
import "other.proto";
option - 级别元数据 / 生成器选项
option java_package = "com.example";
option go_package = "github.com/example/project/proto";
2. message - 消息结构
message Person {
string name = 1;
int32 id = 2;
bool is_verified = 3;
}
repeated - 列表
repeated string tags = 4;
map - 键值对
map<string, int32> scores = 5;
oneof - 互斥字段
oneof contact_info {
string email = 6;
string phone = 7;
}
reserved - 保留字段/编号
reserved 10, 11, 12;
reserved "old_field", "legacy";
3. enum - 枚举
enum Status {
UNKNOWN = 0;
ACTIVE = 1;
INACTIVE = 2;
BANNED = 3;
}
4. service & rpc - 服务 / gRPC 接口
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
rpc CreateUser (User) returns (UserResponse);
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
bool success = 1;
string message = 2;
}
5. Any - 动态类型
import "google/protobuf/any.proto";
message Wrapper {
google.protobuf.Any payload = 1;
}
6. 嵌套类型
message Outer {
message Inner {
int32 value = 1;
}
enum Level {
LOW = 0;
HIGH = 1;
}
Inner inner = 1;
Level level = 2;
}
7. extensions (限 proto2)
message Foo {
extensions 100 to 199;
}
8. 常见验证 magic number (限 protobuf-c)
结构类型 | 定义字段 | 魔数值 (16进制) |
---|---|---|
ProtobufCMessageDescriptor |
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC |
0x28aaeef9 |
ProtobufCServiceDescriptor |
PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC |
0x14159bc3 |
9. 完整示例
syntax = "proto3";
package example;
message User {
int32 id = 1;
string name = 2;
repeated string roles = 3;
Status status = 4;
map<string, string> meta = 5;
oneof contact {
string email = 6;
string phone = 7;
}
}
enum Status {
UNKNOWN = 0;
ACTIVE = 1;
BANNED = 2;
}
service UserService {
rpc GetUser (UserRequest) returns (User);
rpc CreateUser (User) returns (UserResponse);
}
message UserRequest {
int32 id = 1;
}
message UserResponse {
bool success = 1;
string message = 2;
}