# xxxswf.py was created by alexander dot hanel at gmail dot com # version 0.1 # Date - 12-07-2011 # To do list # - Tag Parser # - ActionScript Decompiler # 2016-11-01 PL: - A few changes for Python 2+3 compatibility import fnmatch import hashlib import math import os import re import struct import sys import time from io import BytesIO from optparse import OptionParser import zlib def checkMD5(md5): # checks if MD5 has been seen in MD5 Dictionary # MD5Dict contains the MD5 and the CVE # For { 'MD5':'CVE', 'MD5-1':'CVE-1', 'MD5-2':'CVE-2'} MD5Dict = {'c46299a5015c6d31ad5766cb49e4ab4b':'CVE-XXXX-XXXX'} if MD5Dict.get(md5): print('\t[BAD] MD5 Match on', MD5Dict.get(md5)) return def bad(f): for idx, x in enumerate(findSWF(f)): tmp = verifySWF(f,x) if tmp != None: yaraScan(tmp) checkMD5(hashBuff(tmp)) return def yaraScan(d): # d = buffer of the read file # Scans SWF using Yara # test if yara module is installed # if not Yara can be downloaded from http://code.google.com/p/yara-project/ try: import yara except ImportError: print('\t[ERROR] Yara module not installed - aborting scan') return # test for yara compile errors try: r = yara.compile(r'rules.yar') except: pass print('\t[ERROR] Yara compile error - aborting scan') return # get matches m = r.match(data=d) # print matches for X in m: print('\t[BAD] Yara Signature Hit: %s' % X) return def findSWF(d): # d = buffer of the read file # Search for SWF Header Sigs in files return [tmp.start() for tmp in re.finditer(b'CWS|FWS', d.read())] def hashBuff(d): # d = buffer of the read file # This function hashes the buffer # source: http://stackoverflow.com/q/5853830 if type(d) is str: d = BytesIO(d) md5 = hashlib.md5() while True: data = d.read(128) if not data: break md5.update(data) return md5.hexdigest() def verifySWF(f,addr): # Start of SWF f.seek(addr) # Read Header header = f.read(3) # Read Version ver = struct.unpack(' 20: print(' - [ERROR] Invalid SWF Version') return None if b'CWS' in header: try: f.read(3) tmp = b'FWS' + f.read(5) + zlib.decompress(f.read()) print(' - CWS Header') return tmp except: pass print('- [ERROR]: Zlib decompression error. Invalid CWS SWF') return None elif b'FWS' in header: try: tmp = f.read(size) print(' - FWS Header') return tmp except: pass print(' - [ERROR] Invalid SWF Size') return None else: print(' - [Error] Logic Error Blame Programmer') return None def headerInfo(f): # f is the already opended file handle # Yes, the format is is a rip off SWFDump. Can you blame me? Their tool is awesome. # SWFDump FORMAT # [HEADER] File version: 8 # [HEADER] File is zlib compressed. Ratio: 52% # [HEADER] File size: 37536 # [HEADER] Frame rate: 18.000000 # [HEADER] Frame count: 323 # [HEADER] Movie width: 217.00 # [HEADER] Movie height: 85.00 if type(f) is str: f = BytesIO(f) sig = f.read(3) print('\t[HEADER] File header: %s' % sig) if b'C' in sig: print('\t[HEADER] File is zlib compressed.') version = struct.unpack('> 3 print('\t[HEADER] Rect Nbit: %d' % nbit) # Curretely the nbit is static at 15. This could be modified in the # future. If larger than 9 this will break the struct unpack. Will have # to revist must be a more effective way to deal with bits. Tried to keep # the algo but damn this is ugly... f.seek(ta) rect = struct.unpack('>Q', f.read(int(math.ceil((nbit*4)/8.0))))[0] tmp = struct.unpack('>7)[2:].zfill(1) # bin requires Python 2.6 or higher # skips string '0b' and the nbit rect = bin(rect)[7:] xmin = int(rect[0:nbit-1],2) print('\t[HEADER] Rect Xmin: %d' % xmin) xmax = int(rect[nbit:(nbit*2)-1],2) print('\t[HEADER] Rect Xmax: %d' % xmax) ymin = int(rect[nbit*2:(nbit*3)-1],2) print('\t[HEADER] Rect Ymin: %d' % ymin) # one bit needs to be added, my math might be off here ymax = int(rect[nbit*3:(nbit*4)-1] + str(tmp) ,2) print('\t[HEADER] Rect Ymax: %d' % ymax) framerate = struct.unpack('