Decoding and Tampering Protobuf Serialized Messages in Burp
If you've ever assessed or poked at an application that uses Google Protocol Buffers, you know how painstaking the whole process can be. When you're lucky enough to have a corresponding .proto, crafting messages via generated API's is tedious. When you don't, you have to resort to reversing the protocol format by hand and/or extracting the proto file descriptor out of the application. Otherwise, you're left dumb-fuzzing the protocol and never diving into the application itself.
Out of necessity, I wrote a Burp Extension that would decode raw protobuf messages even when a .proto was not available. After loading a .proto, the extension features the ability to modify and tamper with protobuf messages. In my extension, you can also manually specify what message type to deserialize a given protobuf message as. You can download my extension at
The following set of screenshots should give you a quick overview of what it's capable of:
We start off with a view of what a simple, raw protobuf message looks like in Burp. If you've ever tried to tamper this right here, you'd probably find yourself reading and re-reading protocol buffer encoding.
Here's what that message looks like when decoded using protoc --decode_raw:
Another request that looks to be adding a serialized user object. Note, the burp-protobuf-decoder extension identifies protobuf messages by an HTTP Content-Type request or response header equal to application/x-protobuf . If the application you're looking at does things a bit differently, have a look at modifying isEnabled() , getMessage() and setMessage() of protoburp.py.
And again, what it looks like after protoc --decode_raw:
If we're lucky enough to have a .proto that defines what this message looks like, we can load it from here:
Find our addressbook.proto (taken from the protobuf example applications):
We can then manually deserialize the message as a Person. Next time a request comes through, the extension will automatically deserialize the message. Note, an attempt will be made to deserialize as all types until one is found to deserialize with all required fields initialized (this could result in some false positives).
That looks much better...
But wait, how about we tamper it?
The extension will reserialize our message and we can send it on its way. If any errors occur (such as required fields missing), an alert dialog will pop up letting you know.
And the response from the server confirms our message was tampered succesfully.
Hopefully my extension will make testing protobuf based applications much easier from now on.
blog comments powered by Disqus