Package modules :: Package processing :: Module static
[hide private]
[frames] | no frames]

Source Code for Module modules.processing.static

  1  # Copyright (C) 2010-2013 Claudio Guarnieri. 
  2  # Copyright (C) 2014-2016 Cuckoo Foundation. 
  3  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  4  # See the file 'docs/LICENSE' for copying permission. 
  5   
  6  import datetime 
  7  import logging 
  8  import os 
  9  import re 
 10  import struct 
 11  import zipfile 
 12   
 13  try: 
 14      import bs4 
 15      HAVE_BS4 = True 
 16  except ImportError: 
 17      HAVE_BS4 = False 
 18   
 19  try: 
 20      import magic 
 21      HAVE_MAGIC = True 
 22  except ImportError: 
 23      HAVE_MAGIC = False 
 24   
 25  try: 
 26      import pefile 
 27      import peutils 
 28      HAVE_PEFILE = True 
 29  except ImportError: 
 30      HAVE_PEFILE = False 
 31   
 32  try: 
 33      import M2Crypto 
 34      HAVE_MCRYPTO = True 
 35  except ImportError: 
 36      HAVE_MCRYPTO = False 
 37   
 38  try: 
 39      import oletools.olevba 
 40      HAVE_OLETOOLS = True 
 41  except ImportError: 
 42      HAVE_OLETOOLS = False 
 43   
 44  try: 
 45      import peepdf.PDFCore 
 46      import peepdf.JSAnalysis 
 47      HAVE_PEEPDF = True 
 48  except ImportError: 
 49      HAVE_PEEPDF = False 
 50   
 51  try: 
 52      import PyV8 
 53      HAVE_PYV8 = True 
 54   
 55      PyV8  # Fake usage. 
 56  except: 
 57      HAVE_PYV8 = False 
 58   
 59  from lib.cuckoo.common.abstracts import Processing 
 60  from lib.cuckoo.common.constants import CUCKOO_ROOT 
 61  from lib.cuckoo.common.objects import File 
 62  from lib.cuckoo.common.utils import convert_to_printable 
 63  from lib.cuckoo.common.utils import to_unicode 
 64  from lib.cuckoo.misc import dispatch 
 65   
 66  log = logging.getLogger(__name__) 
 67   
 68  # Partially taken from 
 69  # http://malwarecookbook.googlecode.com/svn/trunk/3/8/pescanner.py 
 70   
