Archive for January, 2014

Resident XSS (Rootkits in your Web application)

Posted in Valnurability on January 11, 2014 by keizer

The new HTML5 was brought the internet community with a whole bunch of new features, to help us create a more dynamic and smooth client side, whether for the mobile apps or to a browser based client. Among its new feature you can find: CSS3, Drag&Drop, localStorage & sessionStorage, Streaming, Geolocation, Webworks and whatnot.

Wait! (imagine you hear the rewind sound): local & session Storage? does that mean that I can store data on the client? -Yes!
Well, it sounds like a great feature isn’t it? they all are… but are they safe? – A big fat No!

But lets concentrate in the session & local storage, shall we? What if someone store things for me? evil things… it means that my own browser will betray me and hold malicious data that could harm me! how does that work?

Lets say that the  site you are using stores some of your account details into your local & session storage, so later on it could read information from your client, sparing it to send requests to the server.

In this scenario, our website stores your account#, the SessionId, your username and some other string that will be displayed on the screen when you enter the website (sounds like… exactly!).

Our website, takes the data it previously entered to the storage and displays it when the page renders. This is how the page looks normally, along with the original information stored in the sessionStorage:

residentXSS_before(Click on the image to enlarge)

 

Notice that the message withing the speech bubble takes its information from the Session Storage, as can be seen in the above image, right below the page. You can access the page’s Resources tab using Chrome’s Developer tools (a.k.a Inspect Element). We can assume that the code behind it looks something like this:

var username = window.sessionStorage.getItem(“User”);
var speech = window.sessionStorage.getItem(“Speach-of-the-day”);
var action = window.sessionStorage.getItem(“Random-action”);

and calling them using:

<h1> <script>document.write(“Hello ” + username); </script> </h1>
<h3> <script>document.write(speech);</script> </h3>
<a href=”#”> <script>document.write(action);</script> </a>

Now, what if this website is vulnerable to a Reflected XSS? in that case the XSS would be active once, on the response that includes it. But what if! this website uses the client side storage to display information?

— If the attacker injected some malicious content to our sessionStorage and the website does not perform client-side encoding/ escaping (wait… client-side? yes!) then the XSS would take residence (thus, the name) inside our browser, just waiting to be called by the client.

Its also very simple to do so, all the attacker needs to know is the name of the key within the storage and then change it simply using: sessionStorage.setItem(key);

So, let go back to the example. The attacker managed to implement a code inside our sessionStorage using regular XSS. Then it will look like this:

residentXSS_after(Click on the image to enlarge)

 

Notice that the Speech-of-the-day key has changed, and it now contains a script. The next time (and everytime after that) the page refreshes, the XSS will be executed:

residentXSS_alert(Click on the image to enlarge)

 

What can we do about it? — as I mentioned earlier, before reading content from the client-storage escape it! so when called, even if someone planted a malicious script – it won’t be executed:

residentXSS_escaping(Click on the image to enlarge)

 

With all the cool features HTML5 has brought to us, a lot of new security issues has been introduced. An important part of them involve data stored in the client, or taken from it. Since the client should never be trusted, all the data in it, no matter if we stored it or not –  should be mitigated, and we should take any precautions possible when dealing with it.

Advertisements

WhatsApp Messages Eavesdropping

Posted in Valnurability on January 10, 2014 by keizer

whatsapplogo

Logging into WhatsApp on a new device currently works as follows:

  • The phone posts its phone number to a HTTPS URL to request an authentication code,
  • the phone receives an authentication code in the text message,
  • the authentication code is used, again over HTTPS, to obtain a password.

These passwords are quite long and never visible to the user, making them hard to steal from a phone.

Authentication Overview

With the password, the client can log in to a XMPP-like server. For this it uses the custom SASL mechanism WAUTH-1. To log in with the phone number 1234567890, the following happens (this is only an XML representation of the protocol)

  • The client sends:
    <auth xmlns=”urn:ietf:params:xml:ns:xmpp-sasl” user=”1234567890” mechanism=”WAUTH-1″ />
  • The server responds with a some challenge (here ABCDEFGHIJKLMNOP):
    <challenge xmlns=”urn:ietf:params:xml:ns:xmpp-sasl”> ABCDEFGHIJKLMNOP</challenge>
  • To respond to the challenge, the client generates a key using PBKDF2 with the user’s password, the challenge data as the salt and SHA1 as the hash function. It only uses 16 iterations of PBKDF2, which is a little low these days, but we know the password is quite long and random so this does not concern me greatly. 20 bytes from the PBKDF2 result are used as a key for RC4, which is used to encrypt and MAC 1234567890 || ABCDEFGHIJKLMNOP || UNIX timestamp:
    <response xmlns=”urn:ietf:params:xml:ns:xmpp-sasl”>XXXXXXXXXXXX</response>
  • From now on, every message is encrypted and MACed (using HMAC-SHA1) using this key.

