从零开始学Fuzzing系列:浏览器fuzz工具探究之框架篇

2016-01-15 457583人围观 ,发现 6 个不明物体 头条工具

原创作者:walkerfuz


0×00写在前面

工欲善其事,必先利其器。笔者收集了近几年Github、Googlecode、SourceForge等站点发布的30余款浏览器漏洞挖掘工具,除相似重复外,几乎涵盖了所有已公开的开源项目,尽可能搭建环境试用、阅读源码、查阅资料,搞清了其中采用的技术原理,初步形成了这篇半叙述形式的分析报告。

希望通过本篇小文,能与大家共同领略前辈们在浏览器漏洞fuzz这一方向上留下的足迹与智慧。

备注:绿盟刘永军老师的《浏览器fuzz框架介绍》已对部分工具进行过介绍,行文简洁,值得拜读。鉴于原文涉及工具的详细实现较少,故撰写此文以作补充归纳,希望能向大家展现当前浏览器fuzz工具开发的基本思路,以供学习探讨。

0×01分类汇总

涉及的所有fuzz工具列表如下,若有感兴趣的童鞋,请Google之:

这些工具中,有的侧重于浏览器fuzz框架的设计,有的侧重于网页样本的生成策略。比如:

框架类:bamboo.js BFuzzer grinder cross_fuzz x-fuzzer
策略类:nduja fileja
综合类:clusterfuzz funfuzz chromefuzzer ajaxdemolisher lithium

其中Google团队的clusterfuzz堪称一套完善的分布式fuzz系统,未公开源码,只能从网上公开的使用说明窥探一二,12年已部署了几百台虚拟机同时fuzz,允许内部使用者提交fuzzer插件;Firefox团队的funfuzz(包含jsfunfuzz和DOMFuzz)也颇具影响。不得不提的是,国内绿盟团队demi6od大神开发的chromefuzzer,也颇具优秀的漏洞发现能力(demi6od本人多次获得了微软和谷歌的致谢)。

这些工具在核心框架的基础上,都增加了分布式调度、自定义fuzz策略、样本精简等特性,工程量巨大,待笔者研究透彻后分享出来。今天主要向大家介绍偏重于fuzz框架设计的五个基本工具的实现。

从本质上讲,浏览器fuzz框架需要解决以下几个关键问题:

1.随机样本的生成
2.浏览器进程监控
3.Crash样本保存

由于开发者思考角度不同,每个框架在这些问题的处理上,也许类似,也许不同。下面详述之。

0×02 Bamboo.js

这是一款在Fuzz效率和稳定性都有所兼顾的DOM Fuzzer,采用ruby语言结合Javascript共同完成,具有以下特点:

a.The fuzzing scope contains DOM level 1,2 and 3
b.The main module triggers semi-random object modifications and creates insecure references
c.Other modules can be added easily
d.Reliable logging by using WebSockets
e.Supported targets

项目源代码的目录结构如下:

bamboo.htm
bamboo.js
config.js
modules
 -tickle_references.js
server.rb
helper.js

经过梳理得知,该框架的核心流程如下图所示:

Bamboo首先生成随机进行DOM操作的Javascript语句,将其保存为字符串发送至服务端,由服务端根据该字符串组合为一个完整的网页样本(保存为log文件)。

然后依靠WebSocket通信将该网页样本从服务端返回至浏览器进程,由bamboo.js将该网页赋值给一个事先构造的iframe标签,从而达到加载执行网页样本的目的。

若测试过程中,网页样本导致浏览器进程崩溃,则可以断定服务端当前最近保存的log文件即为导致Crash的漏洞样本;若不崩溃,浏览器进程会根据SetTimeout设定的时间间隔,重新进行上述样本生成和iframe加载执行的fuzz过程。

