def transition_function( sock, # type: _SocketUnion config, # type: AutomotiveTestCaseExecutorConfiguration kwargs # type: Dict[str, Any] ): # type: (...) -> bool """ Very basic transition function. This function sends a given request in kwargs and evaluates the response. :param sock: Connection to the DUT :param config: Global configuration of the executor (unused) :param kwargs: Dictionary with arguments. This function only uses the argument *"req"* which must contain a Packet, causing an EcuState transition of the DUT. :return: True in case of a successful transition, else False """ req = kwargs.get("req", None) if req is None: return False try: res = sock.sr1(req, timeout=20, verbose=False, chainEX=True) return res is not None and res.service != 0x7f except (OSError, ValueError, Scapy_Exception) as e: log_interactive.critical( "[-] Exception in transition function: %s", e) return False
def show(self, dump=False, filtered=True, verbose=False): # type: (bool, bool, bool) -> Optional[str] s = super(UDS_RMBASequentialEnumerator, self).show( dump, filtered, verbose) or "" try: from intelhex import IntelHex ih = IntelHex() for tup in self.results_with_positive_response: for i, b in enumerate(tup.resp.dataRecord): addr = self.get_addr(tup.req) ih[addr + i] = orb(b) ih.tofile("RMBA_dump.hex", format="hex") except ImportError: err_msg = "Install 'intelhex' to create a hex file of the memory" log_interactive.critical(err_msg) with open("RMBA_dump.hex", "w") as file: file.write(err_msg) if dump: return s + "\n" else: print(s) return None
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 sr1_with_retry_on_error(self, req, socket, state, timeout): # type: (Packet, _SocketUnion, EcuState, int) -> Optional[Packet] try: res = socket.sr1(req, timeout=timeout, verbose=False, chainEX=True) 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 return res
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 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 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 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))