Mistake #1: The same encryption key in both directions

How RC4 is supposed to work? RC4 is a PRNG that generates a stream of bytes, which are XORed with the plaintext that is to be encrypted. By XORing the ciphertext with the same stream, the plaintext is recovered.

So,  (A ^ X) ^ (B ^ X) = A ^ B

In other words: if we have two messages encrypted with the same RC4 key, we can cancel the key stream out!

As WhatsApp uses the same key for the incoming and the outgoing RC4 stream, we know that ciphertext byte i on the incoming stream XORed with ciphertext byte i on the outgoing stream will be equal to XORing plaintext byte i on the incoming stream with plaintext byte i of the outgoing stream. By XORing this with either of the plaintext bytes, we can uncover the other byte.

This does not directly reveal all bytes, but in many cases it will work: the first couple of messages exchanged are easy to predict from the information that is sent in plain. All messages still have a common structure, despite the binary encoding: for example, every stanza starts with 0xF8. Even if a byte is not known fully, sometimes it can be known that it must be alphanumeric or an integer in a specific range, which can give some information about the other byte.

Mistake #2: The same HMAC key in both directions

The purpose of a MAC is to authenticate messages. But a MAC by itself is not enough to detect all forms of tampering: an attacker could drop specific messages, swap them or even transmit them back to the sender. TLS counters this by including a sequence number in the plaintext of every message and by using a different key for the HMAC for messages from the server to the client and for messages from the client to the server. WhatsApp does not use such a sequence counter and it reuses the key used for RC4 for the HMAC.

When an attacker retransmits, swaps or drops messages the receiver can not notice that, except for the fact that the decryption of the message is unlikely to be a valid binary-XMPP message. However, by transmitting a message back to the sender at exactly the same place in the RC4 stream as it was originally transmitted will make it decrypt properly.

Conclusion

You should assume that anyone who is able to eavesdrop on your WhatsApp connection is capable of decrypting your messages, given enough effort. You should consider all your previous WhatsApp conversations compromised. There is nothing a WhatsApp user can do about this but except to stop using it until the developers can update it.

There are many pitfalls when developing a streaming encryption protocol. Considering they don’t know how to use a XOR correctly, maybe the WhatsApp developers should stop trying to do this themselves and accept the solution that has been reviewed, updated and fixed for more than 15 years, like TLS.

Android PoC

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 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:

<auth user=”1234567890″ xmlns=”urn:ietf:params:xml:ns:xmpp-sasl” mechanism=”WAUTH-1″> XXXXXXXXXXXX</auth>

After this message the server replies with an encrypted response (ABCDEFGHIJKLMNOP)

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>. So lets try and repeat the same trick:

  • The plaintext of the XXXXXXXXXXXX block is still 1234567890 || nonce || UNIX time (1234567890 was the phone number, wich is still included in plain). We do not know what the nonce is in this case, but we do know 1234567890. So we could try to make a guess for the timestamp, but lets keep it simple.
  • Calculate (X[i] ^ 1[i]) ^ A[i] (ignoring the HMAC bytes) and the result is (in hex):
    F8 0E BE C3 FC 0A 31 33 38 31 32
  • As mentioned earlier, 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). The 0xBE refers to the string success in WhatsApp’s encoding.

This is very unlikely to be a coincidence, which proves that the latest version of the Android client is vulnerable.

But 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.

We can suspect that 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.

Conclusion

You should assume that anyone who is able to eavesdrop on your WhatsApp connection is capable of decrypting your messages, given enough effort. You should consider all your previous WhatsApp conversations compromised. There is nothing a WhatsApp user can do about this but except to stop using it until the developers can update it.

There are many pitfalls when developing a streaming encryption protocol. Considering they don’t know how to use a XOR correctly, maybe the WhatsApp developers should stop trying to do this themselves and accept the solution that has been reviewed, updated and fixed for more than 15 years, like TLS.

Thanks to : xnyhps’ blog