Readable Thrift 通过将二进制 Thrift 协议消息转换为人类友好的格式(反之亦然),让这些消息更易于处理。这使得对二进制格式 Thrift 消息的手动分析和篡改,就像处理 HTTP 之类的明文协议一样简单。
该库使用 Java 实现,因而能够与运行在 JVM 上的流行 Web 应用测试工具(如 Burp 和 ZAP)的扩展进行集成。要启动一个分析或篡改工具,只需解析出相应的字节并将其传递给编解码器即可。
readablethrift 库是一个基于 Gradle 的 Maven 包,可以作为依赖安装并包含在其他项目中。它提供了四个用于编码和解码的简单方法,支持原始二进制或 Base64 编码形式。
注意: 目前仅支持标准的二进制格式协议。尚不支持 compact binary 和 JSON(与编解码器生成的可读 JSON 不同)。
ThriftCodec::decode 方法直接从包含二进制 Thrift 消息的原始字节缓冲区创建一个描述性的 org.json.JSONObject 实例。ThriftCodec::decodeB64String 静态方法会将 Base64 字符串解码,然后对其调用 decode。ThriftCodec::encode 方法将描述性的 org.json.JSONObject 实例转换为包含等效 Thrift 二进制消息的原始字节缓冲区。ThriftCodec::b64encodeJson 静态方法会将 JSON 对象转换为 Thrift 二进制格式,并对结果进行 Base64 编码。ThriftCodec 类的设计具有可扩展性,因此它可以处理对 Thrift 二进制协议格式的修改或扩展,例如额外的二进制格式头或封装。
要使用库中包含的交互式命令行界面,请使用默认的 Gradle 任务构建 JAR,然后用 java -jar 运行它:
$ ./gradlew
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
$ java -jar build/libs/readablethrift-1.0.0-all.jar
Enter Base64 encoded message or JSON object (or q to quit):
为了演示人类可读的 JSON 是什么样子,我们以一段从某个应用流量中提取的 Base64 编码二进制 blob 为例:
$ base64 -D | hexdump
gAEAAQAAAAVsb2dpbgAAAAAMAAALAAAAAAAIY29vbHVzZXILAAEAAAALcGFzc3dvcmQxMjMAAA==
00000000: 8001 0001 0000 0005 6c6f 6769 6e00 0000 ........login...
00000010: 000c 0000 0b00 0000 0000 0863 6f6f 6c75 ...........coolu
00000020: 7365 720b 0001 0000 000b 7061 7373 776f ser.......passwo
00000030: 7264 3132 3300 00 rd123..
其中的 "login"、用户名和密码字符串暗示这是一个身份验证请求。如果要在传输过程中篡改该消息,就必须查阅 Thrift 协议二进制格式解析器的内部细节,用十六进制编辑器弄清消息的结构,然后手动更新各个字段。对于用户名和密码字符串,除了更新字符串本身之外,还需要更新其前置的长度值。这将是一个繁琐、易错且耗时的过程。而 Readable Thrift 让这一过程变得更简单;下面就是同一消息传给它的输出:
Enter Base64 encoded message or JSON object (or q to quit): gAEAAQAAAAVsb2dpbgAAAAAMAAALAAAAAAAIY29vbHVzZXILAAEAAAALcGFzc3dvcmQxMjMAAA==
{"message": {
"name": "login",
"type": "call",
"fields": [{
"id": 0,
"type": "struct",
"value": [
{
"id": 0,
"type": "string",
"value": "cooluser"
},
{
"id": 1,
"type": "string",
"value": "password123"
}
]
}],
"seqid": 0
}}
现在我们可以轻松确认,该消息描述的是对 "login" 方法的一次调用,参数是一个包含两个字符串值的结构体。更新字符串值就像编辑 value JSON 字段并将新的 JSON 文本传回编解码器一样简单。所有长度前缀和二进制格式的其他细节都将自动处理。
还可以添加新字段来测试可能存在的可选参数。也许有一个 admin 或 debug 布尔标志?或者一组权限 ID 列表?用 id、type 和 value 描述一个新字段,然后将其添加到 fields 数组中:
Enter Base64 encoded message or JSON object (or q to quit): {"message": {
"name": "login",
"type": "call",
"fields": [{
"id": 0,
"type": "struct",
"value": [
{
"id": 0,
"type": "string",
"value": "differentuser"
},
{
"id": 1,
"type": "string",
"value": "differentpassword!"
}
]
},
{"id": 1, "type": "bool", "value": true},
{"id": 2, "type": "list", "value":
{
"elemType": "i32",
"list": [1, 2, 3]
}
},
{"id": 3, "type": "map", "value":
{
"keyType": "string",
"valueType": "string",
"map": {
"dog": "bark",
"cat": "meow"
}
}
}],
"seqid": 0
}}
gAEAAQAAAAVsb2dpbgAAAAAMAAALAAAAAAANZGlmZmVyZW50dXNlcgsAAQAAABJkaWZmZXJlbnRwYXNzd29yZCEAAgABAQ8AAggAAAADAAAAAQAAAAIAAAADDQADCwsAAAACAAAAA2NhdAAAAARtZW93AAAAA2RvZwAAAARiYXJrAA==
下面是转换回 Thrift 二进制协议后的更新消息:
$ base64 -D | hexdump
gAEAAQAAAAVsb2dpbgAAAAAMAAALAAAAAAANZGlmZmVyZW50dXNlcgsAAQAAABJkaWZmZXJlbnRwYXNzd29yZCEAAgABAQ8AAggAAAADAAAAAQAAAAIAAAADDQADCwsAAAACAAAAA2NhdAAAAARtZW93AAAAA2RvZwAAAARiYXJrAA==
00000000: 8001 0001 0000 0005 6c6f 6769 6e00 0000 ........login...
00000010: 000c 0000 0b00 0000 0000 0d64 6966 6665 ...........diffe
00000020: 7265 6e74 7573 6572 0b00 0100 0000 1264 rentuser.......d
00000030: 6966 6665 7265 6e74 7061 7373 776f 7264 ifferentpassword
00000040: 2100 0200 0101 0f00 0208 0000 0003 0000 !...............
00000050: 0001 0000 0002 0000 0003 0d00 030b 0b00 ................
00000060: 0000 0200 0000 0363 6174 0000 0004 6d65 .......cat....me
00000070: 6f77 0000 0003 646f 6700 0000 0462 6172 ow....dog....bar
00000080: 6b00