Package Peach :: Package Generators :: Module untidy
[hide private]

Source Code for Module Peach.Generators.untidy

  1  ''' 
  2  Wrapper to use untidy in Peach. 
  3   
  4  Portions of this code (the untidy stuff) are GPL 
  5   
  6  @author: Jon McClintock 
  7  ''' 
  8   
  9  import sys 
 10  from Peach.generator import Generator 
 11   
12 -class XmlFuzzer(Generator):
13 ''' 14 This generator creates variations on a given XML blob, using the 15 untidy package. See: 16 17 http://untidy.sourceforge.net/ 18 ''' 19 20 _xmlString = None 21 _repetitions = [3, 30, 60] 22 _fuzzer = None 23 _iterator = None 24 _currentValue = None 25
26 - def __init__(self, xml, repetitions = None):
27 Generator.__init__(self) 28 self._xmlString = xml 29 if repetitions != None: 30 self._repetitions = repetitions 31 32 self._fuzzer = xmlFuzzer() 33 self._fuzzer.setRepetitions(self._repetitions) 34 35 self.reset()
36 # end __init__() 37
38 - def next(self):
39 try: 40 self._currentValue = self._iterator.next() 41 except StopIteration, e: 42 raise generator.GeneratorCompleted("XmlFuzzer")
43 # end next() 44
45 - def getRawValue(self):
46 return self._currentValue
47 # end getRawValue() 48
49 - def reset(self):
50 self._iterator = self._fuzzer.fuzz(self._xmlString) 51 self.next()
52 # end reset() 53
54 - def unittest():
55 input = "<xml><field value=\"blah\">boo</field></xml>" 56 g = XmlFuzzer(input) 57 g.next()
58 # end unittest() 59 60 unittest = staticmethod(unittest)
61 62 ''' 63 fuzzingFunctions.py 64 65 Copyright 2006 Andres Riancho 66 67 This file is part of untidy, untidy.sourceforge.net . 68 69 untidy is free software; you can redistribute it and/or modify 70 it under the terms of the GNU General Public License as published by 71 the Free Software Foundation version 2 of the License. 72 73 w3af is distributed in the hope that it will be useful, 74 but WITHOUT ANY WARRANTY; without even the implied warranty of 75 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 76 GNU General Public License for more details. 77 78 You should have received a copy of the GNU General Public License 79 along with w3af; if not, write to the Free Software 80 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 81 82 ''' 83 import re 84
85 -class fuzzingFunctions:
86 ''' 87 This class has a collection of fuzzing funcions for xml tags, text and attrs. 88 89 @author: Andres Riancho ( andres.riancho@gmail.com ) 90 '''
91 - def __init__(self):
92 self._ffTestList = [ self.ff0 ]
93
94 - def _getTestFuzzFunctions( self ):
95 ''' 96 @return: A list of fuzzing functions for testing. 97 ''' 98 return self._ffTestList
99
100 - def _getFuzzFunctions( self ):
101 ''' 102 @return: A list of fuzzing functions. 103 ''' 104 res = [] 105 i = 0 106 try: 107 while True: 108 # pure python love :P 109 res.append( getattr( self, 'ff'+str(i) ) ) 110 i += 1 111 except: 112 # I dont care 113 pass 114 115 return res
116 117 ############################################### 118 # # 119 # This are the fuzzing functions, the Core. # 120 # # 121 ############################################### 122
123 - def ff0( self, xmlItem, repetitions=[] ):
124 ''' 125 Return the item without changes 126 ''' 127 return [xmlItem,]
128 129 ###################################### 130 # # 131 # This set of ff's break the XML sintax # 132 # # 133 ###################################### 134
135 - def ff1( self, xmlItem, repetitions=[] ):
136 ''' 137 Matches the opening <, replace with '>'*repetitions 138 ''' 139 result = [] 140 p = re.compile('^<') 141 for rep in repetitions: 142 if p.match( xmlItem ): 143 fuzzedItem = p.sub('>'*rep , xmlItem ) 144 result.append( fuzzedItem ) 145 return result
146
147 - def ff2( self, xmlItem, repetitions=[] ):
148 ''' 149 If repetitions=2 and xmlItem='<foo>' 150 this ff returns '<foo><<>>' 151 ''' 152 result = [] 153 for rep in repetitions: 154 fuzzedItem = xmlItem 155 for i in range( rep ): 156 fuzzedItem += '<' 157 for i in range( rep ): 158 fuzzedItem += '>' 159 result.append( fuzzedItem ) 160 return result
161
162 - def ff3( self, xmlItem, repetitions=0 ):
163 result = [] 164 for rep in repetitions: 165 fuzzedItem = xmlItem 166 fuzzedItem += 'A'*rep 167 result.append( fuzzedItem ) 168 return result
169
170 - def ff4( self, xmlItem, repetitions=[] ):
171 result = [] 172 for rep in repetitions: 173 result.append(xmlItem*rep) 174 return result
175
176 - def ff5( self, xmlItem, repetitions=0 ):
177 return ['',]
178 179 ###################################### 180 # # 181 # This set of ff's fuzz the XML ( mostly ) without # 182 # breaking XML sintax # 183 # # 184 ###################################### 185
186 - def _sameType( self, charA, charB ):
187 if charA.isalpha() and charB.isalpha(): 188 return True 189 elif charA.isdigit() and charB.isdigit(): 190 return True 191 else: 192 return False
193
194 - def ff6( self, xmlItem, repetitions=[] ):
195 ''' 196 Lots of fuzzing going on here! :) 197 Some of this fuzzed XML's will be valid, some not. 198 ''' 199 result = [] 200 last = '' 201 pointer = 0 202 for char in xmlItem: 203 if not self._sameType( last, char ): 204 for rep in repetitions: 205 fuzzedItem = xmlItem[ : pointer ] 206 207 # This helps me identify the bugs on the remote side 208 if char.isalpha(): 209 fuzzedItem += 'A'* rep 210 elif char.isdigit(): 211 fuzzedItem += '1'* rep 212 else: 213 fuzzedItem += char* rep 214 215 fuzzedItem += xmlItem[ pointer : ] 216 result.append( fuzzedItem ) 217 pointer += 1 218 last = char 219 220 return result
221 222 223 # end XmlFuzzer class 224 225 226 ''' 227 xmlFuzzer.py 228 229 Copyright 2006 Andres Riancho 230 231 This file is part of untidy, untidy.sourceforge.net . 232 233 untidy is free software; you can redistribute it and/or modify 234 it under the terms of the GNU General Public License as published by 235 the Free Software Foundation version 2 of the License. 236 237 w3af is distributed in the hope that it will be useful, 238 but WITHOUT ANY WARRANTY; without even the implied warranty of 239 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 240 GNU General Public License for more details. 241 242 You should have received a copy of the GNU General Public License 243 along with w3af; if not, write to the Free Software 244 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 245 246 ''' 247 248 DEBUG = False 249 250 #import fuzzingFunctions 251 import re 252
253 -class xmlFuzzer:
254 ''' 255 This class fuzzes an xml string. 256 257 @author: Andres Riancho ( andres.riancho@gmail.com ) 258 '''
259 - def __init__(self):
260 self._stopfuzz = False 261 self._output = '' 262 self._current = 0 263 self._startFrom = [] 264 265 #self._repetitions = [ 2, 3, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 266 #127, 128, 129, 254, 255, 256, 511, 512, 513, 1023, 1024, 1025, 2047, 267 #2048, 2049, 4095, 4096, 4097, 10000, 10000 ] 268 self._repetitions = [ 30, 34 ] 269 270 self._ff = fuzzingFunctions()
271
272 - def setRepetitions( self , rep ):
273 self._repetitions = rep
274
275 - def _toList( self, xmlString ):
276 ''' 277 This method separates an xml in a "line by line" form. 278 279 Example: 280 xmlString: "<xml a="b">f00</xml>" 281 result: [ '<xml a="b">' , 'f00', '</xml>'] 282 283 REX/Python 284 285 Based on Robert D. Cameron's REX/Perl 1.0.=20 286 287 Original copyright notice follows: 288 289 REX/Perl 1.0 290 291 Robert D. Cameron "REX: XML Shallow Parsing with Regular Expressions", 292 Technical Report TR 1998-17, School of Computing Science, Simon Fraser=20 293 University, November, 1998. 294 Copyright (c) 1998, Robert D. Cameron.=20 295 The following code may be freely used and distributed provided that 296 this copyright and citation notice remains intact and that modifications 297 or additions are clearly identified. 298 299 @parameter xmlString: A string representation of the xml 300 @return: A list of strings. 301 ''' 302 TextSE = "[^<]+" 303 UntilHyphen = "[^-]*-" 304 Until2Hyphens = UntilHyphen + "(?:[^-]" + UntilHyphen + ")*-" 305 CommentCE = Until2Hyphens + ">?" 306 UntilRSBs = "[^\\]]*](?:[^\\]]+])*]+" 307 CDATA_CE = UntilRSBs + "(?:[^\\]>]" + UntilRSBs + ")*>" 308 S = "[ \\n\\t\\r]+" 309 NameStrt = "[A-Za-z_:]|[^\\x00-\\x7F]" 310 NameChar = "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]" 311 Name = "(?:" + NameStrt + ")(?:" + NameChar + ")*" 312 QuoteSE = "\"[^\"]*\"|'[^']*'" 313 DT_IdentSE = S + Name + "(?:" + S + "(?:" + Name + "|" + QuoteSE +"))*" 314 MarkupDeclCE = "(?:[^\\]\"'><]+|" + QuoteSE + ")*>" 315 S1 = "[\\n\\r\\t ]" 316 UntilQMs = "[^?]*\\?+" 317 PI_Tail = "\\?>|" + S1 + UntilQMs + "(?:[^>?]" + UntilQMs + ")*>" 318 DT_ItemSE = "<(?:!(?:--" + Until2Hyphens + ">|[^-]" + MarkupDeclCE + ")|\\?" + Name + "(?:" + PI_Tail + "))|%" + Name + ";|" + S 319 DocTypeCE = DT_IdentSE + "(?:" + S + ")?(?:\\[(?:" + DT_ItemSE + ")*](?:" + S + ")?)?>?" 320 DeclCE = "--(?:" + CommentCE + ")?|\\[CDATA\\[(?:" + CDATA_CE + ")?|DOCTYPE(?:" + DocTypeCE + ")?" 321 PI_CE = Name + "(?:" + PI_Tail + ")?" 322 EndTagCE = Name + "(?:" + S + ")?>?" 323 AttValSE = "\"[^<\"]*\"|'[^<']*'" 324 ElemTagCE = Name + "(?:" + S + Name + "(?:" + S + ")?=(?:" + S + ")?(?:" + AttValSE + "))*(?:" + S + ")?/?>?" 325 MarkupSPE = "<(?:!(?:" + DeclCE + ")?|\\?(?:" + PI_CE + ")?|/(?:" + EndTagCE + ")?|(?:" + ElemTagCE + ")?)" 326 XML_SPE = TextSE + "|" + MarkupSPE 327 328 res = re.findall(XML_SPE, xmlString) 329 res = [ x for x in res if x !='\n' ] 330 331 return res
332
333 - def _getFuzzFunctions( self ):
334 ''' 335 @return: A list of fuzzing functions. 336 ''' 337 if DEBUG: 338 self._repetitions = [ 5, 28 ] 339 return self._ff._getTestFuzzFunctions() 340 else: 341 return self._ff._getFuzzFunctions()
342
343 - def _generateIterator( self, fuzzedItems ):
344 ''' 345 @return: This method generates and iterator object that returns a string 346 representation of a fuzzed xml on every call to next() 347 ''' 348 class iterator: 349 def __init__( self, fuzzedItems ): 350 self._fi = fuzzedItems 351 352 # Init the counter 353 self._counter = [] 354 for f00 in range( len(self._fi) ): 355 self._counter.append( 1 ) 356 357 # This fixes the first call to next() 358 self._counter[ len( self._fi ) -1 ] = 0 359 360 self._stopIteration = False
361 362 def next( self ): 363 if self._stopIteration: 364 raise StopIteration 365 else: 366 # First we increment the counter 367 self._incrementCounter() 368 369 # Now we fetch the data from the self._fi based on the counter 370 itemList = self._fetchData() 371 372 # Finally the items are joined into a string and returned 373 xmlStr = ''.join( itemList ) 374 return xmlStr 375 376 def _fetchData( self ): 377 itemList = [] 378 # Believe it or not, this for loop worked the first time I wrote it. 379 for pos in range( len( self._counter ) ): 380 itemList.append( self._fi[ pos ][ self._counter[pos] -1 ] ) 381 # I dont care if you dont believe me :P 382 383 return itemList 384 385 def _incrementCounter( self ): 386 # this is ugly ! 387 # It is basically an abacus implementation in python 388 self._counter[ len(self._counter) -1 ] += 1 389 390 rpositions = range( len(self._counter) ) 391 rpositions.reverse() 392 for position in rpositions: 393 if self._counter[ position ] > len( self._fi[ position ] ): 394 # I count from 1, still a human. 395 self._counter[ position ] = 1 396 self._counter[ position - 1 ] += 1 397 398 # If all counters are full, then set a flag that indicates that 399 # the iterator has no more items inside. 400 eq = True 401 for c in range( len( self._counter ) ): 402 if self._counter[ c ] != len( self._fi[ c ] ): 403 eq = False 404 405 if eq: 406 self._stopIteration = True 407 408 def __iter__( self ): 409 # Not sure if this is ok, it works... but... is it ok ? 410 return self 411 412 it = iterator( fuzzedItems ) 413 return it 414
415 - def fuzz( self, xmlString ):
416 ''' 417 This method does all the work 418 419 @parameter xmlString: A string representation of the xml to fuzz 420 @return: An iterator object that returns a fuzzed xml on every call to next() 421 ''' 422 xmlList = self._toList( xmlString ) 423 424 fuzzedXmlItems = [] 425 for xmlItem in xmlList: 426 fuzzedItems = [] 427 for f in self._getFuzzFunctions(): 428 # The repetitions indicate how many times the ff will repeat the pattern 429 # it is configured to repeat. 430 fuzzedItem = apply( f, (xmlItem, self._repetitions ) ) 431 if fuzzedItem != None: 432 fuzzedItems.extend( fuzzedItem ) 433 434 fuzzedXmlItems.append ( fuzzedItems ) 435 436 iter = self._generateIterator( fuzzedXmlItems ) 437 return iter
438