Предисловие
Думаю, стоит сразу указать ссылку, т.к. дальше я буду ссылаться на видеозапись, которую, к сожалению, нельзя прикрепить на Хабр...
Ссылка на материалы: ССЫЛКА
Уровень сложности: средний
Тип: misc, network, coding
Условие задачи:
Хакеры взломали освещение жилого дома и пустили по нему бегущей строкой свои требования: миллион фруктов юдзу и вертолет. А что было в начале их требований?
Нам доступно: перехваченный трафик в формате pcap и видео запись, на которой видно как хакеры взламывают освещение жилого дома.
Решение
Для начала посмотрим видеозапись инцидента... Заметим, что мы попали в ситуацию, которая постоянно рассматривается в кинофильмах: хакеры взломали освещение дома и используют его как баннер :-)
Что ж... Откроем запись трафика в Wireshark. И увидим, что записаны пакеты ZigBee (это протокол обмена между энерго-эффективными IoT устройствами). Заметим, что у нас первые 65 пакетов — это команды Off. То есть происходит «очистка экрана». Для удобства отфильтруем пакеты:
zbee_nwk.dst != 0x0000 && zbee_nwk.dst != 0xffff && zbee_zcl
где получатель покета не 0x0000 (не злоумышленник) и не 0xffff (Broadcast), а так же в пакете есть протокол ZigBee Cluster Library (в нём хранится команда On/Off).

Посмотрев по адресам destination в пакетах, мы можем понять, что матрица будет иметь размер 13х5. А "поковыряв" пакеты в сыром виде, заметим, что последний байт является командой Off(0x00) или On(0x01).


В целом, на этом решение и заканчивается... Дальше нужно просто распарсить все пакеты, которые удовлетворяют фильтру (1), а это всего лишь 5083 пакета :-)
Для парсинга будем использовать библиотеку Scapy. Подключаем следующие модули:
import scapy.all as scapy from scapy.config import conf from scapy.layers.zigbee import ZigbeeClusterLibrary from scapy.layers.zigbee import ZigbeeNWK
Conf нужен для уточнения, что мы работаем с пакетами ZigBee.
ZigbeeClusterLibrary нужен для проверки наличия данного протокола в пакете.
ZigbeeNWK нужен для проверки наличия данного протокола в пакете, а так же для получения источника и получателя пакета.
Затем, собираем все наши пакеты с командами в один список.
print("[*] Поиск пакетов с On/Off командами... ", end='') for i, pkt in enumerate(packets): if pkt.haslayer(ZigbeeNWK) and pkt.haslayer(ZigbeeClusterLibrary): znl = pkt[ZigbeeNWK] if znl.source != 0x0000 or znl.destination == 0xffff: continue raw = bytes(pkt) state = -1 if raw[-1] == ON_CMD: state = ON_CMD if raw[-1] == OFF_CMD: state = OFF_CMD commands.append((pkt.time, znl.destination, state))
Группируем пакеты в кадры по временным задержкам. Кстати, найти эту задержку можно с помощью Wireshark: задержка между пакетами, которые отрисовывают один «кусок» символа имеют задержку 0.16 секунд.
def group_commands_by_time_window(commands:list, window_sec:float=0.8): if not commands: return [] frames: list = [] current_frame: list = [] start_time: float = commands[0][0] for t, addr, cmd in commands: if t - start_time <= window_sec: current_frame.append((addr, cmd)) else: frames.append(current_frame) current_frame = [(addr, cmd)] start_time = t if current_frame: frames.append(current_frame) return frames
После группировки пакетов в кадры, преобразуем эти кадры в матрицы из 0 и 1.
def render_frame(frame:list, matr:list[list[int]], width:int, height:int) -> list[list[int]]: if len(matr) == 0: matrix: list[list[int]] = [ [ 0 for i in range(width) ] for j in range(height) ] else: matrix = matr for addr, state in frame: cell_idx: int = addr % (width * height) row: int = cell_idx // width col: int = cell_idx % width if row < height and col < width: matrix[row][col] = state return matrix
Ну и выводим кадры с задержкой 0.16 секунд.
matrix: list[list[int]] = [] for i, frame in enumerate(frames): os.system('cls' if os.name == 'nt' else 'clear') print(f"=== Кадр #{i+1} ({len(frame)} команд) ===") matrix = render_frame(frame, matrix, height=HEIGHT, width=WIDTH) print_matrix(matrix) time.sleep(FRAME_INTERVAL)
Запустим наш скрипт и поучим графический вывод флага, как это было у хакеров, только вместо здания у нас терминал :-)

После запишем наш флаг: TCTF{WIR3L3SS_BUT_N0T_T00_S3CUR3}
Послесловие
Мы прошли решение задачи шаг за шагом. Жду каких-либо дополнений, замечаний или вопросов в комментариях :-)

