
Human-friendly Thrift encoder/decoder
Readable Thrift erleichtert die Arbeit mit binären Thrift-Protokollnachrichten, indem es sie in ein für Menschen gut lesbares Format umwandelt und zurück. Dadurch wird die manuelle Analyse und Manipulation von Thrift-Nachrichten im Binärformat genauso einfach wie die Arbeit mit Klartextprotokollen wie HTTP.
Die Bibliothek ist in Java implementiert und ermöglicht die Integration mit Erweiterungen für gängige Webanwendungs-Testtools, die auf der JVM laufen, wie Burp und ZAP. Um ein Analyse- oder Manipulationstool zum Laufen zu bringen, muss man lediglich die entsprechenden Bytes parsen und an den Codec übergeben.
Die Bibliothek readablethrift ist ein Gradle-basiertes Maven-Paket, das installiert und als Abhängigkeit in anderen Projekten eingebunden werden kann. Sie stellt vier einfache Methoden zum Kodieren und Dekodieren zur Verfügung, entweder in roher Binärform oder als Base64-kodierte Form.
Hinweis: Derzeit wird nur das Standard-Binärformat-Protokoll unterstützt. Compact Binary und JSON (anders als das vom Codec erzeugte lesbare JSON) werden noch nicht unterstützt.
ThriftCodec::decode erzeugt direkt aus einem rohen Byte-Puffer, der eine binäre Thrift-Nachricht enthält, eine beschreibende org.json.JSONObject-Instanz.ThriftCodec::decodeB64String dekodiert eine Base64-Zeichenkette und ruft anschließend decode darauf auf.ThriftCodec::encode wandelt eine beschreibende org.json.JSONObject-Instanz in einen rohen Byte-Puffer um, der die entsprechende Thrift-Binärnachricht enthält.ThriftCodec::b64encodeJson wandelt ein JSON-Objekt in das Thrift-Binärformat um und kodiert das Ergebnis als Base64.Die Klasse ThriftCodec ist so konzipiert, dass sie erweiterbar ist und Änderungen oder Erweiterungen des Thrift-Binärprotokollformats verarbeiten kann, wie etwa zusätzliche Binärformat-Header oder Kapselung.
Um die in der Bibliothek enthaltene interaktive Befehlszeilenschnittstelle zu nutzen, verwenden Sie die Standard-Gradle-Aufgabe, um ein JAR zu erstellen, und führen Sie es anschließend mit java -jar aus:
$ ./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):
Um zu veranschaulichen, wie das menschenlesbare JSON aussieht, nehmen wir als Beispiel einen Base64-kodierten Binär-Blob, der aus dem Datenverkehr einer Anwendung extrahiert wurde:
$ 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..
Die Zeichenketten „login“, Benutzername und Passwort deuten darauf hin, dass es sich um eine Authentifizierungsanfrage handelt. Wenn man diese Nachricht spontan manipulieren wollte, müsste man die internen Details des Parsers für das Thrift-Binärformat nachschlagen, die Struktur der Nachricht mit einem Hex-Editor ermitteln und dann jedes Feld manuell aktualisieren. Im Falle der Benutzername- und Passwort-Zeichenketten müsste man zusätzlich zu den Zeichenketten selbst auch die vorangestellten Längenwerte aktualisieren. Das wäre ein mühsamer, fehleranfälliger und zeitaufwändiger Prozess. Readable Thrift macht diesen Prozess einfacher; hier ist dieselbe Nachricht, nachdem sie an das Tool übergeben wurde:
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
}}
Jetzt können wir leicht überprüfen, dass die Nachricht einen Aufruf der Methode „login“ beschreibt, mit einer Struktur, die zwei Zeichenkettenwerte als Argument enthält. Das Aktualisieren der Zeichenkettenwerte ist so einfach wie das Bearbeiten der value-JSON-Felder und das Zurückgeben des neuen JSON-Texts an den Codec. Alle Längenpräfixe und sonstigen Details des Binärformats werden automatisch verarbeitet.
Es ist auch möglich, neue Felder hinzuzufügen, um mögliche optionale Parameter zu testen. Vielleicht gibt es ein Admin- oder Debug-Flag (boolesch)? Oder eine Liste von Berechtigungs-IDs? Beschreiben Sie ein neues Feld mit einer id, einem type und einem value und fügen Sie es dann dem fields-Array hinzu:
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==
Unten ist die aktualisierte Nachricht, zurückkonvertiert in das Thrift-Binärprotokoll:
$ 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