Package Peach :: Package Engine :: Module peachshark
[hide private]

Source Code for Module Peach.Engine.peachshark

   1   
   2  ''' 
   3  Convert WireShark PDML files into Peach XML files. 
   4   
   5  Currently does a fairly good job of converting PDML files to Peach XML files 
   6  including the ability to find sizeof relations by looking for fields that look 
   7  like a length and matching them up to other fields in the focument. 
   8   
   9  Todo: 
  10   
  11    - Support parsing out multiple packets 
  12    - Support parsing out multiple proto's in a packet 
  13    - Look at proto's earlier then indicated one to pull out 
  14      transport and transport info (host, ip, etc) 
  15    - Generate the Tests/Test/Run sections 
  16    - Create multiple Data elements from multiple packets 
  17   
  18  @author: Michael Eddington 
  19  @version: $Id: Peach.Engine.peachshark-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $ 
  20  ''' 
  21   
  22  # 
  23  # Copyright (c) 2007 Michael Eddington 
  24  # 
  25  # Permission is hereby granted, free of charge, to any person obtaining a copy  
  26  # of this software and associated documentation files (the "Software"), to deal 
  27  # in the Software without restriction, including without limitation the rights  
  28  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
  29  # copies of the Software, and to permit persons to whom the Software is  
  30  # furnished to do so, subject to the following conditions: 
  31  # 
  32  # The above copyright notice and this permission notice shall be included in     
  33  # all copies or substantial portions of the Software. 
  34  # 
  35  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
  36  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
  37  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
  38  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
  39  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  40  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  41  # SOFTWARE. 
  42  # 
  43   
  44  # Authors: 
  45  #   Michael Eddington (mike@phed.org) 
  46   
  47  # $Id: Peach.Engine.peachshark-pysrc.html 1138 2008-08-16 19:39:03Z meddingt $ 
  48   
  49  import sys, struct, re 
  50  from Ft.Xml import Parse 
  51   
