Notes on how to reverse the facebook messenger mobile protocol. Not planning to write actual protocol docs yet.

Quick protocol summary

  • HTTPS api for login, contact lists, groupchat details, etc.
    • Mostly json. Some GraphQL, some FQL, some other less structured apis.
  • Variant of MQTT 3.1 with version string MQTToT, the transport/pubsub layer.
  • Thrift (compact) or json for message payloads.


Tools used

  • A linux pc (os x might work too)
  • A rooted ARM android phone (4.0 or newer) or an emulator that can run the app
    • For some reason x86 builds of orca require android 5.0.
    • I didn't have much luck with android-x86 5.0, while 4.4 naively tried to use the ARM build and failed.
    • genymotion (closed source but free, requires an account to download base images) with a "custom" android 5.0 image worked for me.
  • mitmproxy
  • wireshark (for fancier dissection) with this custom lua mqtt dissector
  • dnsmasq (maybe optional - dns and dhcp to isolate the VM)

Basic MITM

  1. Read the mitmproxy docs.
  2. Install and run
  3. Get the "explicit http proxy" method working from a desktop browser. Install certs and everything.
  4. Same thing but from the browser app of the phone (not the app yet)
  5. Do what the transparent proxying docs say
  6. Confirm that it works by browsing SSL sites and

Given a physical phone or a VM with bridged networking, where you can just configure the default gateway to be the IP of the computer with mitmproxy, that's probably enough. Otherwise:

Isolated host-only interface in virtualbox

I prefer to configure virtualbox with a host-only vboxnet0 interface, and use that for the iptables forwarding commands. That way the VM can only communicate externally through the MITM'd ports 80 and 443.

dnsmasq listens in that interface only, providing dhcp and dns, and it may log the dns queries for extra information.

Genymotion also uses virtualbox as backend - you can just open virtualbox, go to the settings of the genymotion VM, and change the second network interface from NAT to host-only vboxnet0.

Facebook specific stuff

Newer versions of the app may have a bundled openssl with its own certificate store. I think versions older than 38 might not have it. Messenger lite 2.1 doesn't have it either.

If it exists, remove /data/data/com.facebook.orca/lib-xzs/ from the phone. Some versions (around 64?) fall back to the system openssl and the system certificate store if you do this.

Newer versions (around 100) have openssl bundled in some other library. To MITM those, you'll have to get creative

You might want to get yourself a whitehat test account. They are neat.

MQTT dissection in wireshark

Start mitmproxy like this to write TLS master secrets to a file. See the mitmproxy docs on this

SSLKEYLOGFILE=/tmp/keylog mitmproxy -T --host --raw-tcp

After configuring wireshark you should be able to see the contents of SSL streams.

Get the custom mqtt dissector and put it in ~/.wireshark/plugins/mqtt.lua. Differences with the built-in one:

  • It adds itself to the ssl dissector list (for wireshark 2.0, wireshark 2.2 fixes this)
  • Supports the nonstandard compressed CONNECT command (appears as a malformed packet otherwise)
  • Uncompresses all publish payloads
  • Dissects json
  • Mentions the topic and the message ID in the info column of wireshark

To force wireshark to interpret the SSL stream as MQTT instead of HTTP, go to Edit -> Preferences -> Protocols -> SSL -> RSA Keys List -> Edit button and add an entry with the following:

  • IP: any (literal, otherwise it whines randomly) or the MQTT server IP
  • Port: 443
  • Protocol: mqtt-fb
  • Key File: any valid private key file, i use ~/.mitmproxy/mitmproxy-ca.pem

The key file isn't actually used, it's just for the sake of passing the file type validation, this is just to make it reinterpret 443 as mqtt. The actual keys come from from SSLKEYLOGFILE.

Thanks to Lekensteyn from #wireshark for this hack.

Update: wireshark 2.3+ (git master at the time of this writing) adds a "decode as" for ssl streams, allowing to do the same thing as that hack cleanly. Thanks to Lekensteyn again, one year later.

Also, that hack didn't work for me with 2.2.3 but YMMV.

Fancy screenshot of the dissector in action:

Fancy screenshot

It's not so fancy when you look at the events that have thrift payloads, but that requires some knowledge of the data structures in the dissector itself.

Other parts

For the http requests I just use mitmproxy, because that's where it shines.

TODO: thrift, may god have mercy on our souls.