
Human-friendly Thrift encoder/decoder
O Readable Thrift facilita o trabalho com mensagens binárias do protocolo Thrift, convertendo-as de e para um formato amigável para humanos. Isso torna a análise manual e a adulteração de mensagens Thrift em formato binário tão fáceis quanto trabalhar com protocolos de texto puro, como HTTP.
A biblioteca é implementada em Java, permitindo integração com extensões para ferramentas populares de teste de aplicações web que rodam na JVM, como Burp e ZAP. Tudo o que se precisa fazer para colocar uma ferramenta de análise ou adulteração em funcionamento é extrair os bytes apropriados e passá-los ao codec.
A biblioteca readablethrift é um pacote Maven baseado em Gradle que pode ser
instalada e incluída como dependência em outros projetos. Ela expõe quatro métodos
simples para codificação e decodificação, em forma binária bruta ou codificada em Base64.
Nota: Apenas o formato padrão do protocolo binário é suportado atualmente. O binário compacto e o JSON (diferente do JSON legível produzido pelo codec) ainda não são suportados.
ThriftCodec::decode cria uma instância descritiva de org.json.JSONObject
diretamente de um buffer de bytes bruto que contém uma mensagem Thrift binária.ThriftCodec::decodeB64String decodifica uma string Base64
e então chama decode nela.ThriftCodec::encode converte uma instância descritiva de org.json.JSONObject em um buffer
de bytes bruto contendo a mensagem Thrift binária equivalente.ThriftCodec::b64encodeJson converte um objeto JSON
para o formato binário Thrift e codifica o resultado em Base64.A classe ThriftCodec foi projetada para ser extensível, de modo que possa lidar
com modificações ou extensões do formato binário do protocolo Thrift, como cabeçalhos
extras de formato binário ou encapsulamento.
Para usar a interface interativa de linha de comando incluída na biblioteca,
use a tarefa padrão do Gradle para construir um JAR e então execute-o com
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):
Para demonstrar como ficará o JSON legível por humanos, vamos pegar um exemplo de blob binário codificado em Base64 extraído de algum tráfego de aplicação:
$ 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..
As strings "login", usuário e senha indicam que esta é uma solicitação de autenticação. Se alguém quisesse adulterar essa mensagem em tempo real, seria preciso consultar os detalhes internos do analisador do formato binário do protocolo Thrift, descobrir a estrutura da mensagem com um editor hexadecimal, e então atualizar manualmente cada campo. No caso das strings de usuário e senha, também seria necessário atualizar os valores de comprimento prefixados, além das próprias strings. Esse processo seria tedioso, propenso a erros e demorado. O Readable Thrift torna esse processo mais simples; aqui está a mesma mensagem passada a ele:
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
}}
Agora podemos verificar facilmente que a mensagem descreve uma chamada ao método "login", com uma struct
contendo dois valores de string como argumento. Atualizar os valores das strings é tão simples quanto
editar os campos JSON value e passar o novo texto JSON de volta ao codec.
Todos os prefixos de comprimento e outros detalhes do formato binário serão tratados automaticamente.
Também é possível adicionar novos campos para testar possíveis parâmetros opcionais.
Talvez exista uma flag booleana de admin ou debug? Ou uma lista de IDs de permissão?
Descreva um novo campo com id, type e value e então adicione-o ao
array 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==
Abaixo está a mensagem atualizada convertida de volta para o protocolo binário 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