52 -def debug(str):
53 sys.stderr.write("debug: %s\n" % str)
54 55 #pdml/packet/proto 56 # method 57 58 # 1. Check for children, if we have them make block and recurse 59 # 2. Look for value show attribute and see if it contains a sub portion of the 60 # data (treat this different) 61 # 3. Look for items labled "len" or "length" and try and match them up 62 # 4. Optionally look at RFC's and try and match things up 63
64 -class PeachShark:
65
66 - def __init__(self):
67 self._currentPos = 0 68 self._regexIp = re.compile("^\d+\.\d+\.\d+\.\d+$") 69 self._regexFlagBit1 = re.compile("^(\.*)(\d+)(\.*)") 70 self._relations = {} 71 self._findStack = [] 72 self._templates = []
73
74 - def inStr(self, str, values):
75 str = str.lower() 76 for value in values: 77 if str.find(value) > -1: 78 #debug("found str") 79 return True 80 81 #debug("No: %s" % str) 82 return False
83 84
85 - def findSizeRelation(self, sizeNode, node):
86 # We know two things: 87 # 88 # 1. Sizes always come first 89 # 2. It will be the size of something :P 90 # 91 92 # Prevent infinit looping 93 if node in self._findStack: 94 return None 95 self._findStack.append(node) 96 97 size = self.findSizeGetSize(sizeNode) 98 99 # Search from us forward 100 sibling = sizeNode.nextSibling 101 while sibling != None: 102 checkSize = int(sibling.getAttributeNS(None, 'size')) 103 104 if checkSize == size: 105 return sibling 106 107 sibling = sibling.nextSibling 108 109 # That didn't work look from parent 110 for child in node.childNodes: 111 if child != sizeNode: 112 checkSize = int(child.getAttributeNS(None, 'size')) 113 if checkSize == size: 114 return child 115 116 ret = self.findSizeRelation(sizeNode, child) 117 if ret != None: 118 return ret 119 120 # Search from parent forward 121 sibling = node.nextSibling 122 while sibling != None: 123 checkSize = int(sibling.getAttributeNS(None, 'size')) 124 125 if checkSize == size: 126 return sibling 127 128 ret = self.findSizeRelation(sizeNode, sibling) 129 if ret != None: 130 return ret 131 132 sibling = sibling.nextSibling 133 134 # !!!TODO!!! Sometimes length can indicate the rest of our siblings 135 # but they may not be in a block of there own. 136 # -> Detect 137 # -> Force into a bock 138 # 139 #sibling = node.previousSibling 140 #while sibling != None: 141 # sizeUptoMe += int(sibling.getAttributeNS(None, 'size')) 142 # sibling = sibling.previousSibling 143 # 144 ## This is good, but not what we want! 145 #if (parentSize - sizeUptoMe) == size: 146 # return True 147 #else: 148 # debug("Nope: ParentSize: %d - SizeUptoMe: %d -- Size: %d" % (parentSize, sizeUptoMe, size)) 149 150 return None
151
152 - def findSizes(self, nodes):
153 ''' 154 Find nodes that could be sizes or lengths. 155 ''' 156 157 if nodes == None: 158 return [] 159 160 findValues = ["length", "size"] 161 sizeNodes = [] 162 163 for node in nodes: 164 if node == None: 165 continue 166 167 name = node.getAttributeNS(None, 'name') 168 show = node.getAttributeNS(None, 'show') 169 showName = node.getAttributeNS(None, 'showname') 170 171 if self.inStr(show, findValues) or self.inStr(showName, findValues) or self.inStr(name, findValues): 172 #debug("findSizes(): Found size: %s:%s" % (node.nodeName, name)) 173 sizeNodes.append(node) 174 175 for n in self.findSizes(node.childNodes): 176 sizeNodes.append(n) 177 178 return sizeNodes
179
180 - def findSizeGetSize(self, node):
181 ''' 182 Take a size/length node and figure out it's value. 183 ''' 184 185 ret = None 186 if node.hasAttributeNS(None, 'show') and len(node.getAttributeNS(None, 'show')) > 0: 187 try: 188 return int(node.getAttributeNS(None, 'show')) 189 except: 190 pass 191 192 if node.hasAttributeNS(None, 'value') and len(node.getAttributeNS(None, 'value')) > 0: 193 try: 194 return int(node.getAttributeNS(None, 'value'), 16) 195 except: 196 pass 197 198 try: 199 return int(re.compile(r"(\d+)").search(node.getAttributeNS(None, 'show')).group(1)) 200 201 except: 202 pass 203 204 debug(str("Failed on %s:%s" % (node.getAttributeNS(None, 'name'), node.nodeName))) 205 debug(str("Show: " + node.getAttributeNS(None, 'show'))) 206 debug(str("Value: "+ node.getAttributeNS(None, 'value'))) 207 raise Exception("OMG!!")
208 209
210 - def findSizeRelationCheckSelf(self, node):
211 ''' 212 Check if parent - me + prior siblings == size 213 ''' 214 215 parentSize = int(node.parentNode.getAttributeNS(None, 'size')) 216 sizeUptoMe = int(node.getAttributeNS(None, 'size')) 217 size = self.findSizeGetSize(node) 218 #debug("%d:%d" % (parentSize,size)) 219 220 # If our parent is the size we are indicating 221 # then return True! 222 if parentSize == size: 223 return True 224 225 return False
226
227 - def findSizeRelations(self, nodes):
228 ''' 229 Find and resolve size relations. 230 ''' 231 232 debug("Finding relations: " + nodes[0].nodeName) 233 if nodes[0].nodeName == 'proto': 234 parentNode = nodes[0] 235 else: 236 parentNode = nodes[0].parentNode 237 238 for node in self.findSizes(nodes): 239 #debug("findSizeRelations()... %s:%s" % (node.nodeName, node.getAttributeNS(None, 'name'))) 240 241 if self.findSizeRelationCheckSelf(node): 242 debug("findSizeRelations: Found relation to parent: %s and %s" % (node.getAttributeNS(None, 'name'), node.parentNode.getAttributeNS(None, 'name'))) 243 self._relations[node] = node.parentNode 244 245 else: 246 ret = self.findSizeRelation(node, parentNode) 247 if ret != None: 248 debug("findSizeRelations: Found relation: %s and %s" % (node.getAttributeNS(None, 'name'), ret.getAttributeNS(None, 'name'))) 249 self._relations[node] = ret
250 251
252 - def removeTextNodes(self, node):
253 254 for child in node.childNodes: 255 if child.nodeName == '#text': 256 node.removeChild(child) 257 else: 258 self.removeTextNodes(child)
259
260 - def htmlEncode(self, strInput, default=''):
261 262 if strInput == None or len(strInput) == 0: 263 strInput = default 264 265 if strInput == None or len(strInput) == 0: 266 return '' 267 268 # Allow: a-z A-Z 0-9 SPACE , . 269 # Allow (dec): 97-122 65-90 48-57 32 44 46 270 271 out = '' 272 for char in strInput: 273 c = ord(char) 274 if ((c >= 97 and c <= 122) or 275 (c >= 65 and c <= 90 ) or 276 (c >= 48 and c <= 57 ) or 277 c == 32 or c == 44 or c == 46): 278 out += char 279 else: 280 out += "&#%d;" % c 281 282 return out
283
284 - def getNodeName(self, node):
285 ''' 286 Check for name and show attributes. Figureout a possible name 287 for this node. 288 ''' 289 290 if node.hasAttributeNS(None, 'name'): 291 name = node.getAttributeNS(None, 'name') 292 293 if len(name.strip()) < 1: 294 return None 295 296 # Sounds good on paper, but causes problems 297 #try: 298 # name = name[name.rindex('.')+1:] 299 #except: 300 # pass 301 302 return name.replace(' ', '_').replace('.', '_') 303 304 return None
305
306 - def peachNode(self, node, tabCount, size, parent):
307 308 if node.nodeName == '#text': 309 return '', 0, 0 310 311 tabs = '\t' * tabCount 312 name = node.getAttributeNS(None, 'name') 313 show = node.getAttributeNS(None, 'show') 314 showName = node.getAttributeNS(None, 'showname') 315 size = int(node.getAttributeNS(None, 'size')) 316 pos = int(node.getAttributeNS(None, 'pos')) 317 ret = '' 318 nodeName = self.getNodeName(node) 319 if nodeName != None: 320 nodeName = 'name="%s"' % nodeName 321 else: 322 nodeName = '' 323 324 debug("peachNode: " + name) 325 326 # This should be prior sibling, not parent!! 327 if parent != None: 328 parentPos = int(parent.getAttributeNS(None, 'pos')) 329 parentSize = int(parent.getAttributeNS(None, 'size')) 330 else: 331 parentPos = -1 332 parentSize = -1 333 334 self._currentPos = pos 335 336 if size == 0: 337 #print "Size == 0: ", node.getAttributeNS(None, 'size') 338 return '', 0, 0 339 340 if tabCount == 1: 341 # Do this just once 342 self.findSizeRelations([node]) 343 344 if name.find('-'): 345 newName = '' 346 for n in name.split('-'): 347 newName += n[:1].upper() + n[1:] 348 name = newName 349 350 self._groupName = name[:1].upper() + name[1:] 351 self._genName = name[:1].upper() + name[1:] 352 self._templates.append(self._genName) 353 354 name = node.getAttributeNS(None, 'name') 355 356 if len(node.childNodes) > 0: 357 358 curPos = pos 359 sizeOfChildren = 0 360 361 if tabCount == 1: 362 if len(showName) > 1: ret += tabs + '<!-- %s -->\n' % showName 363 ret += tabs + '<Template name="%s">\n' % self._genName 364 else: 365 ret += tabs + '<Block %s>\n' % nodeName 366 367 for child in node.childNodes: 368 369 sibling = child.nextSibling 370 if sibling != None: 371 siblingPos = int(sibling.getAttributeNS(None, 'pos')) 372 siblingSize = int(sibling.getAttributeNS(None, 'size')) 373 childPos = int(child.getAttributeNS(None, 'pos')) 374 childSize = int(child.getAttributeNS(None, 'size')) 375 376 if siblingPos == childPos and siblingSize < childSize: 377 debug("Found that crazy stuff" + child.getAttributeNS(None, 'name')) 378 ret += tabs + "\t<!-- Skipping %s, same as following fields -->\n" % child.getAttributeNS(None, 'name') 379 continue 380 381 childShow = child.getAttributeNS(None, 'show') 382 383 #print "Child: %s" % childShow 384 385 childRet, childSize, childPos = self.peachNode(child, tabCount + 1, size, node) 386 387 childPos = int(childPos) 388 childSize = int(childSize) 389 390 #print "Child: %s, %d, %d" % (childShow, childPos, childSize) 391 392 if childSize == 0: 393 if len(childRet) > 0: 394 ret += childRet 395 continue 396 397 if int(childPos) == pos + int(sizeOfChildren): 398 ret += childRet 399 400 else: 401 valueHex = node.getAttributeNS(None, 'value') 402 value = self.hex2bin(valueHex) 403 404 # Locate "extra" bits not covered by children and 405 # add them in. Maybe we should fuzz this too? 406 if curPos < childPos: 407 if len(valueHex) >= (childPos-pos)*2: 408 ret += tabs + "\t<!-- Found some extra bits... -->\n" 409 ret += tabs + "\t<Blob %s valueType=\"hex\" value=\"%s\" />\n" % (nodeName, valueHex[(curPos-pos)*2:(childPos-pos)*2]) 410 else: 411 ret += tabs + "\t<!-- Found some extra bits, guessing they are z3r0 -->\n" 412 ret += tabs + "\t<Blob %s valueType=\"hex\" value=\"%s\" />\n\n" % (nodeName, ('00'*((childPos-pos) - (curPos-pos)))) 413 414 ret += childRet 415 416 sizeOfChildren += childSize 417 curPos = childPos + childSize 418 419 #if sizeOfChildren != size: 420 # raise Exception("Size not match %d != %d" % (size, sizeOfChildren)) 421 422 423 # Dunno if we need this anymore 424 if tabCount == 1: 425 name = self._genName[3:] 426 ret += tabs + '</Template>\n' 427 else: 428 ret += tabs + '</Block>\n' 429 430 else: 431 432 type = self.figureType(node) 433 valueHex = node.getAttributeNS(None, 'value') 434 show = node.getAttributeNS(None, 'show') 435 showName = node.getAttributeNS(None, 'showname') 436 if len(showName) < 1: 437 showName = show 438 value = self.hex2bin(valueHex) 439 440 if type != 'bit_flag': 441 if node.previousSibling != None: 442 previousSiblingPos = int(node.previousSibling.getAttributeNS(None, 'pos')) 443 previousSiblingSize = int(node.previousSibling.getAttributeNS(None, 'size')) 444 445 if pos == previousSiblingPos and size == previousSiblingSize: 446 debug("node same position and size of previousSibling") 447 return tabs + "<!-- *** Skipping %s, same position and size of previousSibling *** -->\n\n" % node.getAttributeNS(None, 'name'), 0, 0 448 #return '', 0, 0 449 450 #ret += " [%s] " % type 451 452 if len(showName) > 0: 453 ret += tabs + '<!-- %s -->\n' % showName 454 455 if type.find('str') > -1: 456 # TODO: We should take into account that this string 457 # may be fixed in size as well as different lengths. 458 459 if len(valueHex) == size*2: 460 str = 'valueType="hex" value="%s"' % valueHex 461 else: 462 str = 'value="%s"' % value 463 464 if type == 'str': 465 # regular string 466 ret += tabs + '<String %s %s' % (nodeName, str) 467 if self._relations.has_key(node): 468 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 469 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</String>\n' 470 else: 471 ret += ' />\n' 472 473 elif type == 'p_str': 474 # Padded string 475 ret += tabs + '<String %s %s length="%d"' % (nodeName, str, size) 476 if self._relations.has_key(node): 477 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 478 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</String>\n' 479 else: 480 ret += ' />\n' 481 482 elif type == 'w_str': 483 # wchar string 484 ret += tabs + '<String %s type="wchar" %s' % (nodeName, str) 485 if self._relations.has_key(node): 486 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 487 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</String>\n' 488 else: 489 ret += ' />\n' 490 491 elif type == 'p_w_str': 492 # padded wchar string 493 ret += tabs + '<String %s type="wchar" length="%d" %s' % (nodeName, size/2, str) 494 if self._relations.has_key(node): 495 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 496 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</String>\n' 497 else: 498 ret += ' />\n' 499 500 elif type == 'byte' or type == 'uint8': 501 ret += tabs + '<Number %s size="8" valueType="hex" value="%s" signed="false"' % (nodeName, valueHex) 502 if self._relations.has_key(node): 503 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 504 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 505 else: 506 ret += ' />\n' 507 508 elif type == 'int16': 509 ret += tabs + ('<Number %s size="16" valueType="hex" value="%s" signed="true"' % (nodeName, valueHex)) 510 if self._relations.has_key(node): 511 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 512 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 513 else: 514 ret += ' />\n' 515 516 elif type == 'uint16': 517 ret += tabs + ('<Number %s size="16" valueType="hex" value="%s" signed="false"' % (nodeName, valueHex)) 518 if self._relations.has_key(node): 519 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 520 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 521 else: 522 ret += ' />\n' 523 524 elif type == 'n_int16': 525 ret += tabs + ('<Number %s size="16" valueType="hex" value="%s" signed="true" endian="big"' % (nodeName, valueHex)) 526 if self._relations.has_key(node): 527 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 528 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 529 else: 530 ret += ' />\n' 531 532 elif type == 'n_uint16': 533 ret += tabs + ('<Number %s size="16" valueType="hex" value="%s" signed="false" endian="big"' % (nodeName, valueHex)) 534 if self._relations.has_key(node): 535 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 536 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 537 else: 538 ret += ' />\n' 539 540 541 elif type == 'int32': 542 ret += tabs + ('<Number %s size="32" valueType="hex" value="%s" signed="true"' % (nodeName, valueHex)) 543 if self._relations.has_key(node): 544 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 545 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 546 else: 547 ret += ' />\n' 548 elif type == 'uint32': 549 ret += tabs + ('<Number %s size="32" valueType="hex" value="%s" signed="false"' % (nodeName, valueHex)) 550 if self._relations.has_key(node): 551 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 552 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 553 else: 554 ret += ' />\n' 555 elif type == 'n_int32': 556 ret += tabs + ('<Number %s size="32" valueType="hex" value="%s" signed="true" endian="big"' % (nodeName, valueHex)) 557 if self._relations.has_key(node): 558 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 559 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 560 else: 561 ret += ' />\n' 562 elif type == 'n_uint32': 563 ret += tabs + ('<Number %s size="32" valueType="hex" value="%s" signed="false" endian="big"' % (nodeName, valueHex)) 564 if self._relations.has_key(node): 565 of = self._relations[node].getAttributeNS(None, 'name').replace('.', '_') 566 ret += '>\n' + tabs + '\t<Relation type="size" of="'+of+'" />\n'+tabs+'</Number>\n' 567 else: 568 ret += ' />\n' 569 570 elif type == 'blob': 571 ret += tabs + '<Blob %s valueType="hex" value="%s" />\n' % (nodeName, valueHex) 572 573 elif type == 'ip': 574 #ret += tabs + "WithDefault(%s.addNewGroup(), '%s', BadIpAddress()).setTransformer(Ipv4StringToOctet()),\n" % ( self._groupName, show ) 575 ret += tabs + "<!-- TODO: Handle IP Address Better! -->\n" 576 ret += tabs + '<String %s value="%s">\n' % (nodeName, show) 577 ret += tabs + '\t<Transformer class="encode.Ipv4StringToOctet" />\n' 578 ret += tabs + '</String>\n' 579 #raise Exception("TODO") 580 581 elif type == 'n_ip': 582 #ret += tabs + "WithDefault(%s.addNewGroup(), '%s', BadIpAddress()).setTransformer(Ipv4StringToNetworkOctet()),\n" % ( self._groupName, show ) 583 ret += tabs + "<!-- TODO: Handle IP Address Better! -->\n" 584 ret += tabs + '<String %s value="%s">\n' % (nodeName, show) 585 ret += tabs + '\t<Transformer class="encode.Ipv4StringToNetworkOctet" />\n' 586 ret += tabs + '</String>\n' 587 #raise Exception("TODO") 588 589 elif type == 'bit_flag': 590 # TODO: Handle flags! 591 592 if node.previousSibling == None: 593 # First flag, lets do it! 594 595 nodeNames = [] 596 offsets = [] 597 bits = [] 598 shownames = [] 599 length = 0 600 601 offset, bit = self.getFlagBits(node) 602 length += bit 603 604 offsets.append(offset) 605 bits.append(bit) 606 shownames.append(showName) 607 608 nodeName = self.getNodeName(node) 609 if nodeName != None: 610 nodeNames.append('name="%s"' % nodeName) 611 else: 612 nodeNames.append('') 613 614 sibling = node.nextSibling 615 while sibling != None: 616 offset, bit = self.getFlagBits(sibling) 617 618 length += bit 619 620 offsets.append(offset) 621 bits.append(bit) 622 shownames.append(sibling.getAttributeNS(None, 'showname')) 623 624 nodeName = self.getNodeName(sibling) 625 if nodeName != None: 626 nodeNames.append('name="%s"' % nodeName) 627 else: 628 nodeNames.append('') 629 630 sibling = sibling.nextSibling 631 632 # Now output Flags generator 633 634 # make sure length is multiple of 2 635 while length % 2 != 0: 636 length += 1 637 638 parentName = self.getNodeName(node.parentNode) 639 if parentName != None: 640 ret += tabs + '<Flags name="%s" size="%d">\n' % (parentName, length) 641 else: 642 ret += tabs + '<Flags size="%d">\n' % length 643 644 for i in range(len(offsets)): 645 ret += tabs + '\t<Flag %s position="%d" size="%d" />\n' % (nodeNames[i], offsets[i], bits[i]) 646 647 ret += tabs + "</Flags>\n" 648 649 else: 650 raise Exception("Unknown type: %s" % type) 651 652 return ret + '\n', size, pos
653
654 - def hex2bin(self, h):
655 ''' 656 Convert hex string to binary string 657 ''' 658 ret = '' 659 for cnt in range(0, len(h), 2): 660 ret += chr(int(h[cnt:cnt+2],16)) 661 662 return ret
663
664 - def isWideString(self, str):
665 ''' 666 Is this a wchar string? 667 ''' 668 669 # Wide chars should always have even string 670 # length 671 if len(str) < 4 or len(str) % 2 != 0: 672 return False 673 674 for i in range(0, len(str), 2): 675 c = str[i] 676 c2 = str[i+1] 677 678 # Assume we don't actually have characters that 679 # require two bytes to display. So second byte 680 # should always be NULL 681 if c2 != '\0': 682 return False 683 684 o = ord(c) 685 if o < 32 or o > 126: 686 if c == '\n' or c == '\r' or c == '\t': 687 continue 688 689 return False 690 691 return True
692
693 - def isPaddedWideString(self, str):
694 ''' 695 Is this a wchar string with nulls at the end? 696 ''' 697 698 # Wide chars should always have even string 699 # length 700 if len(str) < 4 or len(str) % 2 != 0: 701 return False 702 703 if str[-1] != '\0' or str[-2] != '\0': 704 return False 705 706 for i in range(0, len(str), 2): 707 c = str[i] 708 c2 = str[i+1] 709 710 # Assume we don't actually have characters that 711 # require two bytes to display. So second byte 712 # should always be NULL 713 if c2 != '\0': 714 return False 715 716 o = ord(c) 717 if o < 32 or o > 126: 718 if c == '\n' or c == '\r' or c == '\t' or c == '\0': 719 continue 720 721 return False 722 723 return True
724
725 - def isString(self, str):
726 ''' 727 Is this a char string? 728 ''' 729 730 if len(str) < 3: 731 return False 732 733 for c in str: 734 o = ord(c) 735 if o < 32 or o > 126: 736 if c == '\n' or c == '\r' or c == '\t': 737 continue 738 739 return False 740 741 #debug("isString('%s'): True" % str) 742 743 return True
744
745 - def isPaddedString(self, str):
746 ''' 747 Is this a char string with nulls at the end? 748 ''' 749 750 if len(str) < 3: 751 #debug("to small") 752 return False 753 754 if str[-1] != '\0': 755 #debug("no null term") 756 return False 757 758 for c in str: 759 o = ord(c) 760 if o < 32 or o > 126: 761 if c == '\n' or c == '\r' or c == '\t' or c == '\0': 762 continue 763 764 debug("odd char [%d]" % o) 765 return False 766 767 return True
768
769 - def getFlagBits(self, node):
770 ''' 771 Checks out the showname field to see if we can determin 772 the number of bits this flag is and it's offset in the packet. 773 ''' 774 # .... ...1 .... .... = Recursion desired: Do query recursively 775 776 show = node.getAttributeNS(None, 'showname') 777 778 #debug("flag str (initial): [%s]" % show) 779 780 # remove spaces 781 show = show.replace(' ', '') 782 783 # Get dots and numbers 784 try: 785 result = self._regexFlagBit1.match(show) 786 firstDots = result.group(1) 787 number = result.group(2) 788 lastDots = result.group(3) 789 790 offset = len(firstDots) 791 bits = len(number) 792 793 #debug("flag str: [%s]" % show) 794 #debug("offset: %d - bits: %s - remander: %d" % (offset, bits, len(lastDots))) 795 796 if (len(firstDots) + len(number) + len(lastDots)) % 2 != 0: 797 debug("getFlagBits(): Something fishy about this!!! %d" % (len(firstDots) + len(number) + len(lastDots))) 798 799 return offset, bits 800 except: 801 return 0, 1
802
803 - def figureType(self, node):
804 805 # Try and figure out our type, number, string, etc. 806 807 show = node.getAttributeNS(None, 'show') 808 showName = node.getAttributeNS(None, 'showname') 809 value = self.hex2bin(node.getAttributeNS(None, 'value')) 810 valueHex = node.getAttributeNS(None, 'value') 811 size = int(node.getAttributeNS(None, 'size')) 812 pos = int(node.getAttributeNS(None, 'pos')) 813 parentPos = int(node.parentNode.getAttributeNS(None, 'pos')) 814 parentSize = int(node.parentNode.getAttributeNS(None, 'size')) 815 816 #print "Show: [%s], valueHex: [%s], size: %d" % (show, valueHex, size) 817 818 # If just compar pos == parentPos we will get the first 819 # child. Should also check next child and size 820 if pos == parentPos and parentSize == size: 821 # A flag will have the same position as it's parent 822 # parent will have size of 1 823 #print "bit_flag: pos: %d parentPos: %d" % (pos, parentPos) 824 #debug("show: %s - showName: %s" % (show, showName)) 825 return 'bit_flag' 826 #else: 827 # print "pos: %d parentPos: %d" % (pos, parentPos) 828 829 if len(value) > 2 and value.isalnum() and not show.isdigit(): 830 return 'str' 831 832 elif self._regexIp.match(show) != None and size == 4: 833 # ip address 834 ip1, ip2, ip3, ip4 = show.split('.') 835 836 #debug("ip: %s - %s - %s - %s" % (show, ip1, valueHex[len(valueHex)-2:], valueHex)) 837 if int(ip1) == int(valueHex[6:], 16) and int(ip2) == int(valueHex[4:6], 16) and int(ip3) == int(valueHex[2:4], 16) and int(ip4) == int(valueHex[:2], 16): 838 return 'n_ip' 839 840 if int(ip1) == int(valueHex[:2], 16): 841 return 'ip' 842 843 elif show[:2] == "0x": 844 845 # Figure if we are little or big endian 846 847 showHex = show[2:] 848 849 if showHex == valueHex or int(showHex, 16) == int(valueHex, 16): 850 # little 851 if size == 1: 852 return 'uint8' 853 854 if size == 2: 855 return 'uint16' 856 857 elif size == 4: 858 return 'uint32' 859 860 elif size == 8: 861 return 'uint64' 862 863 #debug("bigBalue: [%s][%s]" % (valueHex, show)) 864 bigValue = struct.unpack("!H", value)[0] 865 if int(bigValue) == int(showHex, 16): 866 if size == 1: 867 return 'n_uint8' 868 869 if size == 2: 870 return 'n_uint16' 871 872 elif size == 4: 873 return 'n_uint32' 874 875 elif size == 8: 876 return 'n_uint64' 877 878 879 elif not show.isdigit() and self.isWideString(value): 880 return 'w_str' 881 882 elif not show.isdigit() and self.isPaddedWideString(value): 883 return 'p_w_str' 884 885 elif not show.isdigit() and self.isString(value): 886 return 'str' 887 888 elif not show.isdigit() and self.isPaddedString(value): 889 return 'p_str' 890 891 elif show.isdigit() or (len(showName) == 0 and size <= 4): 892 893 cnt = len(valueHex) 894 895 if size == 1: 896 # Byte I bet 897 return 'byte' 898 899 elif size == 2: 900 # Maybe 16 bit int? 901 902 try: 903 show = int(show) 904 except: 905 show = 0 906 907 try: 908 val = struct.unpack('H', value)[0] 909 if int(val) == show: 910 return 'uint16' 911 912 val = struct.unpack('h', value)[0] 913 if val == show: 914 return 'int16' 915 916 val = struct.unpack('!H', value)[0] 917 if val == show: 918 return 'n_int16' 919 920 val = struct.unpack('!h', value)[0] 921 if val == show: 922 return 'n_uint16' 923 924 except struct.error: 925 pass 926 927 return 'n_uint16' 928 929 elif size == 4: 930 # Maybe 32 bit int? 931 if struct.unpack('I', value)[0] == show: 932 return 'uint32' 933 934 elif struct.unpack('i', value)[0] == show: 935 return 'int32' 936 937 elif struct.unpack('!I', value)[0] == show: 938 return 'n_int32' 939 940 return 'n_uint32' 941 942 return 'blob'
943
944 - def figureOutPublisher(self, doc):
945 ''' 946 Look for udp or tcp protocol and pull out 947 address and port. 948 ''' 949 950 defaultPublisher = "\t<Publisher class=\"Publisher\" />" 951 952 nodes = doc.xpath('descendant::proto[@name="ip"]') 953 if len(nodes) == 0: 954 return defaultPublisher 955 956 nodeIp = nodes[0] 957 958 nodes = doc.xpath('descendant::proto[@name="tcp"]') 959 if len(nodes) == 0: 960 nodes = doc.xpath('descendant::proto[@name="udp"]') 961 962 if len(nodes) == 0: 963 return defaultPublisher 964 965 nodeProt = nodes[0] 966 967 m = re.search("Dst: ([^\s(]*)", str(nodeIp.getAttributeNS(None, 'showname'))) 968 ip = m.group(1) 969 970 ret = '' 971 for child in nodeProt.childNodes: 972 if child.getAttributeNS(None, 'name') == 'udp.dstport': 973 974 ret =""" 975 <Publisher class="udp.Udp"> 976 <Param name="Host" value="%s" /> 977 <Param name="Port" value="%s" /> 978 </Publisher> 979 """ % (ip, str(child.getAttributeNS(None, 'show'))) 980 981 if child.getAttributeNS(None, 'name') == 'tcp.dstport': 982 983 ret =""" 984 <Publisher class="tcp.Tcp"> 985 <Param name="Host" value="%s" /> 986 <Param name="Port" value="%s" /> 987 </Publisher> 988 """ % (ip, str(child.getAttributeNS(None, 'show'))) 989 990 return ret
991 992 993 994 # ######################################################################## 995
996 -def DoTheShark(argv):
997 998 if len(argv) == 2: 999 # print out the protocols 1000 print "Select one of the following protocols:\n" 1001 1002 doc = Parse(argv[1]) 1003 nodes = doc.xpath('descendant::proto') 1004 1005 for n in nodes: 1006 print "\t", n.getAttributeNS(None, 'name') 1007 1008 return "" 1009 1010 name = argv[1] 1011 doc = Parse(argv[1]) 1012 1013 node = doc.xpath('descendant::proto[@name="%s"]' % argv[2])[0] 1014 1015 shark = PeachShark() 1016 shark.removeTextNodes(node.parentNode) 1017 1018 ret = '<?xml version="1.0" encoding="utf-8"?>\n<Peach xmlns="http://phed.org/2008/Peach" version="0.1" author="PeachShark" description="%s">\n' % argv[2] 1019 ret += """ 1020 <!-- ==// Auto Generated by PeachShark //== --> 1021 1022 <!-- 1023 1024 Please do the following before using this fuzzer: 1025 1026 1. Take a look through the generated output, see if it makes sense 1027 2. Verify the Publisher settings at the bottom, they are only a guess 1028 3. **UPDATE TARGET IP** 1029 4. Perform a WireShark capture of a couple packets to make sure 1030 they parse out okay. 1031 1032 --> 1033 1034 <Include ns="default" src="file:defaults.xml" /> 1035 <Include ns="pt" src="file:PeachTypes.xml" /> 1036 1037 """ 1038 1039 sibling = node 1040 while sibling != None: 1041 1042 #shark.removeTextNodes(sibling.parentNode) 1043 debug("Handing node: " + sibling.getAttributeNS(None, 'name')) 1044 templateStr, s, p = shark.peachNode(sibling, 1, sibling.getAttributeNS(None, 'size'), None) 1045 ret += templateStr 1046 sibling = sibling.nextSibling 1047 1048 ret += '\t<Template name="SharkTemplate">\n' 1049 1050 for t in shark._templates: 1051 ret += '\t\t<Block ref="%s" />\n' % t 1052 1053 ret += """ 1054 </Template> 1055 1056 <Test name="SharkTest"> 1057 <Template ref="SharkTemplate" /> 1058 %s 1059 </Test> 1060 1061 <Run name="DefaultRun"> 1062 <Test ref="SharkTest" /> 1063 </Run> 1064 1065 </Peach>\n""" % shark.figureOutPublisher(doc) 1066 1067 return ret
1068 1069 if __name__ == "__main__": 1070 1071 sys.stderr.write("\n]] PeachShark 2\n\n") 1072 sys.stderr.write("Loading pdml: %s\n\n" % sys.argv[1]) 1073 1074 print DoTheShark(argv) 1075 1076 # end 1077