My previous post received a lot of attention today and some people rightly complained that the results don’t mean much when it can not be reproduced with an official WhatsApp client.
So today I spent some time trying to disassemble the offical clients and running the Android client in the Android Emulator.
I had some success decompiling the latest version of the Nokia S40 package (version 2.11.4, SHA1:
I found this (with some classes and functions given meaningful names by me):
I think it’s clear that
this.a are two different instances of RC4 with the same key and
this.c are HMAC instances also with that key.
Decompiling this turned into a pile of garbarge. All strings are obfuscated so it’s very hard to determine which class is doing what. It appears to use some crypto API as I can find references to certain elliptic curves and AES. This is likely Bouncy Castle, which doesn’t mean they actually use ECC or AES.
So on to the Android Emulator, where it turns out it is not following the authentication procedure as described in my previous post. The mechanism is still called
WSAUTH-1, but the initial
<auth> contains 45 bytes of data now:
After this message the server replies with an encrypted response, lets call this
The first hint that this is still RC4 is that encrypted messages are of different lengths: a block cipher would require padding and would result in messages of exactly the block size.
45 bytes is also exactly the length of the data in the SASL
<response> I described. So lets see if we can repeat the same trick:
- I assume the plaintext of the
ZZZZZZZZZZZZZZZZZZZblock is still
XXXXXXXXXXX || nonce || UNIX time(
XXXXXXXXXXXwas the phone number, wich is still included in plain). I do not know what the
nonceis in this case, but I do know
XXXXXXXXXXX. I could try to make a guess for the timestamp, but lets keep it simple.
- I calculate
(Z[i] ^ X[i]) ^ U[i](ignoring the HMAC bytes) and the result is (in hex):
f8 0e be c3 fc 0a 31 33 38 31 32
- Recall that all stanzas in WhatsApp’s binary encoding start with
0xf8. The last 5 bytes are
13812in ASCII, which looks suspiciously much like the
't'attribute of the
<success>message (a UNIX timestamp). Indeed: the
0xberefers to the string
successin WhatsApp’s encoding.
This is very unlikely to be a coincidence, which proves that the latest version of the Android client is vulnerable.
…but wait, where did that RC4 key come from?
Apparently the server is able to generate the RC4 key using no nonce or key exchange with the client. The key is also different on each login, as otherwise the first couple of ciphertext bytes in the
<auth> would always be the same.
I suspect the key only depends on the password, but new password is obtained during every login. The client makes an HTTPS request to WhatsApp before the fake-XMPP connection is made and
yowsup-cli has a flag that will send your password to the server, which will give you a new one if the password was correct.
I have shown pretty convincingly that the latest versions of the Android and Nokia S40 WhatsApp clients are vulnerable to this problem. I don’t have an iPhone to reproduce the results on iOS nor have I looked at the BlackBerry version, but I don’t think the results will be much different.