def decompress(self, dump_dir): # Check if the file type is right. # TODO: this might be a bit hacky, need to verify whether malformed # Flash exploit would get a different file type. if 'Flash' not in __sessions__.current.file.type: self.log('error', "The opened file doesn't appear to be a valid SWF object") return # Retrieve key information from the opened SWF file. header, version, size, data = self.parse_swf() # Decompressed data. decompressed = None # Check if the file is already a decompressed Flash object. if header == 'FWS': self.log('info', "The opened file doesn't appear to be compressed") return # Check if the file is compressed with zlib. elif header == 'CWS': self.log('info', "The opened file appears to be compressed with Zlib") # Open an handle on the compressed data. compressed = StringIO(data) # Skip the header. compressed.read(3) # Decompress and reconstruct the Flash object. decompressed = 'FWS' + compressed.read(5) + zlib.decompress(compressed.read()) # Check if the file is compressed with lzma. elif header == 'ZWS': self.log('info', "The opened file appears to be compressed with Lzma") # We need an third party library to decompress this. if not HAVE_PYLZMA: self.log('error', "Missing dependency, please install pylzma (`pip install pylzma`)") return # Open and handle on the compressed data. compressed = StringIO(data) # Skip the header. compressed.read(3) # Decompress with pylzma and reconstruct the Flash object. ## ZWS(LZMA) ## | 4 bytes | 4 bytes | 4 bytes | 5 bytes | n bytes | 6 bytes | ## | 'ZWS'+version | scriptLen | compressedLen | LZMA props | LZMA data | LZMA end marker | decompressed = 'FWS' + compressed.read(5) compressed.read(4) # skip compressedLen decompressed += pylzma.decompress(compressed.read()) # If we obtained some decompressed data, we print it and eventually # dump it to file. if decompressed: # Print the decompressed data # TODO: this prints too much, need to find a better wayto display # this. Paginate? self.log('', cyan(hexdump(decompressed))) if dump_dir: # Dump the decompressed SWF file to the specified directory # or to the default temporary one. dump_path = os.path.join(dump_dir, '{0}.swf'.format(get_md5(decompressed))) with open(dump_path, 'wb') as handle: handle.write(decompressed) self.log('info', "Flash object dumped at {0}".format(dump_path)) # Directly open a session on the dumped Flash object. __sessions__.new(dump_path)
def decompress(self, dump_dir): # Check if the file type is right. # TODO: this might be a bit hacky, need to verify whether malformed # Flash exploit would get a different file type. if 'Flash' not in __sessions__.current.file.type: self.log( 'error', "The opened file doesn't appear to be a valid SWF object") return # Retrieve key information from the opened SWF file. header, version, size, data = self.parse_swf() # Decompressed data. decompressed = None # Check if the file is already a decompressed Flash object. if header == 'FWS': self.log('info', "The opened file doesn't appear to be compressed") return # Check if the file is compressed with zlib. elif header == 'CWS': self.log('info', "The opened file appears to be compressed with Zlib") # Open an handle on the compressed data. compressed = StringIO(data) # Skip the header. compressed.read(3) # Decompress and reconstruct the Flash object. decompressed = 'FWS' + compressed.read(5) + zlib.decompress( compressed.read()) # Check if the file is compressed with lzma. elif header == 'ZWS': self.log('info', "The opened file appears to be compressed with Lzma") # We need an third party library to decompress this. if not HAVE_PYLZMA: self.log( 'error', "Missing dependency, please install pylzma (`pip install pylzma`)" ) return # Open and handle on the compressed data. compressed = StringIO(data) # Skip the header. compressed.read(3) # Decompress with pylzma and reconstruct the Flash object. ## ZWS(LZMA) ## | 4 bytes | 4 bytes | 4 bytes | 5 bytes | n bytes | 6 bytes | ## | 'ZWS'+version | scriptLen | compressedLen | LZMA props | LZMA data | LZMA end marker | decompressed = 'FWS' + compressed.read(5) compressed.read(4) # skip compressedLen decompressed += pylzma.decompress(compressed.read()) # If we obtained some decompressed data, we print it and eventually # dump it to file. if decompressed: # Print the decompressed data # TODO: this prints too much, need to find a better wayto display # this. Paginate? self.log('', cyan(hexdump(decompressed))) if dump_dir: # Dump the decompressed SWF file to the specified directory # or to the default temporary one. dump_path = os.path.join( dump_dir, '{0}.swf'.format(get_md5(decompressed))) with open(dump_path, 'wb') as handle: handle.write(decompressed) self.log('info', "Flash object dumped at {0}".format(dump_path)) # Directly open a session on the dumped Flash object. __sessions__.new(dump_path)
def run(self): super(Shellcode, self).run() if self.args is None: return if not __sessions__.is_set(): self.log('error', "No session opened") return collection = [ { 'description': 'FS:[30h] shellcode', 'patterns': [ b'\x64\xa1\x30\x00|\x64\x8b\x0d\x30|\x64\x8b\x0d\x30|\x64\x8b\x15\x30|\x64\x8b\x35\x30|\x64\x8b\x3d\x30|\x6a\x30.\x64\x8b|\x33..\xb3\x64\x8b', '64a13000|648b0d30|648b0d30|648b1530|648b3530|648b3d30|6a30..648b|33....b3648b' ] }, { 'description': 'FS:[00h] shellcode', 'patterns': [ b'\x64\x8b\x1d|\x64\xa1\x00|\x64\x8b\x0d|\x64\x8b\x15|\x64\x8b\x35|\x64\x8b\x3d', '648b1d00|64a10000|648b0d00|648b1500|648b3500|648b3d00' ] }, { 'description': 'API hashing', 'patterns': [ b'\x74.\xc1.\x0d\x03|\x74.\xc1.\x07\x03', '74..c1..0d03|74..c1..0703' ] }, { 'description': 'PUSH DWORD[]/CALL[]', 'patterns': [ b'\x00\xff\x75\x00\xff\x55', '00ff7500ff55' ] }, { 'description': 'FLDZ/FSTENV [esp-12]', 'patterns': [ b'\x00\xd9\x00\xee\x00\xd9\x74\x24\x00\xf4\x00\x00', '00d900ee00d9742400f40000' ] }, { 'description': 'CALL next/POP', 'patterns': [ b'\x00\xe8\x00\x00\x00\x00(\x58|\x59|\x5a|\x5b|\x5e|\x5f|\x5d)\x00\x00', '00e800000000(58|59|5a|5b|5e|5f|5d)0000' ] }, { 'description': 'Function prolog', 'patterns': [ b'\x55\x8b\x00\xec\x83\x00\xc4|\x55\x8b\x0ec\x81\x00\xec|\x55\x8b\x00\xec\x8b|\x55\x8b\x00\xec\xe8|\x55\x8b\x00\xec\xe9', '558b00ec8300c4|558b0ec8100ec|558b00ec8b|558b00ece8|558b00ece9' ] }, ] self.log('info', "Searching for known shellcode patterns...") for entry in collection: for pattern in entry['patterns']: match = re.search(pattern, __sessions__.current.file.data) if match: offset = match.start() self.log('info', "{0} pattern matched at offset {1}".format(entry['description'], offset)) self.log('', cyan(hexdump(__sessions__.current.file.data[offset:], maxlines=15)))