Recently we discovered a very interesting vulnerability in Android’s DNS resolver, a weakness in its pseudo-random number generator (PRNG), which makes DNS poisoning attacks feasible.
DNS poisoning attacks endanger the confidentiality and integrity of the target victim’s machine. For instance, DNS poisoning can be used to steal the victim’s cookies, or tamper with weak applications’ update mechanisms in order to execute malicious code.
The official advisory with full details can be found here.
This blog post summarizes the advisory.
A very short background on DNS poisoning
Each DNS request holds a unique identifier (‘nonce’) which consists of an attribute called ‘TXID’ and the UDP source port. They both combine to a 32bit value. Ideally these 32 bits are random.
In order to conduct a DNS poisoning attack, an attacker must be able to inject a forged response before the legitimate one arrives from the server. The forged response must include the correct nonce (that the attacker must correctly guess), otherwise it is dropped by the resolver.
If the nonce is a 32bit random value, an attack takes years to succeed (in average). Not that feasible! But with every bit of randomness we are able to reduce from the nonce, the expected time drops by a factor of two.
How does android resolve DNS?
The code that is in charge of the DNS resolution can be found under Android’s libc implementation (aka ‘bionic’).
Android provides source port and TXID randomization by calling the function res_randomid , which returns a 16bit integer:
1: u_int
2: res_randomid(void) {
3: struct timeval now;
4:
5: gettimeofday(&now, NULL);
6: return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
7: }
It can be seen that the returned value is a XOR operation of the fraction of the current time in microseconds, the current time in seconds and the process ID. This method is used twice in close succession in order to produce the TXID and source port values.
The dominant factor which makes this value hard to predict is the microseconds fraction.
Why is it vulnerable?
Remember that the res_randomid function is used twice, once for the TXID, and once for the source port. The Achilles' heel and the crux of the attack is the fact that there two subsequent calls to the res_random_id function in a very short time. Since res_random_id is a function of the current time, the TXID and source port values become very much correlated to each other: given that the attacker guessed correctly one value, probability is high that the other value would be also guessed correctly. This means that instead of 32 random bits, you get much less. In fact, our research shows that in some environments, the 32 bits contain less than 21 random ones. The expected time for a successful attack is brought down from years to minutes!
The attack is feasible regardless of whether or not the attacker knows the process ID. See our whitepaper for the complete analysis.
Take a look at the following capture:
Let’s examine some source port, TXID couples and verify if there is any correlation:
It can be seen even to the naked eye that the TXID and source port values are not that different. Remember that ideally each of them is chosen out of 65536 values.
Why should you care? What is the impact?
As usual, DNS poisoning attacks may endanger the integrity and confidentiality of the attacked system. For example, in Android, the Browser app can be attacked in order to steal the victim's cookies of a domain of the attacker's choice. In case the attacker manages to lure the victim to browse a web page controlled by him/her, the attacker can use JavaScript in order to start resolving non-existing sub-domains. Upon success, a sub-domain points to the attacker's IP, which enables the latter to steal wildcard cookies of the attacked domain, and even insert ones (see this for more details on the impact of subdomain poisoning). In addition, a malicious app may instantiate the Browser app on the attacker's malicious web-page. If the attacker knows the process ID (for example, a malicious app can access that information), the expected time for a successful attack can be reduced, as explained in the whitepaper.
A video demo of the attack
How was the issue fixed?
The random sample is now taken from /dev/urandom which should have enough entropy when the call is made.
Which versions are vulnerable?
Android 4.0.4 and below
Which versions are non-vulnerable?
Android 4.1.1
Disclosed by:
Roee Hay and Roi Saltzman
Disclosure timeline
07/24/2012 Public disclosure
06/05/2012 Issue confirmed by Android Security Team and patch provided to partners
05/21/2012 Disclosed to Android Security Team by Roee Hay and Roi Saltzman
Great Work! Clear and well documented... and No secret selling of '0 Days'!!
Posted by: Lisa Peterson | July 24, 2012 at 04:32 PM
Very nice. Interesting read.
:)
Posted by: Mike | July 24, 2012 at 09:30 PM
Nice research and good that it's been fixed.
But I really don't see how this can be exploted in the real world.
(open wlans or recursors owned by the attacker don't need this. I don't know where else an attacker out there should see a dns packet originating from the Android device.)
Posted by: otmar | July 25, 2012 at 03:33 PM
@otmar
Thanks for the feedback!:)
One example for an attack is closed wifi, to which the attacker has access (our PoC video demonstrates just that)
Mobile data networks are also attractive.
In either case, the attacker must be able to send spoofed DNS packets to the victim.
Posted by: Roee Hay | July 25, 2012 at 05:45 PM