0x00: 前言 之前学习过peach的使用,在willj师傅的指导下尝试去fuzz了某播放器,只是个尝试,并没有更深入去搞(本来的计划是结合winafl的),虽然没啥产出,但是fuzz过程还算清晰。过程中实现了自动化的fuzz脚本,有完整的功能,就是效率堪忧-。-
0x01: 关于peach peach 是一款优秀的文件格式fuzz工具。Fuzzing with Peach – Part 1 « Flinkd! ,他这篇文章写的非常好,几乎涵盖了peach 90%的语法,仔细阅读,自己动手实践,会很快入门pit file的编写。
0x02: 文件fuzz的思路 fuzz嘛,简单的来看就是
   构造输入 
   传给目标程序 
   程序状态检测(是否crash) 
   做log 
 
之后根据你的log,把有用的样本拿出来在分析。
   flv文件格式 
   根据文件格式编写pit file 
   如何加载我的fuzz.flv文件? 
   异常检测怎么做 
 
下面慢慢来分析。
flv文件格式flv文件主要分为header和body两个部分。
header部分1 2 3 4 第1-3字节:文件标志,FLV的文件标志为固定的“FLV",字节(0x46, 0x4C,0x56),见上面的字节序和字符序两行; 第4字节:当前文件版本,固定为1(0x01) 第5字节:此字节当前用到的只有第6,8两个bit位,分别标志当前文件是否存在音频,视频。参见上面bit序,即是第5字节的内容; 第6-9字节:此4字节共同组成一个无符号32位整数(使用大头序),表示文件从FLV Header开始到Flv Body的字节数,当前版本固定为9(0x00,0x00,0x00,0x09) 
 
body部分1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ------------------------- |  Previous Tag Size    | ------------------------- |          Tag          | ------------------------- |  Previous Tag Size    | ------------------------- |          Tag          | ------------------------- |  Previous Tag Size    | ------------------------- |          Tag          | ------------------------- |  Previous Tag Size    | ------------------------- 
flv文件格式详解 ,以及是官方的flv格式相关的文档都可以。 
 
   根据文件格式编写pit file
   如何加载我的fuzz.flv文件?
   异常检测怎么做
 