样本字符串的生成具体由modules/*.js完成,官方源码自带的tickle_references.js插件部分摘录如下:

function fuzzOwnReferences(count)
{
  ......
  //R(2)和R(97)等函数为随机数函数,可以生成0~N-1之间的任意整数。
 if(r(2)>0)
    payload += 'getRandomObject(' + r(97) + ').appendChild(e_1);\n';
  else
    payload += 'document.body.appendChild(e_1);\n';

由上得知,本框架支持自定义样本生成策略,使用者可以编写自定义fuzz策略的插件放置在Modules目录。

浏览器和服务端采用WebSocket进行通信。Bamboo.js向服务端Server.rb发送生成的字符串,并接收服务端返回的网页样本:

function wsSwap(data)
{
  ws = new WebSocket("ws://" + host + ":5678");
  ws.onclose = function(evt){}
  ws.onerror = function(evt){}
  ws.onopen = function(evt){
    ws.send(data);
  }
  ws.onmessage = function(evt){
    createBuffer(evt.data)
  }
}

Server.rb主要作用是,将接收的字符串组合为完整的网页样本并保存为bamboo.log,然后反馈至浏览器进程:

def generate_template
  in_file = File.read("template.dat")
  return "<script src='http://localhost/bamboo/helper.js'></script>" + in_file
end
EM.run do
  WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 10933) do |ws|
    ws.onmessage do |data, type|
      chunk = [generate_template + "\n<script>", "</script>\n</html>"]
      File.open("bamboo.log", "w") { |f| f.write(chunk[0] + data + chunk[1]) }
      ws.send Base64.encode64(chunk[0] + data + chunk[1]), :type => type
    end
  end
end

浏览器进程接收的网页样本交由iframe标签加载执行:

//Bamboo.js
function createBuffer(data)
{
  document.getElementById('buffer').src = 'data:text/html;base64,' + data;
}
//Bamboo.htm
<body>
<iframe id="buffer"></iframe>
</body>

目前Bamboo框架缺少浏览器进程崩溃检测模块,出现Crash后需手动重启浏览器重新fuzz,自动化程度有待提高。

0×03 BFuzzer

BFuzzer是国内瀚海源团队的Hikerell采用Python开发的一款浏览器fuzz框架。

这款框架不同于Bamboo.js的地方在于,它将随机生成Javascript语句(随机进行DOM操作)的任务交给了Python脚本来完成。浏览器向服务端申请网页样本,服务端在收到请求后,由Python随机生成进行DOM操作的网页样本,反馈给浏览器进程加载执行,其核心fuzz逻辑如下图:

框架采用pydbg监控浏览器进程是否出现异常或崩溃。每次fuzz循环都会调用浏览器进程加载样本网页,若浏览器进程无异常,则强制杀死进程,进入下一次循环。很容易得知,这样的fuzz循环因进程调用频繁会造成耗时太久。

备注:可考虑单次循环按序加载多个网页样本作为改进措施,只是需要特别留意因多个网页共同作用造成浏览器进程出现异常或崩溃这一场景下Crash样本的保存与还原。

该项目源代码的目录结构(python2.7编写)如下:

Server.py
rGener
 -fuzz.py
 -templater.py
Monitor.py
Fuzzutil
 -Crasher.py

为保证逻辑简洁,该框架在实现上划分为Monitor.py和Server.py两部分。

Server.py:服务端,只负责样本网页的生成与反馈
Monitor.py:监控器,负责Fuzz循环、进程调用和URL加载、异常监控等

整体实现原理如下图:

Server.py只负责为浏览器请求提供随机网页样本,并为监控进程请求提供最近生成的网页用于Crash样本保存:

class FuzzRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):
        global curHTML
        if 'next' in self.requestline:  # 处理随机生成样本请求
            curHTML = fuzz.getNext()
            self.send_response(200)
            self.wfile.write(curHTML)
        elif 'cur' in self.requestline:  # 处理Crash样本请求
            self.send_response(200)
            self.wfile.write(curHTML)

其中fuzz.getNext会调用rGener目录中的fuzz.py和templater.py,用以随机生成网页样本的内容:

def node_add_by_applyElement(self, id_child, id_parent):
    r = random.randint(0,3)
    if r<2:
        cxt = "document.createElement('"+random.choice(HTMLs[1:])+"')"
        return cxt+".applyElement("+id_parent+");"
    else:
        return id_child+".applyElement("+id_parent+");"

最终得到的网页样本则会返回给浏览器进程加载执行。

Monitor.py是该框架的主逻辑,主要负责调用浏览器进程去访问http://host:port/init(init会跳转到http://host:port/next获取样本):

class moniter():
  def run(self):
    while 1:
      os.system('taskkill /T /F /IM '+ self.cf.image + '> logs/null')
      time.sleep(3)
      dbg = pydbg.pydbg()
      dbg.load(self.cf.targetpath, command_line=self.InitPage)
      time.sleep(1)
      dbg_browser = self.crasher.hook(dbg)
      if dbg_browser!=None:
        dbg_browser.run()
        dosfile = self.cf.logspath + '\\dos-' + hashlib.md5(str(datetime.now())).hexdigest() + '.html'
        dosurl = 'http://'+self.cf.host + ':' + self.cf.port + '/cur'
        urllib.urlretrieve(dosurl, dosfile)

Monitor在fuzzutil目录中的crasher.py完成了pydbg的监控逻辑。首先将pydbg附加到符合条件的iexplore.exe进程:

class crasher():
  def hookIE(self, dbg):
    loadpid = dbg.pid
    dbg.detach()
    dbg = pydbg()
    dbg.cf = self.cf
    pattern = r'iexplore.exe\s*([0-9]*)\s*Console'
    count = 0
    while count<=1:
      p = os.popen('tasklist|find "iexplore"')
      pids = re.findall(pattern, p.read())
      count = len(pids)
    for pid in pids:
      if loadpid == int(pid): # 注意这里
        continue
      try:
        dbg.attach(int(pid))
        dbg.set_callback(EXCEPTION_ACCESS_VIOLATION, deal_accessv)
        return dbg
      except Exception, e:
        return None

为什么这里说是符合条件呢?这里面包含了一个小技巧。作者调用pydbg的顺序是这样的:

pydbg.load
pydbg.detach
pydbg.attach
pydbg.setcall_back

注意上面的逻辑,展现了作者调用pydbg的思维。熟悉IE进程调用方式的童鞋可能了解,x64下的IE浏览器会通过一个64位的IE进程打开一个32位的IE进程去加载实际的网页内容(在任务管理器中会存在两个iexplore.exe进程)。一般情况下造成异常或崩溃的进程通常都是那个32位的进程,并不是pydbg.load获得的x64位IE进程的PID。

作者这样做是为了能attach到正确的进程,以便能获得正确的现场快照。

然后是处理EXCEPTION_ACCESS_VIOLATION异常的流程:

def deal_accessv(dbg):
  if dbg.dbg.u.Exception.dwFirstChance:
    return DBG_EXCEPTION_NOT_HANDLED
  crash_bin = utils.crash_binning.crash_binning()
  crash_bin.record_crash(dbg)
  name = hashlib.md5(str(datetime.datetime.now())).hexdigest()
  crashfile = dbg.cf.logspath + '\\crash-'+name+'.txt'
  f = open(crashfile, 'w')
  f.write(crash_bin.crash_synopsis())
  f.close()
  pocfile = dbg.cf.logspath + '\\poc-' + name + '.html'
  pocurl = 'http://'+dbg.cf.host + ':' + dbg.cf.port + '/cur'
  urllib.urlretrieve(pocurl, pocfile)
  dbg.terminate_process()
  return DBG_EXCEPTION_NOT_HANDLED

将通过http://host:port/cur请求得到的POC样本和pydbg得到的Crash现场信息分别保存。

BFuzzer框架模块之间低耦合,使用者可以通过修改template.py生成自定义网页样本内容,初步具备了自动化Fuzz的能力,当然还有很多需要优化的地方。

0×04 Grinder

Grinder可以说是最广为人知的浏览器Fuzz框架了,采用ruby语言编写,著名的nduja、fileja等工具的自动化部署默认都以它作为支撑环境。相对精简的Crash样本、优秀的分布式能力使其得到了很多使用者的喜爱。但熟悉它的人肯定对它又爱又恨,因为时常会出现某些Crash无法重现的情况。下面我们结合之前写的文章讲解一下Grinder架构,或许你就能明白无法复现的原因了。

该项目源代码的目录结构如下:

node
  -browser
     chrome.rb
     firefox.rb
     internetexplorer.rb
     safari.rb
  -core
    debug
      debugger.rb
      debuggerexception.rb
      heaphook.rb
      hookedprocess.rb
      logger.rb
      processsymbols.rb
    configuration.rb
    crypt.rb
    debugger.rb
    logging.rb
    server.rb
    webstats.rb
    xmlcrashlog.rb
  -crashes
  -data
  -fuzzer
    *.html
  -lib
    metasm
  -source
    --部分dll的源码
  config.rb
  crypto.rb
  grinder.rb
  reduction.rb
  testcase.rb
server
  --主要用于分布式节点的漏洞结果汇总,这里不再详述

在使用时分为两部分,node节点和server端。

node:负责Fuzz的主逻辑
server:负责所有节点的结果收集

这里的Server端是为分布式挖掘建立的集中管理服务器。如果只想单机进行挖掘,只运行node目录下的相关脚本即可。

node节点开始fuzz的命令为:

ruby grinder.rb [--config=config.rb] --browser=BROWSER

如果fuzz过程中出现Crash,则会在Crashes目录生成记录样本信息的*.log文件和记录崩溃现场的*.crash文件。若提前在config.rb中指定了用于上报漏洞的Server网址,则在发现Crash后会将上述文件上报至Server端。config.rb中关于上报至Server端的网址配置示例如下:

# Configure any remote grinder web server to record crashes...
# Set to nil to disable this feature.
# Note: dont specify the http/https part.
$webstats_baseurl = '192.168.1.1/status.php'

在后续漏洞分析之前,使用testcase.rb将*.log转换为网页样本:

ruby testcase.rb [--config= config.rb] --log=*.log --save=*.html

上述就是Grinder基本使用过程。通俗来讲,Grinder的fuzz流程和BFuzzer类似,通过专门的调度进程负责启动、监控被测浏览器,专门的WEB服务器为每次fuzz提供网页样本。

备注:该WEB服务运行于node节点本机,与用于分布式的Server不同

Grinder的核心在于网页样本的生成方式和Crash样本的恢复。Bamboo.js和BFuzzer本质上网页样本都是由WEB服务器静态提供的,也就是说浏览器每次加载执行的网页样本都是在服务端生成反馈过来的,而Grinder不同,它是先从服务端得到网页模板,后续在浏览器加载模板期间,动态生成网页样本并执行的。

下面以一个精简的网页模板作为解释。

<html>
<head>
<title>simple fuzz</title>
<script type='text/javascript'>
elements = ["a","div","button","applet","area","article","aside","audio",  "var","video",  "xmp"];
interesting_values = [
  0, 1, -1, 5e6, -7e6, 8e-6, 2e1000, 0xFFFFFFFF, NaN,false, true, null, 'pink', 'ltr','rtl','auto','copy','move','link','open','controls','#000000', '#ffffff',
];
// Pick a random number between 0 and X
function rand( x ){
  return Math.floor( Math.random() * x );
}
function rand_item( arr ){
  return arr[rand(arr.length)];
}
function fuzz(){
    r = rand_item(elements);
    elem = document.createElement(r);
    for(var p in elem){
      try{
        rr = rand_item(interesting_values);
        elem.setAttribute(p, rr);      
      }catch(exception){
      }
    }
    document.all[0].appendChild(elem);  
}
</script>
</head>
<body onload="fuzz()"></body>
</html>

这是一个对DOM元素属性进行随机赋值以测试是否存在漏洞的样本生成策略,其中rand_item是一个随机化函数,可以随机得到指定数组的元素值。

对于Bamboo和BFuzzer而言,无论使用Javascript字符串还是Python脚本,WEB服务端最终都会生成一个类似于下述网页内容反馈给浏览器用于加载执行:

<html>
<head>
<title>simple fuzz</title>
<script type='text/javascript'>
elements = ["a","div","button","applet","area","article","aside","audio",  "var","video",  "xmp"];
interesting_values = [
  0, 1, -1, 5e6, -7e6, 8e-6, 2e1000, 0xFFFFFFFF, NaN,false, true, null, 'pink', 'ltr','rtl','auto','copy','move','link','open','controls','#000000', '#ffffff',
];
// Pick a random number between 0 and X
function rand( x ){
  return Math.floor( Math.random() * x );
}
function rand_item( arr ){
  return arr[rand(arr.length)];
}
function fuzz(){
    r = “button”;
    elem = document.createElement(r);
    for(var p in elem){
      try{
        rr = '#000000';
        elem.setAttribute(p, rr);      
      }catch(exception){}
    }
    document.all[0].appendChild(elem);  
}
</script>
</head>
<body onload="fuzz()">
</body>
</html>

可以发现,原模板中涉及rand_item随机函数部分都被替换为了实际的某个元素和属性值。浏览器从服务端得到的是一个具体的网页样本,每次循环得到的都不同:

但Grinder不同,Grinder调用的浏览器从WEB端得到的仍旧是携带rand_item随机函数的网页模板:

只不过在Grinder服务端使用的网页模板比原模板多了必要的logger.log语句:

<html>
<head>
<title>simple fuzz</title>
<script type='text/javascript' src='logging.js'></script>
<script type='text/javascript'>
elements = ["a","div","button","applet","area","article","aside","audio",  "var","video",  "xmp"];
interesting_values = [
  0, 1, -1, 5e6, -7e6, 8e-6, 2e1000, 0xFFFFFFFF, NaN,false, true, null, 'pink', 'ltr','rtl','auto','copy','move','link','open','controls','#000000', '#ffffff',
];
// Pick a random number between 0 and X
function rand( x ){
  return Math.floor( Math.random() * x );
}
function rand_item( arr ){
  return arr[rand(arr.length)];
}
var logger = null;
function fuzz(){
    logger = new LOGGER( "SimpleExample" );
    logger.starting();
    r = rand_item(elements);
    logger.log("document.createElement("+r+");","ndujaLogger",1);
    elem = document.createElement(r);
    for(var p in elem){
      try{
        rr = rand_item(interesting_values);
        logger.log("elem.setAttribute(“+p+”,” +rr+");","ndujaLogger",1);
        elem.setAttribute(p, rr);
      }catch(exception){
      }
    }
    logger.log("document.all[0].appendChild(elem);","ndujaLogger",1);
    document.all[0].appendChild(elem); 
    logger.finished();
}
</script>
</head>
<body onload="fuzz()">
</body>
</html>

logger.log最终调用的是Javascript中的parseFloat函数。

Grinder通过向浏览器进程中注入grinder_logger.dll,进而hook住Javascript中的parseFloat函数。这样在调用logger.log时,grinder_logger.dll设置的hook回调函数就可以记录下来其内容,并存储为log文件。比如:

logger.log("document.all[0].appendChild(elem);","ndujaLogger",1);

就可以将下列Javascript语句:

document.all[0].appendChild(elem);

完整记录在log文件中。上述网页模板某次执行时,记录的日志格式类似于:

<fuzzer name="ndujaL" browser="IE">
 <log>
  <idx>1</idx>
  <location>ndujaLogger</location>
  <message> elem = document.createElement(“button”);</message>
  <count>1</count>
 </log>
 <log>
  <idx>2</idx>
  <location> ndujaLogger </location>
  <message> elem.setAttribute(“id”,”move”);</message>
  <count>1</count>
 </log>
 <log>
  <idx>3</idx>
  <location> ndujaLogger </location>
  <message> document.all[0].appendChild(elem);</message>
  <count>1</count>
 </log>
</fuzzer>

如果fuzz过程中引起了异常,Grinder则会将本次执行网页模板得到的log信息存储起来,通过testcase.py即可将log信息恢复为具体的网页。上述log信息会恢复成如下网页:

<html>
<script type='text/javascript'>
function poc(){
  try{elem = document.createElement(“button”); }catch(exception){}
  try{elem.setAttribute(“id”,”move”); }catch(exception){ }
  try{document.all[0].appendChild(elem);  }catch(exception){}
}
</script>
<body onload="poc()">
</body>
</html>

Grinder的精妙之处就在于,将执行的Javascript语句序列动态地通过进程注入记录了下来。当然,技术难点肯定在于对parseFloat函数的hook操作。IE的ParseFloat函数位于jscript9.dll,Firefox早期版本的ParseFloat函数位于mozjs.dll。作者是借助于symbols符号文件来定位该函数的存在的。

这种动态注入的方式,对浏览器进程fuzz稳定性的影响也受到了质疑,有可能是进程注入导致浏览器更加容易崩溃,而不是网页模板导致的。开发Grinder插件的关键也在于对logger.log的正确使用,如果记录的内容和原来执行的内容有出入,就很容易出现无法重现的情况。但无论如何,Grinder还是非常优秀的。

0×05 X-Fuzzer

X-Fuzzer可以说是框架类fuzz工具里面最轻量级的了,其源码文件只有两个:

fuzzer.html(加载x.js)
x.js(主文件)

但这个工具到底该如何使用,倒是让笔者好好琢磨了一阵子。先看一下它的运行界面:

该工具可以对x.js中包含的150余个标签的属性进行随机赋值,以测试是否有漏洞。fuzz操作可分为Start和Auto、Spray和Spray-n-Auto、internode和internode-n-Spray三组。Start和Spray每次fuzz只对单个标签进行赋值,而其余四个都会将所有标签遍历。Start和Spray的不同在于,对属性赋值内容是不同的类型。这里不再详述。

该框架比较有特点的就是,采用document.cookie记录日志信息,采用localStorage在本地存储最近一次fuzz操作的必要信息(假设浏览器崩溃的话,可以根据这些必要信息恢复样本),与grinder中logger.log的作用类似。

备注:从本地调用IE打开网页是不支持localStorage的,必须采用web方式打开网页,测试时需注意。浏览器也不能设置为“退出后清空浏览历史,否则存储的localStorage会被清空”。

目前该工具只是提出了一种优秀的fuzz思想,还不具备自动化fuzz能力。前段时间绿盟公开的NBFuzz框架就是借助了localStorage和XMLHttpRequest特性,和上面几款框架的核心思想类似。

备注:NBFuzz可以通过Websocket代替XMLHttpRequest,则其适用性会更好。

0×06 cross_fuzz

和上述几个框架都不太相似的是,cross_fuzz实质上强调的是一种递归式的浏览器fuzz策略思想,其经典的递归和随机DOM操作可以说对浏览器挖掘产生了深远影响。

其源码目录如下:

cross_fuzz_msie_randomized_seed.html
cross_fuzz_randomized_20100729_seed.html
cross_fuzz_randomized_20110105_seed.html
cross_fuzz_randomized_20110105_seed_TEST.htm
linktocrossfuzz.html
logo.jpg
mersenne.js
-targets
 lolcat.jpg
 target.html
 target.svg
 target.xml
 target.xul
 target2.html
 target_strict.html
 target_strict2.html
 target_xhtml.xhtml
 text6.swf

该工具的使用方法是,浏览器打开主文件cross_fuzz_randomized_*.html,它会随机调用targets目录中两个HTML、XHTML或SVG文档,并根据下面的算法进行fuzzing操作。下面借助于翻译一起欣赏该工具的算法细节:

The fuzzer owes much of its efficiency to dynamically generating extremely long-winding sequences of DOM operations across multiple documents, inspecting returned objects, recursing into them, and creating circular node references that stress-test garbage collection mechanisms.

该模糊器的高效性在很大程度上归功于通过多文档动态产生随机化的冗长的DOM操作序列,检查返回的对象,对其进行递归,并创建用于对垃圾回收机制进行压力测试的循环节点引用。

该框架的fuzzing算法细节如下: 

1.Open two windows with documents of any (DOM-enabled) type. Simple HTML, XHTML, and SVG documents are randomly selected as targets by default - although any other, possibly plugin-supported formats could be targeted instead.

打开两个任意文档类型(启用DOM)。默认会随机选择简单的HTML、XHTML和SVG文件,当然其它一些插件支持的格式也可以针对性地替代。

2.Crawl DOM hierarchy of the first document, collecting encountered object references for later reuse.Visited objects and collected references are tagged using an injected property to avoid infinite recursion; a secondary blacklist is used to prevent navigating away or descending into the master window. Critically, random shuffling and recursion fanout control are used to ensure good coverage.

抓取第一个文档的DOM层次结构,收集遇到的对象引用以备后续使用。访问到的对象和收集的引用会被标记一个注入的属性来避免无限递归;还有一个黑名单列表来防止网页窗口导航离当前开页面或转到主窗口。重要的是,随机打乱对象引用的序列并递归调用控制可以确保良好的覆盖率。

3.Repeat DOM crawl, randomly tweaking encountered object properties by setting them to a one of the previously recorded references (or, with some probability, to one of a handful of hardcoded "interesting" values).

重复DOM抓取操作,调整遇到的对象属性,将其设置为一个先前记录的引用(或者以一定概率设置为一个硬编码的有趣的数值)。

备注:这些硬编码的有趣数值,被预置在HTML文档中的数组。

4.Repeat DOM crawl, randomly calling encountered object methods. Call parameters are synthesized using collected references and "interesting" values, as noted above. If a method returns an object, its output is subsequently crawled and tweaked in a similar manner.

重复DOM抓取,随机调用遇到的对象方法,使用收集的引用和上述有趣数值作为调用参数。如果一个方法返回了一个对象,那么这个对象随后会被抓取,并以上述类似方式作调整。

5.Randomly destroy first document using one of the several possible methods, toggle garbage collection.

使用一些可能的方法随机破坏第一个文档,并切换至垃圾回收。

6.Perform the same set of crawl & tweak operations for the second document, but use references collected from the first document for overwriting properties and calling methods in the second one.

对第二个文档实施同样的抓取和调整操作,但不同的是,使用从第一个文档收集的引用来覆盖第二个对象的属性,并在第二个文档中调用这些对象的方法。

7.Randomly destroy document windows, carry over a percentage of collected references to the next fuzzing cycle.

随机破坏文档窗口,将收集的引用沿用到下一个fuzzing循环。

细细品味cross_fuzz的思想后,深深地被折服,只能说作者太强大了。当然,目前cross_fuzz只是一个演示性的功能模块,需要实现日志记录、异常监控等部分。

0×07 总结

由上可知,浏览器fuzz框架的关键在于随机样本的生成和崩溃样本的记录两者的权衡上。或许看完这篇小文,有童鞋可以结合它们的利弊,写出来一个更好的框架,所以,请期待morph v0.3吧。

*原创作者:walkerfuz,本文属FreeBuf原创奖励计划文章,未经许可禁止转载

Loading...
css.php