71 -class PortableExecutable(object):
72 """PE analysis.""" 73
74 - def __init__(self, file_path):
75 """@param file_path: file path.""" 76 self.file_path = file_path 77 self.pe = None
78
79 - def _get_filetype(self, data):
80 """Gets filetype, uses libmagic if available. 81 @param data: data to be analyzed. 82 @return: file type or None. 83 """ 84 if not HAVE_MAGIC: 85 return None 86 87 try: 88 ms = magic.open(magic.MAGIC_NONE) 89 ms.load() 90 file_type = ms.buffer(data) 91 except: 92 try: 93 file_type = magic.from_buffer(data) 94 except Exception: 95 return None 96 finally: 97 try: 98 ms.close() 99 except: 100 pass 101 102 return file_type
103
104 - def _get_peid_signatures(self):
105 """Gets PEID signatures. 106 @return: matched signatures or None. 107 """ 108 try: 109 sig_path = os.path.join(CUCKOO_ROOT, "data", 110 "peutils", "UserDB.TXT") 111 signatures = peutils.SignatureDatabase(sig_path) 112 return signatures.match(self.pe, ep_only=True) 113 except: 114 return None
115
116 - def _get_imported_symbols(self):
117 """Gets imported symbols. 118 @return: imported symbols dict or None. 119 """ 120 imports = [] 121 122 for entry in getattr(self.pe, "DIRECTORY_ENTRY_IMPORT", []): 123 try: 124 symbols = [] 125 for imported_symbol in entry.imports: 126 symbols.append({ 127 "address": hex(imported_symbol.address), 128 "name": imported_symbol.name, 129 }) 130 131 imports.append({ 132 "dll": convert_to_printable(entry.dll), 133 "imports": symbols, 134 }) 135 except: 136 log.exception("Unable to parse imported symbols.") 137 138 return imports
139
140 - def _get_exported_symbols(self):
141 """Gets exported symbols. 142 @return: exported symbols dict or None. 143 """ 144 exports = [] 145 146 if hasattr(self.pe, "DIRECTORY_ENTRY_EXPORT"): 147 for exported_symbol in self.pe.DIRECTORY_ENTRY_EXPORT.symbols: 148 exports.append({ 149 "address": hex(self.pe.OPTIONAL_HEADER.ImageBase + 150 exported_symbol.address), 151 "name": exported_symbol.name, 152 "ordinal": exported_symbol.ordinal, 153 }) 154 155 return exports
156
157 - def _get_sections(self):
158 """Gets sections. 159 @return: sections dict or None. 160 """ 161 sections = [] 162 163 for entry in self.pe.sections: 164 try: 165 section = {} 166 section["name"] = convert_to_printable(entry.Name.strip("\x00")) 167 section["virtual_address"] = "0x{0:08x}".format(entry.VirtualAddress) 168 section["virtual_size"] = "0x{0:08x}".format(entry.Misc_VirtualSize) 169 section["size_of_data"] = "0x{0:08x}".format(entry.SizeOfRawData) 170 section["entropy"] = entry.get_entropy() 171 sections.append(section) 172 except: 173 continue 174 175 return sections
176
177 - def _get_resources(self):
178 """Get resources. 179 @return: resources dict or None. 180 """ 181 resources = [] 182 183 if hasattr(self.pe, "DIRECTORY_ENTRY_RESOURCE"): 184 for resource_type in self.pe.DIRECTORY_ENTRY_RESOURCE.entries: 185 try: 186 resource = {} 187 188 if resource_type.name is not None: 189 name = str(resource_type.name) 190 else: 191 name = str(pefile.RESOURCE_TYPE.get(resource_type.struct.Id)) 192 193 if hasattr(resource_type, "directory"): 194 for resource_id in resource_type.directory.entries: 195 if hasattr(resource_id, "directory"): 196 for resource_lang in resource_id.directory.entries: 197 data = self.pe.get_data(resource_lang.data.struct.OffsetToData, resource_lang.data.struct.Size) 198 filetype = self._get_filetype(data) 199 language = pefile.LANG.get(resource_lang.data.lang, None) 200 sublanguage = pefile.get_sublang_name_for_lang(resource_lang.data.lang, resource_lang.data.sublang) 201 202 resource["name"] = name 203 resource["offset"] = "0x{0:08x}".format(resource_lang.data.struct.OffsetToData) 204 resource["size"] = "0x{0:08x}".format(resource_lang.data.struct.Size) 205 resource["filetype"] = filetype 206 resource["language"] = language 207 resource["sublanguage"] = sublanguage 208 resources.append(resource) 209 except: 210 continue 211 212 return resources
213
214 - def _get_versioninfo(self):
215 """Get version info. 216 @return: info dict or None. 217 """ 218 infos = [] 219 if hasattr(self.pe, "VS_VERSIONINFO"): 220 if hasattr(self.pe, "FileInfo"): 221 for entry in self.pe.FileInfo: 222 try: 223 if hasattr(entry, "StringTable"): 224 for st_entry in entry.StringTable: 225 for str_entry in st_entry.entries.items(): 226 entry = {} 227 entry["name"] = convert_to_printable(str_entry[0]) 228 entry["value"] = convert_to_printable(str_entry[1]) 229 infos.append(entry) 230 elif hasattr(entry, "Var"): 231 for var_entry in entry.Var: 232 if hasattr(var_entry, "entry"): 233 entry = {} 234 entry["name"] = convert_to_printable(var_entry.entry.keys()[0]) 235 entry["value"] = convert_to_printable(var_entry.entry.values()[0]) 236 infos.append(entry) 237 except: 238 continue 239 240 return infos
241
242 - def _get_imphash(self):
243 """Gets imphash. 244 @return: imphash string or None. 245 """ 246 try: 247 return self.pe.get_imphash() 248 except AttributeError: 249 return None
250
251 - def _get_timestamp(self):
252 """Get compilation timestamp. 253 @return: timestamp or None. 254 """ 255 try: 256 pe_timestamp = self.pe.FILE_HEADER.TimeDateStamp 257 except AttributeError: 258 return None 259 260 dt = datetime.datetime.fromtimestamp(pe_timestamp) 261 return dt.strftime("%Y-%m-%d %H:%M:%S")
262
263 - def _get_pdb_path(self):
264 """Get the path to any available debugging symbols.""" 265 try: 266 for entry in getattr(self.pe, "DIRECTORY_ENTRY_DEBUG", []): 267 raw_offset = entry.struct.PointerToRawData 268 size_data = entry.struct.SizeOfData 269 debug_data = self.pe.__data__[raw_offset:raw_offset+size_data] 270 271 if debug_data.startswith("RSDS"): 272 return debug_data[24:].strip("\x00").decode("latin-1") 273 except: 274 log.exception("Exception parsing PDB path")
275
276 - def _get_signature(self):
277 """If this executable is signed, get its signature(s).""" 278 dir_index = pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"] 279 if len(self.pe.OPTIONAL_HEADER.DATA_DIRECTORY) < dir_index: 280 return [] 281 282 dir_entry = self.pe.OPTIONAL_HEADER.DATA_DIRECTORY[dir_index] 283 if not dir_entry or not dir_entry.VirtualAddress or not dir_entry.Size: 284 return [] 285 286 if not HAVE_MCRYPTO: 287 log.critical("You do not have the m2crypto library installed " 288 "preventing certificate extraction: " 289 "pip install m2crypto") 290 return [] 291 292 signatures = self.pe.write()[dir_entry.VirtualAddress+8:] 293 bio = M2Crypto.BIO.MemoryBuffer(signatures) 294 if not bio: 295 return [] 296 297 pkcs7_obj = M2Crypto.m2.pkcs7_read_bio_der(bio.bio_ptr()) 298 if not pkcs7_obj: 299 return [] 300 301 ret = [] 302 p7 = M2Crypto.SMIME.PKCS7(pkcs7_obj) 303 for cert in p7.get0_signers(M2Crypto.X509.X509_Stack()) or []: 304 subject = cert.get_subject() 305 ret.append({ 306 "serial_number": "%032x" % cert.get_serial_number(), 307 "common_name": subject.CN, 308 "country": subject.C, 309 "locality": subject.L, 310 "organization": subject.O, 311 "email": subject.Email, 312 "sha1": "%040x" % int(cert.get_fingerprint("sha1"), 16), 313 "md5": "%032x" % int(cert.get_fingerprint("md5"), 16), 314 }) 315 316 if subject.GN and subject.SN: 317 ret[-1]["full_name"] = "%s %s" % (subject.GN, subject.SN) 318 elif subject.GN: 319 ret[-1]["full_name"] = subject.GN 320 elif subject.SN: 321 ret[-1]["full_name"] = subject.SN 322 323 return ret
324
325 - def run(self):
326 """Run analysis. 327 @return: analysis results dict or None. 328 """ 329 if not os.path.exists(self.file_path): 330 return {} 331 332 try: 333 self.pe = pefile.PE(self.file_path) 334 except pefile.PEFormatError: 335 return {} 336 337 results = {} 338 results["peid_signatures"] = self._get_peid_signatures() 339 results["pe_imports"] = self._get_imported_symbols() 340 results["pe_exports"] = self._get_exported_symbols() 341 results["pe_sections"] = self._get_sections() 342 results["pe_resources"] = self._get_resources() 343 results["pe_versioninfo"] = self._get_versioninfo() 344 results["pe_imphash"] = self._get_imphash() 345 results["pe_timestamp"] = self._get_timestamp() 346 results["pdb_path"] = self._get_pdb_path() 347 results["signature"] = self._get_signature() 348 results["imported_dll_count"] = len([x for x in results["pe_imports"] if x.get("dll")]) 349 return results
350
351 -class WindowsScriptFile(object):
352 """Deobfuscates and interprets Windows Script Files.""" 353 encoding = [ 354 1, 2, 0, 1, 2, 0, 2, 0, 0, 2, 0, 2, 1, 0, 2, 0, 355 1, 0, 2, 0, 1, 1, 2, 0, 0, 2, 1, 0, 2, 0, 0, 2, 356 1, 1, 0, 2, 0, 2, 0, 1, 0, 1, 1, 2, 0, 1, 0, 2, 357 1, 0, 2, 0, 1, 1, 2, 0, 0, 1, 1, 2, 0, 1, 0, 2, 358 ] 359 360 lookup = [ 361 [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 362 0x08, 0x7b, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 363 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 364 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 365 0x32, 0x30, 0x21, 0x29, 0x5b, 0x38, 0x33, 0x3d, 366 0x58, 0x3a, 0x35, 0x65, 0x39, 0x5c, 0x56, 0x73, 367 0x66, 0x4e, 0x45, 0x6b, 0x62, 0x59, 0x78, 0x5e, 368 0x7d, 0x4a, 0x6d, 0x71, 0x00, 0x60, 0x00, 0x53, 369 0x00, 0x42, 0x27, 0x48, 0x72, 0x75, 0x31, 0x37, 370 0x4d, 0x52, 0x22, 0x54, 0x6a, 0x47, 0x64, 0x2d, 371 0x20, 0x7f, 0x2e, 0x4c, 0x5d, 0x7e, 0x6c, 0x6f, 372 0x79, 0x74, 0x43, 0x26, 0x76, 0x25, 0x24, 0x2b, 373 0x28, 0x23, 0x41, 0x34, 0x09, 0x2a, 0x44, 0x3f, 374 0x77, 0x3b, 0x55, 0x69, 0x61, 0x63, 0x50, 0x67, 375 0x51, 0x49, 0x4f, 0x46, 0x68, 0x7c, 0x36, 0x70, 376 0x6e, 0x7a, 0x2f, 0x5f, 0x4b, 0x5a, 0x2c, 0x57], 377 [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 378 0x08, 0x57, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 379 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 380 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 381 0x2e, 0x47, 0x7a, 0x56, 0x42, 0x6a, 0x2f, 0x26, 382 0x49, 0x41, 0x34, 0x32, 0x5b, 0x76, 0x72, 0x43, 383 0x38, 0x39, 0x70, 0x45, 0x68, 0x71, 0x4f, 0x09, 384 0x62, 0x44, 0x23, 0x75, 0x00, 0x7e, 0x00, 0x5e, 385 0x00, 0x77, 0x4a, 0x61, 0x5d, 0x22, 0x4b, 0x6f, 386 0x4e, 0x3b, 0x4c, 0x50, 0x67, 0x2a, 0x7d, 0x74, 387 0x54, 0x2b, 0x2d, 0x2c, 0x30, 0x6e, 0x6b, 0x66, 388 0x35, 0x25, 0x21, 0x64, 0x4d, 0x52, 0x63, 0x3f, 389 0x7b, 0x78, 0x29, 0x28, 0x73, 0x59, 0x33, 0x7f, 390 0x6d, 0x55, 0x53, 0x7c, 0x3a, 0x5f, 0x65, 0x46, 391 0x58, 0x31, 0x69, 0x6c, 0x5a, 0x48, 0x27, 0x5c, 392 0x3d, 0x24, 0x79, 0x37, 0x60, 0x51, 0x20, 0x36], 393 [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 394 0x08, 0x6e, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 395 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 396 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 397 0x2d, 0x75, 0x52, 0x60, 0x71, 0x5e, 0x49, 0x5c, 398 0x62, 0x7d, 0x29, 0x36, 0x20, 0x7c, 0x7a, 0x7f, 399 0x6b, 0x63, 0x33, 0x2b, 0x68, 0x51, 0x66, 0x76, 400 0x31, 0x64, 0x54, 0x43, 0x00, 0x3a, 0x00, 0x7e, 401 0x00, 0x45, 0x2c, 0x2a, 0x74, 0x27, 0x37, 0x44, 402 0x79, 0x59, 0x2f, 0x6f, 0x26, 0x72, 0x6a, 0x39, 403 0x7b, 0x3f, 0x38, 0x77, 0x67, 0x53, 0x47, 0x34, 404 0x78, 0x5d, 0x30, 0x23, 0x5a, 0x5b, 0x6c, 0x48, 405 0x55, 0x70, 0x69, 0x2e, 0x4c, 0x21, 0x24, 0x4e, 406 0x50, 0x09, 0x56, 0x73, 0x35, 0x61, 0x4b, 0x58, 407 0x3b, 0x57, 0x22, 0x6d, 0x4d, 0x25, 0x28, 0x46, 408 0x4a, 0x32, 0x41, 0x3d, 0x5f, 0x4f, 0x42, 0x65], 409 ] 410 411 unescape = { 412 "#": "\r", "&": "\n", "!": "<", "*": ">", "$": "@", 413 } 414 415 script_re = "<\\s*script\\s*.*>.*?<\\s*/\\s*script\\s*>" 416
417 - def __init__(self, filepath):
418 self.filepath = filepath
419
420 - def decode(self, source, start="#@~^", end="^#~@"):
421 if start not in source or end not in source: 422 return 423 424 o = source.index(start) + len(start) + 8 425 end = source.index(end) - 8 426 427 c, m, r = 0, 0, [] 428 429 while o < end: 430 ch = ord(source[o]) 431 if source[o] == "@": 432 r.append(ord(self.unescape.get(source[o+1], "?"))) 433 c += r[-1] 434 o, m = o + 1, m + 1 435 elif ch < 128: 436 r.append(self.lookup[self.encoding[m % 64]][ch]) 437 c += r[-1] 438 m = m + 1 439 else: 440 r.append(ch) 441 442 o = o + 1 443 444 if (c % 2**32) != struct.unpack("I", source[o:o+8].decode("base64"))[0]: 445 log.info("Invalid checksum for JScript.Encoded WSF file!") 446 447 return "".join(chr(ch) for ch in r)
448
449 - def run(self):
450 ret = [] 451 source = open(self.filepath, "rb").read() 452 453 # Get rid of superfluous comments. 454 source = re.sub("/\\*.*?\\*/", "", source, flags=re.S) 455 456 for script in re.findall(self.script_re, source, re.I | re.S): 457 try: 458 x = bs4.BeautifulSoup(script, "html.parser") 459 language = x.script.attrs.get("language", "").lower() 460 except: 461 language = None 462 463 # We can't rely on bs4 or any other HTML/XML parser to provide us 464 # with the raw content of the xml tag as they decode html entities 465 # and all that, leaving us with a corrupted string. 466 source = re.match("<.*>(.*)</.*>$", script, re.S).group(0) 467 468 # Decode JScript.Encode encoding. 469 if language in ("jscript.encode", "vbscript.encode"): 470 source = self.decode(source) 471 472 ret.append(to_unicode(source)) 473 474 return ret
475
476 -class OfficeDocument(object):
477 """Static analysis of Microsoft Office documents.""" 478 deobf = [ 479 # [ 480 # # Chr(65) -> "A" 481 # "Chr\\(\\s*(?P<chr>[0-9]+)\\s*\\)", 482 # lambda x: '"%c"' % int(x.group("chr")), 483 # 0, 484 # ], 485 [ 486 # "A" & "B" -> "AB" 487 "\\\"(?P<a>.*?)\\\"\\s+\\&\\s+\\\"(?P<b>.*?)\\\"", 488 lambda x: '"%s%s"' % (x.group("a"), x.group("b")), 489 0, 490 ], 491 ] 492 493 eps_comments = "\\(([\\w\\s]+)\\)" 494
495 - def __init__(self, filepath):
496 self.filepath = filepath 497 self.files = {}
498
499 - def get_macros(self):
500 """Get embedded Macros if this is an Office document.""" 501 if not HAVE_OLETOOLS: 502 log.warning( 503 "In order to do static analysis of Microsoft Word documents " 504 "we're going to require oletools (`pip install oletools`)" 505 ) 506 return 507 508 try: 509 p = oletools.olevba.VBA_Parser(self.filepath) 510 except TypeError: 511 return 512 513 # We're not interested in plaintext. 514 if p.type == "Text": 515 return 516 517 try: 518 for f, s, v, c in p.extract_macros(): 519 yield { 520 "stream": s, 521 "filename": v.decode("latin-1"), 522 "orig_code": c.decode("latin-1"), 523 "deobf": self.deobfuscate(c.decode("latin-1")), 524 } 525 except ValueError as e: 526 log.warning( 527 "Error extracting macros from office document (this is an " 528 "issue with oletools - please report upstream): %s", e 529 )
530
531 - def deobfuscate(self, code):
532 """Bruteforce approach of regex-based deobfuscation.""" 533 changes = 1 534 while changes: 535 changes = 0 536 537 for pattern, repl, flags in self.deobf: 538 count = 1 539 while count: 540 code, count = re.subn(pattern, repl, code, flags=flags) 541 changes += count 542 543 return code
544
545 - def unpack_docx(self):
546 """Unpacks .docx-based zip files.""" 547 try: 548 z = zipfile.ZipFile(self.filepath) 549 for name in z.namelist(): 550 self.files[name] = z.read(name) 551 except: 552 return
553
554 - def extract_eps(self):
555 """Extract some information from Encapsulated Post Script files.""" 556 ret = [] 557 for filename, content in self.files.items(): 558 if filename.lower().endswith(".eps"): 559 ret.extend(re.findall(self.eps_comments, content)) 560 return ret
561
562 - def run(self):
563 self.unpack_docx() 564 565 return { 566 "macros": list(self.get_macros()), 567 "eps": self.extract_eps(), 568 }
569
570 -class PdfDocument(object):
571 """Static analysis of PDF documents.""" 572
573 - def __init__(self, filepath):
574 self.filepath = filepath
575
576 - def _parse_string(self, s):
577 # Big endian. 578 if s.startswith(u"\xfe\xff"): 579 return s[2:].encode("latin-1").decode("utf-16be") 580 581 # Little endian. 582 if s.startswith(u"\xff\xfe"): 583 return s[2:].encode("latin-1").decode("utf-16le") 584 585 return s
586
587 - def _sanitize(self, d, key):
588 return self._parse_string(d.get(key, "").decode("latin-1"))
589
590 - def run(self):
591 if not HAVE_PEEPDF: 592 log.warning( 593 "Unable to perform static PDF analysis as PeePDF is missing " 594 "(install with `pip install peepdf`)" 595 ) 596 return 597 598 p = peepdf.PDFCore.PDFParser() 599 r, f = p.parse( 600 self.filepath, forceMode=True, 601 looseMode=True, manualAnalysis=False 602 ) 603 if r: 604 log.warning("Error parsing PDF file, error code %s", r) 605 return 606 607 ret = [] 608 609 for version in xrange(f.updates + 1): 610 md = f.getBasicMetadata(version) 611 row = { 612 "version": version, 613 "creator": self._sanitize(md, "creator"), 614 "creation": self._sanitize(md, "creation"), 615 "title": self._sanitize(md, "title"), 616 "subject": self._sanitize(md, "subject"), 617 "producer": self._sanitize(md, "producer"), 618 "author": self._sanitize(md, "author"), 619 "modification": self._sanitize(md, "modification"), 620 "javascript": [], 621 "urls": [], 622 } 623 624 for obj in f.body[version].objects.values(): 625 if obj.object.type == "stream": 626 stream = obj.object.decodedStream 627 628 # Is this actually Javascript code? 629 if not peepdf.JSAnalysis.isJavascript(stream): 630 continue 631 632 row["javascript"].append({ 633 "orig_code": stream.decode("latin-1"), 634 "urls": [], 635 }) 636 continue 637 638 if obj.object.type == "dictionary": 639 for url in obj.object.urlsFound: 640 row["urls"].append(self._parse_string(url)) 641 642 for url in obj.object.uriList: 643 row["urls"].append(self._parse_string(url)) 644 645 ret.append(row) 646 647 return ret
648
649 -class Static(Processing):
650 """Static analysis.""" 651 PUBKEY_RE = "(-----BEGIN PUBLIC KEY-----[a-zA-Z0-9\\n\\+/]+-----END PUBLIC KEY-----)" 652 PRIVKEY_RE = "(-----BEGIN RSA PRIVATE KEY-----[a-zA-Z0-9\\n\\+/]+-----END RSA PRIVATE KEY-----)" 653 654 office_ext = [ 655 "doc", "docm", "dotm", "docx", "ppt", "pptm", "pptx", "potm", 656 "ppam", "ppsm", "xls", "xlsm", "xlsx", 657 ] 658
659 - def run(self):
660 """Run analysis. 661 @return: results dict. 662 """ 663 self.key = "static" 664 static = {} 665 666 # Does the target file still exist? 667 if self.task["category"] != "file" or \ 668 not os.path.exists(self.file_path): 669 return 670 671 package = self.task.get("package") 672 673 if self.task["category"] == "file": 674 ext = os.path.splitext(self.task["target"])[1].lstrip(".").lower() 675 else: 676 ext = None 677 678 if ext == "exe" or "PE32" in File(self.file_path).get_type(): 679 if HAVE_PEFILE: 680 static.update(PortableExecutable(self.file_path).run()) 681 static["keys"] = self._get_keys() 682 683 if package == "wsf" or ext == "wsf": 684 static["wsf"] = WindowsScriptFile(self.file_path).run() 685 686 if package in ("doc", "ppt", "xls") or ext in self.office_ext: 687 static["office"] = OfficeDocument(self.file_path).run() 688 689 def pdf_worker(filepath): 690 return PdfDocument(filepath).run()
691 692 if package == "pdf" or ext == "pdf": 693 timeout = int(self.options.get("pdf_timeout", 60)) 694 static["pdf"] = dispatch( 695 pdf_worker, (self.file_path,), timeout=timeout 696 ) 697 698 return static
699
700 - def _get_keys(self):
701 """Get any embedded plaintext public and/or private keys.""" 702 buf = open(self.file_path).read() 703 ret = set() 704 ret.update(re.findall(self.PUBKEY_RE, buf)) 705 ret.update(re.findall(self.PRIVKEY_RE, buf)) 706 return list(ret)
707