使用ChakraCore来Fuzz NScript(3)——构建符合NScript的Funfuzz脚本

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再一次做一个大工程,把不兼容的内容全部换成兼容代码。

标签:none

添加新评论

captcha
请输入验证码