NScript在对脚本进行evaluation之前会做一次熵判断,现在常用的做法是用一段长而无用的代码插在要评估的代码之前,达到熵的限值。而我们既然要用其他程序生成Funfuzz的结果再抛给NScript,看Funfuzz的输出:
/*FRC-fuzzSeed-58694107*/count=25; tryItOut("mathy5 = (function(x, y) { \"use strict\"; return ( ! (((( ~ (( + ( - y)) | 0)) | 0) & ( + ( + ((-(2**53) != (-0 >>> 0)) >>> 0)))) | 0)); }); testMathyFunction(mathy5, [(new Number(-0)), -0, '', null, /0/, (new Number(0)), (new String('')), false, '\\0', ({valueOf:function(){return '0';}}), (new Boolean(false)), '0', [], undefined, '/0/', 0.1, NaN, [0], ({valueOf:function(){return 0;}}), 0, (new Boolean(true)), (function(){return 0;}), ({toString:function(){return '0';}}), objectEmulatingUndefined(), true, 1]); ");
Running threw: ReferenceError: 'objectEmulatingUndefined' is not defined
/*FRC-fuzzSeed-58694107*/count=26; tryItOut("mathy2 = (function(stdlib, foreign, heap){ \"\"; var ff = foreign.ff;\n var Int32ArrayView = new stdlib.Int32Array(heap);\n function f(i0, d1)\n {\n i0 = i0|0;\n d1 = +d1;\n var i2 = 0;\n var i3 = 0;\n return +(((Int32ArrayView[((0xa5daeffa)+(0xffffffff)) >> 2])));\n }\n return f; })(this, {ff: encodeURIComponent}, new ArrayBuffer(4096)); testMathyFunction(mathy2, /*MARR*/[(void 0), false, (void 0), false, false, false, (yield -21), false]); ");
Plain eval!
/*FRC-fuzzSeed-58694107*/count=27; tryItOut("mathy4 = (function(stdlib, foreign, heap){ \"\"; var ff = foreign.ff;\n function f(i0, i1)\n {\n i0 = i0|0;\n i1 = i1|0;\n i1 = (x * b);\n {\n i0 = (0xa9b3c950);\n }\n i1 = (0xfa09be60);\n i1 = (i0);\n return (((i0)-(i0)))|0;\n }\n return f; })(this, {ff: this}, new ArrayBuffer(4096)); testMathyFunction(mathy4, [-(2**53+2), 0, -0x100000001, 1, -Number.MAX_SAFE_INTEGER, Math.PI, -0, 0.000000000000001, 0x100000000, -Number.MAX_VALUE, 0x080000000, Number.MAX_VALUE, 1/0, 0x0ffffffff, -Number.MIN_VALUE, 42, -0x080000000, 0/0, (2**53), (2**53)+2, 0x100000001, -(2**53-2), -0x07fffffff, Number.MIN_VALUE, -Number.MIN_SAFE_INTEGER, 0x080000001, Number.MIN_SAFE_INTEGER, -(2**53), (2**53)-2, Number.MAX_SAFE_INTEGER, -0x0ffffffff, -0x100000000, -1/0, -0x080000001, 0x07fffffff, 1.7976931348623157e308]); ");
可以看到有很多不一样的,比如tryItOut
,这个实际上是Funfuzz自己定义的,一个复杂的函数,它的内容如下:
垃圾回收
DUPTRY自定义FUZZ关键字处理
,我们暂时不管
JS STRICT MODE为代码自动加上'use strict'
,不管,因为NScript根本不支持:
input:a=4;
evaluation result: 4
input:'use strict';a=4;
evaluation result: 4
创建new Function
,将代码传给Function,如果有compile error,抛出compile error。
输出字面代码
执行代码
其实我们就简化一下,直接把它包装成一个try catch即可。
testMathyFunction
(a
,b
)是另一个test类型的函数,调用a
(b
),并输出结果,我们对结果其实并不是非常感兴趣,简单起见可以在里面直接调用a(b)。
mathy*
属于动态生成的函数,这部分需要提前拿到,并丢给NScript。
if (rnd(5)) {
if (rnd(8)) {
s += "mathy" + i + " = " + makeMathFunction(6, b, i) + "; ";
} else {
s += "mathy" + i + " = " + makeAsmJSFunction(6, b) + "; ";
}
}
这里makeMathFunction和makeAsmJSFunction均不好直接移植,同时你也可以看出来为什么我对funfuzz的代码反映这么大,全是d、b、i这样的参数,根本没法明白地看清楚函数在干什么。
好在我们可以忽略它在干啥,在上面s += ‘mathy’…… 的时候,我们就可以为这里加上一个特殊的注释,然后抛出去。ChakraCore在收到带有这种注释的输出时,直接通过socket将数据发送给NScript备用。 NScript同时减少为了增熵数据的量,填入这里有用的函数代码。
function makeMathFunction(d, b, i)
{
if (rnd(TOTALLY_RANDOM) == 2) return totallyRandom(d, b);
var ivars = ["x", "y"];
if (rnd(10) == 0) {
// Also use variables from the enclosing scope
ivars = ivars.concat(b);
}
return "(function(x, y) { " + directivePrologue() + "return " + makeMathExpr(d, ivars, i) + "; })";
}
除去这些,我们可以再看一下NScript对基础数据类型的支持:
input:var x = new RegExp('d');x;
evaluation result: /d/
input:var x = new Array('d');x;
evaluation result: d
input:var x = new Function('g(){}');x;
evaluation result: [object Function]
input:var x = new Image('');x;
evaluation result: ReferenceError: 'Image' is undefined
input:var x = new Int32Array('');x;
evaluation result: ReferenceError: 'Int32Array' is undefined
input:var x = new DataView('');x;
evaluation result: ReferenceError: 'DataView' is undefined
input:var x = new HTMLDivElement('');x;
evaluation result: ReferenceError: 'HTMLDivElement' is undefined
input:function SomeObj(x){log(x);}; SomeObj.y = "1"; SomeObj.prototype.oops = function(){log(SomeObj.y)}; var xx = new SomeObj("2"); xx.oops();
evaluation result: 2
evaluation result: 1
evaluation result: undefined
input:Infinity
evaluation result: Infinity
input:Error
evaluation result: [object Function]
input:Date
evaluation result: [object Function]
input:JSON
evaluation result: ReferenceError: 'JSON' is undefined
input:Math
evaluation result: [object Math]
input:Map
evaluation result: ReferenceError: 'Map' is undefined
input:Proxy
evaluation result: ReferenceError: 'Proxy' is undefined
input:String
evaluation result: [object Function]
input:TypedArray
evaluation result: ReferenceError: 'TypedArray' is undefined
input:parseFloat
evaluation result: [object Function]
input:parseInt
evaluation result: [object Function]
input:eval
evaluation result: [object Function]
input:typeof escape === typeof unescape
evaluation result: true
input:ArrayBuffer
evaluation result: ReferenceError: 'ArrayBuffer' is undefined
input:void 0
evaluation result: undefined
input:encodeURIComponent
evaluation result: [object Function]
可以发现
DOM相关的,大部分不支持
ES5+的不支持
JSON不支持
本文来自http://nul.pw,作者blast,转载请注明
然后,让我们看一些常见的对象:
input:for(var p in Math) log(p)
evaluation result: abs
evaluation result: acos
evaluation result: asin
evaluation result: atan
evaluation result: atan2
evaluation result: ceil
evaluation result: cos
evaluation result: exp
evaluation result: floor
evaluation result: log
evaluation result: max
evaluation result: min
evaluation result: pow
evaluation result: random
evaluation result: round
evaluation result: sin
evaluation result: sqrt
evaluation result: tan
evaluation result: E
evaluation result: LN10
evaluation result: LN2
evaluation result: LOG2E
evaluation result: LOG10E
evaluation result: PI
evaluation result: SQRT1_2
evaluation result: SQRT2
evaluation result: undefined
以及:
input:for(var p in Number) log(p)
evaluation result: prototype
evaluation result: constructor
evaluation result: MAX_VALUE
evaluation result: MIN_VALUE
evaluation result: NaN
evaluation result: POSITIVE_INFINITY
evaluation result: NEGATIVE_INFINITY
evaluation result: undefined
还有 String:
input:for(p in String) log(p)
evaluation result: fromCharCode
evaluation result: prototype
evaluation result: prototype
evaluation result: undefined
在这里我们看到了很多不支持的东西,因此只要攻击者能够去简单检测一下,就可以绕过这个evaluation……
input:for(p in window) log(p)
evaluation result: Date
evaluation result: Scripting
evaluation result: MSXML2
evaluation result: ADODB
evaluation result: WScript
evaluation result: Enumerator
evaluation result: WMI
evaluation result: WinHTTP
evaluation result: Shell
evaluation result: WSH
evaluation result: ActiveXObject
evaluation result: GetObject
evaluation result: d
evaluation result: ScriptEngineBuildVersion
evaluation result: deconcept
evaluation result: hex2bin
evaluation result: rc4
evaluation result: log
evaluation result: dump
evaluation result: p
evaluation result: undefined
input:for(p in Object) log(p)
evaluation result: prototype
evaluation result: undefined
input:for(p in Function) log(p)
evaluation result: prototype
evaluation result: undefined
input:for(p in Array) log(p)
evaluation result: prototype
evaluation result: undefined
以及arguments:
input:function p(){for(x in arguments) log(x)} p()
evaluation result: undefined
所以看起来要对Funfuzz再一次做一个大工程,把不兼容的内容全部换成兼容代码。