关闭
Hit
enter
to search or
ESC
to close
May I Suggest ?
#leanote #leanote blog #code #hello world
Mutepig's Blog
Home
Archives
Tags
Search
About Me
domato
无
850
1
0
mut3p1g
# 0x01 github 项目地址:https://github.com/googleprojectzero/domato ## 1. 使用方法 生成一个`html`的样本: ``` python generator.py <output file> ``` 生成多个样本到某个目录下,他们会被命名为`fuzz-<number>.html`。同时生成多个样本会更快。 ``` python generator.py --output_dir <output directory> --no_of_files <number of output files> ``` ## 2. 代码结构 首先看一下包含的`py`文件: ``` ./generator.py ./grammar.py ./mathml/test.py ./jscript/generator.py ./canvas/generator.py ``` 其中`generator.py`为最主要的脚本,它包含了`grammar.py`,里面包括一些辅助函数用于`DOM fuzzing`。 `grammar.py`包含与浏览器无关的生成引擎,可用于其他`非DOM`的`fuzzer`。 然后看一下`txt`文件,他们是语法的定义,其中下面前三个是主要的语法 ``` ./html.txt ./css.txt ./js.txt ./common.txt ./attributevalues.txt ./mathml/mathattrvalues.txt ./mathml/mathml.txt ./svg.txt ./cssproperties.txt ./jshelpers.txt ./jscript/jscript.txt ./canvas/canvas.txt ./tagattributes.txt ./svgattrvalues.txt ``` ## 3. 自定义语法 如果需要用自定义语法来生成`payload`的话,参照下面的代码: ``` from grammar import Grammar my_grammar = Grammar() my_grammar.parse_from_file('input_file.txt') result_string = my_grammar.generate_symbol('symbol_name') ``` ## 4. 基本语法 基本语法的格式是作者自定义的,格式如下: ``` <symbol> = a mix of constants and <other_symbol>s ``` 每条语法都包含左符号和右符号(符号即`<symbols>`, 相当于变量),左符号一般都是固定的,而右符号会被递归展开。 下面是一个`demo`: ``` <cssrule> = <selector> { <declaration> } <selector> = a <selector> = b <declaration> = width:100% ``` 那么可以得到的结果有两条: ``` a { width:100% } or b { width:100% } ``` 同时,符号还能给它添加属性,如下: ``` <selector p=0.9> = a <selector p=0.1> = b ``` 其中`p`属性表示概率,那么`a`出现的几率就会比`b`出现的几率大不少;如果没注明的话则概率相近。 那么这里就出现了一个问题,语法定义中用到了标签`<>`,但是`html`里面必然也会出现`<>`。所以作者使用了`<lt>`和`<gt>`来代替它们,如下: ``` <html> = <lt>html<gt><head><body><lt>/html<gt> <head> = <lt>head<gt>...<lt>/head<gt> <body> = <lt>body<gt>...<lt>/body<gt> ``` 还有一些内置的符号,以及上面提到的属性,都在单独的部分定义好了。 ## 5. 生成编程代码 下面针对编程代码(我觉得主要是js)的变量进行举例: ``` !varformat fuzzvar%05d !lineguard try { <line> } catch(e) {} !begin lines <new element> = document.getElementById("<string min=97 max=122>"); <element>.doSomething(); !end lines ``` 如果指定生成5行代码,那应该生成类似下面的代码: ``` try { var00001 = document.getElementById("hw"); } catch(e) {} try { var00001.doSomething(); } catch(e) {} try { var00002 = document.getElementById("feezcqbndf"); } catch(e) {} try { var00002.doSomething(); } catch(e) {} try { var00001.doSomething(); } catch(e) {} ``` 需要注意下面几点: * 编程语言由`!begin lines`和`!end lines`包含了起来 * `<new element>`表示生成一个新的变量,而`<element>`表示使用之前生成变量 * `<string ...>`为自定义的标签,表示随机生成字符串,且通过`min`和`max`限制了生成字符串的长度 * [可选] 可以通过`!varformat`来定义生成变量的变量名格式 * [可选] 可以通过`lineguard`来定义每一行代码的格式,而`<line>`表示生成的代码 * 除了`!begin lines`还能用`!begin helperlines`,没看懂是干啥的 ## 6. 注释 可以用`#`来表示注释行 ## 7. 防止无限递归 为了防止无限递归,可以用类似下面的代码: ``` !max_recursion 10 <test root=true> = <foobar> <foobar> = foo<foobar> <foobar nonrecursive> = bar ``` 其中,`!max_recursion`表示最大递归层数(默认为50),而`nonrescursive`属性表示该语法为`非递归`,那么一旦达到定义的最大递归层数,则会强制使用`非递归`语法。 ## 8. 包含/引用其他语法文件 包含其他语法文件的代码如下, ``` !include other.txt ``` 而引用其他语法文件的代码如下: ``` !import other.txt ``` 这样让解析器创建一个新的对象`Grammare`,通过`<import>`标签来进行引用: ``` <cssrule> = <import from=css.txt symbol=rule> ``` ## 9. 包含python代码 直接给代码: ``` !begin function savesize context['size'] = ret_val !end function !begin function createbody n = int(context['size']) ret_val = 'a' * n !end function <foo root> = <header><cr><lf><body> <header> = Size: <int min=1 max=20 beforeoutput=savesize> <body> = <call function=createbody> ``` 通过`!begin function savesize`和`!end function`可以定义一个`python`的函数,调用的方法有俩: * 通过属性`beforeoutput` * 通过`<call function=function_name>` 每个`python`的函数默认有变量: * context:样本生成过程中的全局字典,可以设置一些值让其他函数也使用。 * attributes: 与当前正在处理的符号对应的属性的字典,可以通过`attributes[x]=y`来将该符号的`x`属性设置为`y` * ret_val: 函数调用结束后输出的值。 ## 10. 内置符号 在`grammer.py`中定义: ``` self._constant_types = { 'lt': '<', 'gt': '>', 'hash': '#', 'cr': chr(13), 'lf': chr(10), 'space': ' ', 'tab': chr(9), 'ex': '!' } self._built_in_types = { 'int': self._generate_int, 'int32': self._generate_int, 'uint32': self._generate_int, 'int8': self._generate_int, 'uint8': self._generate_int, 'int16': self._generate_int, 'uint16': self._generate_int, 'int64': self._generate_int, 'uint64': self._generate_int, 'float': self._generate_float, 'double': self._generate_float, 'char': self._generate_char, 'string': self._generate_string, 'htmlsafestring': self._generate_html_string, 'hex': self._generate_hex, 'import': self._generate_import, 'lines': self._generate_lines } ``` ## 11. 符号属性 * root: 只能设置为`true`,表示是否为根符号;如果调用`GenerateSymbol()`时没有符号设置该属性,则会生成一个根符号 * nonrecursive: 非递归属性 * new: 只能设置为`true`,表明是生成一个新的符号而不是拓展符号 * from, symbol: 从其他语法导入语法时使用 * count: 指定要创建多少行 * id: 标记某几个符号应当共享一样的值 * min, max: 设置数字的最小最大值,以及限制生成字符串的集合 * b,be: 指定小端序`b` 或者大端序`be`) * code: 在`char`符号中指定确切字符集合 * minlength, maxlength: 定义字符串的长度 * up: 用于指定16进制以大写输出(默认小写) * function:用于符号`call` * beforeoutput: 调用自定义`python`脚本 # 0x02 blog 博客地址:https://googleprojectzero.blogspot.com/2017/09/the-great-dom-fuzz-off-of-2017.html https://www.sigpwn.io/blog/2018/4/14/domato-fuzzers-generation-engine-internals # 0x03 语法编写样例 ## 1. js/template.html 首先,作者给了`html`的基本元素: ``` <!-- saved from url=(0014)about:internet --> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=8"></meta> </head> <body> <script language="Jscript.Encode"> ``` 接着,定义了1个数组用来记录变量,以及一个`main`函数及10个有3个参数的自定义函数。这些函数中都有`alert`以方便崩溃后快速定位崩溃位置,同时会记录每个函数调用的次数这里限定的是每个函数最多调用3次。 ``` var vars = new Array(100); var runcount = {main:0, f0:0, f1:0, f2:0, f3:0, f4:0, f5:0, f6:0, f7:0, f8:0, f9:0} function main() { runcount.main++; if(runcount.main>2) return; //alert('main'); <jsfuzzer> } function f0(arg1, arg2, arg3) { runcount.f0++; if(runcount.f0>2) return; //alert(0); <jsfuzzer> } ``` 最后就是定义变量了,先定义了20个大小为10的数组,接着定义了20个简单的字符串,再定义了20个`dom`元素,再定义了30个最基本的对象,最后10个位上面声明的10个函数。 ``` for(var i=0;i<20;i++) { vars[i] = new Array(10); } for(var i=20;i<40;i++) { vars[i] = 'aaaaaaaaaa'; } for(var i=40;i<60;i++) { vars[i] = document.createElement("foo"); } for(var i=60;i<90;i++) { vars[i] = {}; } vars[90] = f0; vars[91] = f1; vars[92] = f2; vars[93] = f3; vars[94] = f4; vars[95] = f5; vars[96] = f6; vars[97] = f7; vars[98] = f8; vars[99] = f9; main(); ``` ## 2. js/jscript.txt ### 1) init ``` <root root=true> = <lines count=1000> # 设置根符号 !lineguard try { <line> } catch(e) { } # 设置每一行代码的格式 ``` ### 2) 变量的声明 下面挑一些比较重要的分析一下 * fuzzint 设置了一些小整数,十的倍数,以及`<largeint>` * largeint 设置了几个大整数,临近各个整形的溢出值 * property 设置了一些常见的属性 * propertyorindex 由`<fuzzint>`和`<property>`构成 * param 参数组成如下: ``` <param> = <var> <param> = <fuzzint> <param> = true <param> = false <param> = Infinity <param> = 'a' <param> = <arg> ``` * arg 组成为`arg1`、`arg2`.. * propertydescriptorfield ``` <propertydescriptorfield> = get: <function> <propertydescriptorfield> = set: <function> <propertydescriptorfield> = enumerable: <param> <propertydescriptorfield> = writable: <param> <propertydescriptorfield> = configurable: <param> <propertydescriptorfield> = value: <param> ``` * f_num ``` <int min=0 max=100> ``` * function 组成为`f1`、`f2`.. * 随机字符串 ``` <fuzzstring> = <fuzzstringpart> <fuzzstring> = <fuzzstringpart> + <fuzzstringpart> <fuzzstring> = <fuzzstringpart> + <fuzzstringpart> + <fuzzstringpart> <fuzzstringpart> = Array(<repeatcount>).join(<repeatstr>) <repeatcount> = 17 <repeatcount> = 65 <repeatcount> = 257 <repeatcount> = 1025 <repeatcount> = 4097 <repeatcount> = 65537 <repeatstr> = String.fromCharCode(<int min=0 max=127>) <repeatstr> = String.fromCharCode(<int min=0 max=127>, <int min=0 max=127>) <repeatstr> = String.fromCharCode(<int min=0 max=127>, <int min=0 max=127>, <int min=0 max=127>) ``` * 变量 这里的变量以及返回值都是数组 ``` <var> = vars[<int min=0 max=99>] <retvar> = vars[<int min=0 max=99>] ``` ### 3) 代码 * 变量的定义 ``` <var> = Array; <var> = ActiveXObject; <var> = Date; <var> = Boolean; <var> = Enumerator; <var> = Error; <var> = Function; <var> = JSON; <var> = RegExp; <var> = Object; <var> = new Array(<fuzzint>); <var> = {}; <var> = <fuzzstring>; <var> = this; <var> = <function>; ``` * 变量的使用 这里都是先通过临时变量`ret`获取返回值,若返回值存在再记录到`<retvar>`中 ``` var ret = <arg>; if(ret) <retvar> = ret; # 直接利用arg var ret = <var>(<param>, <param>, <param>, <param>, <param>); if(ret) <retvar> = ret; # 调用函数 var ret = new <var>(<param>, <param>, <param>, <param>, <param>); if(ret) <retvar> = ret; # 新建对象实例 var ret = <var>.call(<var>, <param>, <param>, <param>, <param>, <param>); if(ret) <retvar> = ret; # 通过call对函数进行调用 var ret = new <var>.call(<var>, <param>, <param>, <param>, <param>, <param>); if(ret) <retvar> = ret; # 通过call对函数进行调用后的结果是一个对象并创建该对象的实例 var ret = <var>.apply(<var>, <param>); if(ret) <retvar> = ret; # 通过apply对函数进行调用 var ret = new <var>.apply(<var>, <param>); if(ret) <retvar> = ret; # 通过apply对函数进行调用后的结果是一个对象并创建该对象的实例 ``` 不过这里我对`call`和`apply`的概念不是很清楚,再学习一下: 这两个的作用起始是一样的,只不过`call`是在知道参数个数的情况下使用,而`apply`是不知道参数个数的时候使用 ``` 这里的this可以是任何对象 func.call(this, arg1, arg2); func.apply(this, [arg1, arg2]) ``` * 变量属性 ``` <var>.<property> = <param>; var ret = <var>.<property>; if(ret) <retvar> = ret; ``` * 变量数组 ``` <var>[<fuzzint>] = <param>; var ret = <var>[<fuzzint>]; if(ret) <retvar> = ret; ``` * 对象 ``` # 初始化 var ret = new Array(); if(ret) <retvar> = ret; var ret = new Array(<param>); if(ret) <retvar> = ret; var ret = new Array(<param>, <param>, <param>); if(ret) <retvar> = ret; var ret = Array(); if(ret) <retvar> = ret; var ret = Array(<param>); if(ret) <retvar> = ret; var ret = Array(<param>, <param>, <param>); if(ret) <retvar> = ret; var ret = []; if(ret) <retvar> = ret; var ret = [<param>, <param>, <param>]; if(ret) <retvar> = ret; # 函数调用 var ret = Array.prototype.push.call(<var>); if(ret) <retvar> = ret; var ret = Array.prototype.push.call(<var>, <param>); if(ret) <retvar> = ret; var ret = Array.prototype.push.call(<var>, <param>, <param>); if(ret) <retvar> = ret; ```
觉得不错,点个赞?
提交评论
Sign in
to leave a comment.
No Leanote account ?
Sign up now
.
0
条评论
More...
文章目录
No Leanote account ? Sign up now.