0x03: 编写pit file 首先是针对flv header的部分的编写
1 2 3 4 5 6 7 8 9 10 11 <DataModel  name ="flvHeader" > 	<String  name ="flv_Signature"  value ="464C5601"  valueType ="hex"  token ="true"  mutable ="false" />      	<Flags  name ="HeadFlags"  size ="8" >          	<Flag  name ="dummy"   position ="3"  size ="5" />  			<Flag  name ="audio"   position ="2"  size ="1" />              <Flag  name ="dummy2"  position ="1"  size ="1" />              <Flag  name ="video"   position ="0"  size ="1" />          </Flags >      <Number  name ="dataoffset"  value ="9"  size ="32" />  	<Number  name ="zero"  size ="32" />  </DataModel > 
这部分是script tag部分的编写
1 2 3 4 5 6 7 8 9 10 <Block  name ="script" >     <Number  name ="type"  size ="8"  signed ="false"  endian ="big"  value ="18"  token ="true"  mutable ="false" />      <Number  name ="datasize"  size ="24"  endian ="big"  signed ="false" />      <Number  name ="timestamp"  size ="24"  endian ="big"  signed ="false" />      <Number  name ="timestampi"  size ="8"  endian ="big"  signed ="false" />      <Number  name ="streamid"  size ="24"  endian ="big"  signed ="false" />      <Number  name ="firstbyte"  size ="8"  endian ="big"  signed ="false" />      <Blob  name ="data2"  lengthType ="calc"  length ="int(self.find('datasize').getInternalValue())-1" />      <Number  name ="lastsize"  size ="32"  endian ="big"  signed ="false" />  </Block > 
这部分是audio tag部分的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <Block  name ="audio" > 	<Number  name ="type"  size ="8"  signed ="false"  endian ="big"  value ="8"  token ="true"  mutable ="false" />  	<Number  name ="datasize1"  size ="24"  endian ="big"  signed ="false" />  	<Number  name ="timestamp"  size ="24"  endian ="big"  signed ="false" />  	<Number  name ="timestampi"  size ="8"  endian ="big"  signed ="false" />  	<Number  name ="streamid"  size ="24"  endian ="big"  signed ="false" />  		<Flags  name ="Flag3"  size ="8" >  			<Flag  name ="fmt"  position ="0"  size ="4" />  			<Flag  name ="sr"  position ="4"  size ="2" />  			<Flag  name ="bits"  position ="6"  size ="1" />              <Flag  name ="channels"  position ="7"  size ="1" />  		</Flags >          <Block >          	<Relation  type ="when"  when ="int(self.find('Flag3.fmt').getInternalValue()) == 10" />              <Blob  name ="frmtype"  length ="1" />              <Blob  name ="data1"  lengthType ="calc"  length ="int(self.find('datasize1').getInternalValue())-2" />          </Block >  		<Block >          	<Relation  type ="when"  when ="int(self.find('Flag3.fmt').getInternalValue()) != 10" />              <Blob  name ="data1"  lengthType ="calc"  length ="int(self.find('datasize1').getInternalValue())-1" />          </Block >  	<Number  name ="lastsize"  size ="32"  endian ="big"  signed ="false" />  </Block > 
这部分是video tag的部分的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <Block  name ="video" > 	<Number  name ="type"  size ="8"  signed ="false"  endian ="big"  value ="9"  token ="true"  mutable ="false" />  	<Number  name ="datasize2"  size ="24"  endian ="big"  signed ="false" />  	<Number  name ="timestamp"  size ="24"  endian ="big"  signed ="false" />  	<Number  name ="timestampi"  size ="8"  endian ="big"  signed ="false" />  	<Number  name ="streamid"  size ="24"  endian ="big"  signed ="false" />  	<Flags  name ="Flag2"  size ="8" >      	<Flag  name ="frmtype"  position ="0"  size ="4" />          <Flag  name ="codecid"  position ="4"  size ="4" />      </Flags >  	<Block >      	<Relation  type ="when"  when ="int(self.find('Flag2.codecid').getInternalValue()) == 7" />  		<Blob  name ="pkttype"  length ="1" />  		<Blob  name ="compotime"  length ="3" />          <Blob  name ="data"  lengthType ="calc"  length ="int(self.find('datasize2').getInternalValue())-5" />      </Block >  	<Block >      	<Relation  type ="when"  when ="int(self.find('Flag2.codecid').getInternalValue()) != 7" />  		<Blob  name ="data"  lengthType ="calc"  length ="int(self.find('datasize2').getInternalValue())-1" />  	</Block >  	<Number  name ="lastsize"  size ="32"  endian ="big"  signed ="false" />  </Block > 
0x04: swf加载样本 利用as语言编写的代码,编译后得到swf文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package {     import  flash.display.Sprite;     import  flash.net.*;     import  flash.media.*;     import  flash.utils.*;     import  flash.display.*     import  flash.events.*;     import  flash.system.fscommand;     import  flash.display3D.textures.VideoTexture;     public  class  Main  extends  Sprite       {        public  function  Main () :void          {            var  video:Video;             var  netCon:NetConnection;             var  stream:NetStream;             function  loadVideo (url:String) :Video              {                video = new  Video();                 netCon = new  NetConnection();                 netCon.connect(null );                 stream = new  NetStream(netCon);                 stream.play(url);                 var  client:Object = new  Object();                 client.onMetaData = onMetaEvent;                 stream.client = client;                 stream.addEventListener(NetStatusEvent.NET_STATUS, netStatus);                 video.attachNetStream(stream);                 return  video;             }             function  onMetaEvent (e:Object) :void              {            }             function  netStatus (e:NetStatusEvent) :void              {                video.width  = stage.stageWidth;                 video.height = stage.stageHeight;             }             stage.addChild(loadVideo("fuzz.flv" ));         }     } } 
0x05: 自动化fuzz脚本 核心部分的代码如下。
1 2 3 4 5 6 7 def  run (fileID ):    copyFile(fileID)     subprocess.Popen(runCmd)          checkCrash()          clean() 
首先会拷贝一个样本文件到工作目录
1 2 def  copyFile (fileID ):    shutil.copyfile(fileDict.get(fileID),workDir+"fuzz.flv" ) 
然后开始一轮的fuzz
1 2 3 4 fuzzFilename = "fuzz.swf"  programName = "flashplayer_22_sa_debug.exe"  runCmd = programName +" " + fuzzFilename subprocess.Popen(runCmd) 
然后是异常检测(贼搓的方法…TAT)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def  checkCrash ():    winDbg = "windbg.exe"           try :         processList = psutil.process_iter()     except  Exception as  e:         print  e     for  p in  processList:         if (p.name == winDbg):             print  "[#]Crash Found! Writing to log now ..."              log(fileID)             sleep(1 )             p.kill()         else :             pass   
最后就是收尾的工作了
1 2 3 4 5 def  clean ():    subprocess.Popen(killProgram)     sleep(1 )     if (os.path.exists(workDir+"fuzz.flv" )):         os.remove(workDir+"fuzz.flv" ) 
0x06: 结束语 我这个东西只能叫toy吧,效率低下,简单粗暴。但是过程中是学习到不少东西,之后的打算是多看一些论文,多学习一些漏洞挖掘的方法,之前尝试了结合winafl来搞,不过问题很多,有待解决…慢慢来吧。fuzz with peach 
0x07: 参考 flv文件格式详解 peach 文档 Fuzzing with Peach – Part 1 « Flinkd!