def render(self, filename="SystemStateGraph.gv", view=True): # type: (str, bool) -> None """ Renders this Graph as PDF, if `graphviz` is installed. :param filename: A filename for the rendered PDF. :param view: If True, rendered file will be opened. """ try: from graphviz import Digraph except ImportError: log_interactive.info("Please install graphviz.") return ps = Digraph(name="SystemStateGraph", node_attr={ "fillcolor": "lightgrey", "style": "filled", "shape": "box" }, graph_attr={"concentrate": "true"}) for n in self.nodes: ps.node(str(n)) for e, f in self.__transition_functions.items(): try: desc = "" if f is None else f[1]["desc"] except (AttributeError, KeyError): desc = "" ps.edge(str(e[0]), str(e[1]), label=desc) ps.render(filename, view=view)
def get_security_access(self, sock, level=1, seed_pkt=None): # type: (_SocketUnion, int, Optional[Packet]) -> bool log_interactive.info("Try bootloader security access for level %d" % level) if seed_pkt is None: seed_pkt = self.get_seed_pkt(sock, level) if not seed_pkt: return False if not any(seed_pkt.securitySeed): return False key_pkt = self.get_key_pkt(seed_pkt, level) if key_pkt is None: return False try: res = sock.sr1(key_pkt, timeout=5, verbose=False) if sock.closed: log_interactive.critical("[-] Socket closed during scan.") raise Scapy_Exception("Socket closed during scan") except (OSError, ValueError, Scapy_Exception) as e: try: last_seed_req = self._results[-1].req last_state = self._results[-1].state if not self._populate_retry(last_state, last_seed_req): log_interactive.critical( "[-] Exception during retry. This is bad") except IndexError: log_interactive.warning("[-] Couldn't populate retry.") raise e return self.evaluate_security_access_response(res, seed_pkt, key_pkt)
def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None, replay_args=None, # noqa: E501 parse_results=False): """Send packets at layer 2 using tcpreplay for performance :param pps: packets per second :param mpbs: MBits per second :param realtime: use packet's timestamp, bending time with real-time value :param loop: number of times to process the packet list :param file_cache: cache packets in RAM instead of reading from disk at each iteration :param iface: output interface :param replay_args: List of additional tcpreplay args (List[str]) :param parse_results: Return a dictionary of information outputted by tcpreplay (default=False) :returns: stdout, stderr, command used """ if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % network_name(iface)] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--preload-pcap") # Check for any additional args we didn't cover. if replay_args is not None: argv.extend(replay_args) f = get_temp_file() argv.append(f) wrpcap(f, x) results = None with ContextManagerSubprocess(conf.prog.tcpreplay): try: cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception: os.unlink(f) raise else: stdout, stderr = cmd.communicate() if stderr: log_runtime.warning(stderr.decode()) if parse_results: results = _parse_tcpreplay_result(stdout, stderr, argv) elif conf.verb > 2: log_runtime.info(stdout.decode()) os.unlink(f) return results
def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None): """Send packets at layer 2 using tcpreplay for performance pps: packets per second mpbs: MBits per second realtime: use packet's timestamp, bending time with realtime value loop: number of times to process the packet list file_cache: cache packets in RAM instead of reading from disk at each iteration iface: output interface """ if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % iface ] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--enable-file-cache") f = get_temp_file() argv.append(f) wrpcap(f, x) try: subprocess.check_call(argv) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception,e: log_interactive.error("while trying to exec [%s]: %s" % (argv[0],e))
def enter_state(self, prev_state, next_state): # type: (EcuState, EcuState) -> bool """ Obtains a transition function from the system state graph and executes it. On success, the cleanup function is added for a later cleanup of the new state. :param prev_state: Current state :param next_state: Desired state :return: True, if state could be changed successful """ edge = (prev_state, next_state) funcs = self.state_graph.get_transition_tuple_for_edge(edge) if funcs is None: log_interactive.error("[!] No transition function for %s", edge) return False trans_func, trans_kwargs, clean_func = funcs state_changed = trans_func(self.socket, self.configuration, trans_kwargs) if state_changed: self.target_state = next_state if clean_func is not None: self.cleanup_functions += [clean_func] return True else: log_interactive.info("[-] Transition for edge %s failed", edge) return False
def has_completed(self, state): # type: (EcuState) -> bool if not (self.current_test_case.has_completed(state) and self.current_test_case.completed): # current test_case not fully completed # reset completion delay, since new states could have been appeared self.__completion_delay = 0 return False # current stage is finished. We have to increase the stage if self.__completion_delay < StagedAutomotiveTestCase.__delay_stages: # First we wait five more iteration of the executor # Maybe one more execution reveals new states of other # test_cases self.__completion_delay += 1 return False # current test_case is fully completed elif self.__stage_index == len(self.__test_cases) - 1: # this test_case was the last test_case... nothing to do return True else: # We waited more iterations and no new state appeared, # let's enter the next stage log_interactive.info("[+] Staged AutomotiveTestCase %s completed", self.current_test_case.__class__.__name__) self.__stage_index += 1 self.__completion_delay = 0 return False
def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None, replay_args=None, # noqa: E501 parse_results=False): """Send packets at layer 2 using tcpreplay for performance pps: packets per second mpbs: MBits per second realtime: use packet's timestamp, bending time with real-time value loop: number of times to process the packet list file_cache: cache packets in RAM instead of reading from disk at each iteration # noqa: E501 iface: output interface replay_args: List of additional tcpreplay args (List[str]) parse_results: Return a dictionary of information outputted by tcpreplay (default=False) # noqa: E501 :returns stdout, stderr, command used""" if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % iface] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--preload-pcap") # Check for any additional args we didn't cover. if replay_args is not None: argv.extend(replay_args) f = get_temp_file() argv.append(f) wrpcap(f, x) results = None try: log_runtime.info(argv) with subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as cmd: # noqa: E501 stdout, stderr = cmd.communicate() log_runtime.info(stdout) log_runtime.warning(stderr) if parse_results: results = _parse_tcpreplay_result(stdout, stderr, argv) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception: if conf.interactive: log_interactive.error("Cannot execute [%s]", argv[0], exc_info=True) # noqa: E501 else: raise finally: os.unlink(f) return results
def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None, replay_args=None, # noqa: E501 parse_results=False): """Send packets at layer 2 using tcpreplay for performance pps: packets per second mpbs: MBits per second realtime: use packet's timestamp, bending time with real-time value loop: number of times to process the packet list file_cache: cache packets in RAM instead of reading from disk at each iteration # noqa: E501 iface: output interface replay_args: List of additional tcpreplay args (List[str]) parse_results: Return a dictionary of information outputted by tcpreplay (default=False) # noqa: E501 :returns stdout, stderr, command used""" if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % iface] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--preload-pcap") # Check for any additional args we didn't cover. if replay_args is not None: argv.extend(replay_args) f = get_temp_file() argv.append(f) wrpcap(f, x) results = None with ContextManagerSubprocess("sendpfast()", conf.prog.tcpreplay): try: cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception: os.unlink(f) raise else: stdout, stderr = cmd.communicate() if stderr: log_runtime.warning(stderr.decode()) if parse_results: results = _parse_tcpreplay_result(stdout, stderr, argv) elif conf.verb > 2: log_runtime.info(stdout.decode()) os.unlink(f) return results
def reset_target(self): log_interactive.info("[i] Target reset") self.reset_tps() if self.reset_handler: try: self.reset_handler(self) except TypeError: self.reset_handler() self.target_state = ECU_State()
def save_session(fname="", session=None, pickleProto=-1): # type: (str, Optional[Dict[str, Any]], int) -> None """Save current Scapy session to the file specified in the fname arg. params: - fname: file to save the scapy session in - session: scapy session to use. If None, the console one will be used - pickleProto: pickle proto version (default: -1 = latest)""" from scapy import utils from scapy.config import conf, ConfClass if not fname: fname = conf.session if not fname: conf.session = fname = utils.get_temp_file(keep=True) log_interactive.info("Saving session into [%s]", fname) if not session: try: from IPython import get_ipython session = get_ipython().user_ns except Exception: session = six.moves.builtins.__dict__["scapy_session"] if not session: log_interactive.error("No session found ?!") return ignore = session.get("_scpybuiltins", []) hard_ignore = ["scapy_session", "In", "Out"] to_be_saved = session.copy() for k in list(to_be_saved): i = to_be_saved[k] if k[0] == "_": del(to_be_saved[k]) elif hasattr(i, "__module__") and i.__module__.startswith("IPython"): del(to_be_saved[k]) elif isinstance(i, ConfClass): del(to_be_saved[k]) elif k in ignore or k in hard_ignore: del(to_be_saved[k]) elif isinstance(i, (type, types.ModuleType)): if k[0] != "_": log_interactive.warning("[%s] (%s) can't be saved.", k, type(to_be_saved[k])) del(to_be_saved[k]) try: os.rename(fname, fname + ".bak") except OSError: pass f = gzip.open(fname, "wb") six.moves.cPickle.dump(to_be_saved, f, pickleProto) f.close()
def evaluate_security_access_response(res, seed, key): # type: (Optional[Packet], Packet, Optional[Packet]) -> bool if res is None or res.service == 0x7f: log_interactive.debug(repr(seed)) log_interactive.debug(repr(key)) log_interactive.debug(repr(res)) log_interactive.info("Security access error!") return False else: log_interactive.info("Security access granted!") return True
def execute(self, socket, state, **kwargs): # type: (_SocketUnion, EcuState, Any) -> None self.check_kwargs(kwargs) timeout = kwargs.pop('timeout', 1) execution_time = kwargs.pop("execution_time", 1200) state_block_list = kwargs.get('state_block_list', list()) if state_block_list and state in state_block_list: self._state_completed[state] = True log_interactive.debug("[i] State %s in block list!", repr(state)) return state_allow_list = kwargs.get('state_allow_list', list()) if state_allow_list and state not in state_allow_list: self._state_completed[state] = True log_interactive.debug("[i] State %s not in allow list!", repr(state)) return it = self.__get_request_iterator(state, **kwargs) # log_interactive.debug("[i] Using iterator %s in state %s", it, state) start_time = time.time() log_interactive.debug("[i] Start execution of enumerator: %s", time.ctime(start_time)) for req in it: res = self.sr1_with_retry_on_error(req, socket, state, timeout) self._store_result(state, req, res) if self._evaluate_response(state, req, res, **kwargs): log_interactive.debug("[i] Stop test_case execution because " "of response evaluation") return if (start_time + execution_time) < time.time(): log_interactive.debug( "[i] Finished execution time of enumerator: %s", time.ctime()) return log_interactive.info("[i] Finished iterator execution") self._state_completed[state] = True log_interactive.debug("[i] States completed %s", repr(self._state_completed))
def reconnect(self): # type: () -> None if self.reconnect_handler: try: self.socket.close() except Exception as e: log_interactive.debug("[i] Exception '%s' during socket.close", e) log_interactive.info("[i] Target reconnect") socket = self.reconnect_handler() if not isinstance(socket, SingleConversationSocket): self.socket = SingleConversationSocket(socket) else: self.socket = socket
def save_session(fname=None, session=None, pickleProto=-1): """Save current Scapy session to the file specified in the fname arg. params: - fname: file to save the scapy session in - session: scapy session to use. If None, the console one will be used - pickleProto: pickle proto version (default: -1 = latest)""" from scapy import utils from scapy.config import conf, ConfClass if fname is None: fname = conf.session if not fname: conf.session = fname = utils.get_temp_file(keep=True) log_interactive.info("Use [%s] as session file" % fname) if session is None: try: session = get_ipython().user_ns except Exception: session = six.moves.builtins.__dict__["scapy_session"] to_be_saved = session.copy() if "__builtins__" in to_be_saved: del (to_be_saved["__builtins__"]) for k in list(to_be_saved): i = to_be_saved[k] if hasattr(i, "__module__") and ( k[0] == "_" or i.__module__.startswith("IPython")): # noqa: E501 del (to_be_saved[k]) if isinstance(i, ConfClass): del (to_be_saved[k]) elif isinstance(i, (type, type, types.ModuleType)): if k[0] != "_": log_interactive.error("[%s] (%s) can't be saved.", k, type(to_be_saved[k])) # noqa: E501 del (to_be_saved[k]) try: os.rename(fname, fname + ".bak") except OSError: pass f = gzip.open(fname, "wb") six.moves.cPickle.dump(to_be_saved, f, pickleProto) f.close() del f
def run(self): log_interactive.info("Pipe engine thread started.") try: for p in self.active_pipes: p.start() sources = self.active_sources sources.add(self) exhausted = set([]) RUN = True STOP_IF_EXHAUSTED = False while RUN and (not STOP_IF_EXHAUSTED or len(sources) > 1): fds = select_objects(sources, 2, customTypes=(AutoSource, PipeEngine)) for fd in fds: if fd is self: cmd = self._read_cmd() if cmd == "X": RUN = False break elif cmd == "B": STOP_IF_EXHAUSTED = True elif cmd == "A": sources = self.active_sources - exhausted sources.add(self) else: warning( "Unknown internal pipe engine command: %r. Ignoring." % cmd) elif fd in sources: try: fd.deliver() except Exception as e: log_interactive.exception( "piping from %s failed: %s" % (fd.name, e)) else: if fd.exhausted(): exhausted.add(fd) sources.remove(fd) except KeyboardInterrupt: pass finally: try: for p in self.active_pipes: p.stop() finally: self.thread_lock.release() log_interactive.info("Pipe engine thread stopped.")
def _prepare_negative_response_blacklist(self): # type: () -> None nrc_dict = defaultdict(int) # type: Dict[int, int] for nr in self.results_with_negative_response: nrc_dict[self._get_negative_response_code(nr.resp)] += 1 total_nr_count = len(self.results_with_negative_response) for nrc, nr_count in nrc_dict.items(): if nrc not in self.negative_response_blacklist and \ nr_count > 30 and (nr_count / total_nr_count) > 0.3: log_interactive.info("Added NRC 0x%02x to filter", nrc) self.negative_response_blacklist.append(nrc) if nrc in self.negative_response_blacklist and nr_count < 10: log_interactive.info("Removed NRC 0x%02x to filter", nrc) self.negative_response_blacklist.remove(nrc)
def get_security_access(sock, level=1, seed_pkt=None): # type: (_SocketUnion, int, Optional[Packet]) -> bool log_interactive.info("Try bootloader security access for level %d" % level) if seed_pkt is None: seed_pkt = UDS_SAEnumerator.get_seed_pkt(sock, level) if not seed_pkt: return False key_pkt = UDS_SA_XOR_Enumerator.get_key_pkt(seed_pkt, level) if key_pkt is None: return False res = sock.sr1(key_pkt, timeout=5, verbose=False) return UDS_SA_XOR_Enumerator.evaluate_security_access_response( res, seed_pkt, key_pkt)
def execute(self, socket, state, **kwargs): # type: (_SocketUnion, EcuState, Any) -> None timeout = kwargs.pop('timeout', 1) execution_time = kwargs.pop("execution_time", 1200) it = self.__get_request_iterator(state, **kwargs) # log_interactive.debug("[i] Using iterator %s in state %s", it, state) start_time = time.time() log_interactive.debug("[i] Start execution of enumerator: %s", time.ctime(start_time)) for req in it: try: res = socket.sr1(req, timeout=timeout, verbose=False) except (OSError, ValueError, Scapy_Exception) as e: if self._retry_pkt[state] is None: log_interactive.debug( "[-] Exception '%s' in execute. Prepare for retry", e) self._retry_pkt[state] = req else: log_interactive.critical( "[-] Exception during retry. This is bad") raise e if socket.closed: log_interactive.critical("[-] Socket closed during scan.") return self._store_result(state, req, res) if self._evaluate_response(state, req, res, **kwargs): log_interactive.debug("[i] Stop test_case execution because " "of response evaluation") return if (start_time + execution_time) < time.time(): log_interactive.debug( "[i] Finished execution time of enumerator: %s", time.ctime()) return log_interactive.info("[i] Finished iterator execution") self._state_completed[state] = True log_interactive.debug("[i] States completed %s", repr(self._state_completed))
def cleanup_state(self): # type: () -> None """ Executes all collected cleanup functions from a traversed path :return: None """ for f in self.cleanup_functions: if not callable(f): continue try: if not f(self.socket, self.configuration): log_interactive.info("[-] Cleanup function %s failed", repr(f)) except (OSError, ValueError, Scapy_Exception) as e: log_interactive.critical("[!] Exception during cleanup: %s", e) self.cleanup_functions = list()
def run(self): log_interactive.info("Pipe engine thread started.") try: for p in self.active_pipes: p.start() sources = self.active_sources sources.add(self.__fdr) exhausted = set([]) RUN = True STOP_IF_EXHAUSTED = False while RUN and (not STOP_IF_EXHAUSTED or len(sources) > 1): fds, fdo, fde = select.select(sources, [], []) for fd in fds: if fd is self.__fdr: cmd = os.read(self.__fdr, 1) if cmd == "X": RUN = False break elif cmd == "B": STOP_IF_EXHAUSTED = True elif cmd == "A": sources = self.active_sources-exhausted sources.add(self.__fdr) else: warning( "Unknown internal pipe engine command: %r. Ignoring." % cmd) elif fd in sources: try: fd.deliver() except Exception, e: log_interactive.exception( "piping from %s failed: %s" % (fd.name, e)) else: if fd.exhausted(): exhausted.add(fd) sources.remove(fd) except KeyboardInterrupt: pass finally: try: for p in self.active_pipes: p.stop() finally: self.thread_lock.release() log_interactive.info("Pipe engine thread stopped.")
def save_session(fname=None, session=None, pickleProto=-1): """Save current Scapy session to the file specified in the fname arg. params: - fname: file to save the scapy session in - session: scapy session to use. If None, the console one will be used - pickleProto: pickle proto version (default: -1 = latest)""" from scapy import utils if fname is None: fname = conf.session if not fname: conf.session = fname = utils.get_temp_file(keep=True) log_interactive.info("Use [%s] as session file" % fname) if session is None: try: session = get_ipython().user_ns except: session = six.moves.builtins.__dict__["scapy_session"] to_be_saved = session.copy() if "__builtins__" in to_be_saved: del(to_be_saved["__builtins__"]) for k in list(to_be_saved): i = to_be_saved[k] if hasattr(i, "__module__") and (k[0] == "_" or i.__module__.startswith("IPython")): del(to_be_saved[k]) if isinstance(i, ConfClass): del(to_be_saved[k]) elif isinstance(i, (type, type, types.ModuleType)): if k[0] != "_": log_interactive.error("[%s] (%s) can't be saved.", k, type(to_be_saved[k])) del(to_be_saved[k]) try: os.rename(fname, fname+".bak") except OSError: pass f=gzip.open(fname,"wb") six.moves.cPickle.dump(to_be_saved, f, pickleProto) f.close() del f
def get_security_access(sock, level=1, seed_pkt=None, keyfunction=None): # type: (_SocketUnion, int, Optional[Packet], Optional[Callable[[int], int]]) -> bool # noqa: E501 log_interactive.info("Try bootloader security access for level %d" % level) if seed_pkt is None: seed_pkt = GMLAN_SAEnumerator.get_seed_pkt(sock, level) if not seed_pkt: return False if keyfunction is None: return False key_pkt = GMLAN_SAEnumerator.get_key_pkt(seed_pkt, keyfunction, level) if key_pkt is None: return False res = sock.sr1(key_pkt, timeout=5, verbose=False) return GMLAN_SAEnumerator.evaluate_security_access_response( res, seed_pkt, key_pkt)
def get_seed_pkt(sock, level=1): # type: (_SocketUnion, int) -> Optional[Packet] req = GMLAN() / GMLAN_SA(subfunction=level) for _ in range(10): seed = sock.sr1(req, timeout=5, verbose=False) if seed is None: return None elif seed.service == 0x7f and \ GMLAN_Enumerator._get_negative_response_code(seed) != 0x37: log_interactive.info("Security access no seed! NR: %s", repr(seed)) return None elif seed.service == 0x7f and \ GMLAN_Enumerator._get_negative_response_code(seed) == 0x37: log_interactive.info("Security access retry to get seed") time.sleep(10) continue else: return seed return None
def get_seed_pkt(sock, level=1, record=b""): # type: (_SocketUnion, int, bytes) -> Optional[Packet] req = UDS() / UDS_SA(securityAccessType=level, securityAccessDataRecord=record) for _ in range(10): seed = sock.sr1(req, timeout=5, verbose=False) if seed is None: return None elif seed.service == 0x7f and \ UDS_Enumerator._get_negative_response_code(seed) != 0x37: log_interactive.info("Security access no seed! NR: %s", repr(seed)) return None elif seed.service == 0x7f and seed.negativeResponseCode == 0x37: log_interactive.info("Security access retry to get seed") time.sleep(10) continue else: return seed return None
def _activate_routing( self, source_address, # type: int target_address, # type: int activation_type, # type: int reserved_oem=b"" # type: bytes ): # type: (...) -> None resp = self.sr1(DoIP(payload_type=0x5, activation_type=activation_type, source_address=source_address, reserved_oem=reserved_oem), verbose=False, timeout=1) if resp and resp.payload_type == 0x6 and \ resp.routing_activation_response == 0x10: self.target_address = target_address or \ resp.logical_address_doip_entity log_interactive.info( "Routing activation successful! Target address set to: 0x%x", self.target_address) else: log_interactive.error("Routing activation failed! Response: %s", repr(resp))
def scan(self, timeout=None): # type: (Optional[int]) -> None """ Executes all testcases for a given time. :param timeout: Time for execution. :return: None """ kill_time = time.time() + (timeout or 0xffffffff) while kill_time > time.time(): test_case_executed = False log_interactive.debug("[i] Scan paths %s", self.state_paths) for p, test_case in product(self.state_paths, self.configuration.test_cases): log_interactive.info("[i] Scan path %s", p) terminate = kill_time < time.time() if terminate: log_interactive.debug( "[-] Execution time exceeded. Terminating scan!") break final_state = p[-1] if test_case.has_completed(final_state): log_interactive.debug("[+] State %s for %s completed", repr(final_state), test_case) continue try: if not self.enter_state_path(p): log_interactive.error("[-] Error entering path %s", p) continue log_interactive.info("[i] Execute %s for path %s", str(test_case), p) self.execute_test_case(test_case) test_case_executed = True except (OSError, ValueError, Scapy_Exception) as e: log_interactive.critical("[-] Exception: %s", e) if self.configuration.debug: raise e if isinstance(e, OSError): log_interactive.critical( "[-] OSError occurred, closing socket") self.socket.close() if cast(SuperSocket, self.socket).closed and \ self.reconnect_handler is None: log_interactive.critical( "Socket went down. Need to leave scan") raise e finally: self.cleanup_state() if not test_case_executed: log_interactive.info( "[i] Execute failure or scan completed. Exit scan!") break self.cleanup_state() self.reset_target()
def scan(self): scan_complete = False while not scan_complete: scan_complete = True log_interactive.info("[i] Scan paths %s", self.get_state_paths()) for p in self.get_state_paths(): log_interactive.info("[i] Scan path %s", p) final_state = p[-1] for e in self.enumerators: if e.state_completed[final_state]: log_interactive.debug("[+] State %s for %s completed", repr(final_state), e) continue if not self.enter_state_path(p): log_interactive.error("[-] Error entering path %s", p) continue log_interactive.info("[i] EXECUTE SCAN %s for path %s", e.__class__.__name__, p) self.execute_enumerator(e) scan_complete = False self.reset_target()
def vprint(self, s=""): if self.verbose: if conf.interactive: log_interactive.info("> %s", s) else: print("> %s" % s)
def vprint(self, s=""): if self.verbose: log_interactive.info("> %s", s)
def execute(self, socket, state, **kwargs): # type: (_SocketUnion, EcuState, Any) -> None self.check_kwargs(kwargs) timeout = kwargs.pop('timeout', 1) execution_time = kwargs.pop("execution_time", 1200) state_block_list = kwargs.get('state_block_list', list()) if state_block_list and state in state_block_list: self._state_completed[state] = True log_interactive.debug("[i] State %s in block list!", repr(state)) return state_allow_list = kwargs.get('state_allow_list', list()) if state_allow_list and state not in state_allow_list: self._state_completed[state] = True log_interactive.debug("[i] State %s not in allow list!", repr(state)) return it = self.__get_request_iterator(state, **kwargs) # log_interactive.debug("[i] Using iterator %s in state %s", it, state) start_time = time.time() log_interactive.debug("[i] Start execution of enumerator: %s", time.ctime(start_time)) for req in it: try: res = socket.sr1(req, timeout=timeout, verbose=False) except (OSError, ValueError, Scapy_Exception) as e: if not self._populate_retry(state, req): log_interactive.critical( "[-] Exception during retry. This is bad") raise e if socket.closed: if not self._populate_retry(state, req): log_interactive.critical( "[-] Socket closed during retry. This is bad") log_interactive.critical("[-] Socket closed during scan.") raise Scapy_Exception("Socket closed during scan") self._store_result(state, req, res) if self._evaluate_response(state, req, res, **kwargs): log_interactive.debug("[i] Stop test_case execution because " "of response evaluation") return if (start_time + execution_time) < time.time(): log_interactive.debug( "[i] Finished execution time of enumerator: %s", time.ctime()) return log_interactive.info("[i] Finished iterator execution") self._state_completed[state] = True log_interactive.debug("[i] States completed %s", repr(self._state_completed))
def reset_target(self): # type: () -> None log_interactive.info("[i] Target reset") if self.reset_handler: self.reset_handler() self.target_state = self.__initial_ecu_state
def post_execute(self, socket, state, global_configuration): # type: (_SocketUnion, EcuState, AutomotiveTestCaseExecutorConfiguration) -> None # noqa: E501 if not self._state_completed[state]: return if not self.random_probe_finished[state]: log_interactive.info("[i] Random memory probing finished") self.random_probe_finished[state] = True for tup in [ t for t in self.results_with_positive_response if t.state == state ]: self.points_of_interest[state].append( (tup.req.memoryAddress, True)) self.points_of_interest[state].append( (tup.req.memoryAddress, False)) if not len(self.points_of_interest[state]): return log_interactive.info( "[i] Create %d memory points for sequential probing" % len(self.points_of_interest[state])) tested_addrs = [tup.req.memoryAddress for tup in self.results] pos_addrs = [ tup.req.memoryAddress for tup in self.results_with_positive_response if tup.state == state ] new_requests = list() new_points_of_interest = list() for poi, upward in self.points_of_interest[state]: if poi not in pos_addrs: continue temp_new_requests = list() for i in range(self.probe_width, self.sequential_probes_len + self.probe_width, self.probe_width): if upward: new_addr = min(poi + i, self.highest_possible_addr) else: new_addr = max(poi - i, 0) if new_addr not in tested_addrs: pkt = GMLAN() / GMLAN_RMBA(memoryAddress=new_addr, memorySize=self.probe_width) temp_new_requests.append(pkt) if len(temp_new_requests): new_points_of_interest.append( (temp_new_requests[-1].memoryAddress, upward)) new_requests += temp_new_requests self.points_of_interest[state] = list() if len(new_requests): self._state_completed[state] = False self._request_iterators[state] = new_requests self.points_of_interest[state] = new_points_of_interest log_interactive.info("[i] Created %d pkts for sequential probing" % len(new_requests))