Как я проводил обратную разработку таинственного UDP-трафика в гостиничном номере

в 9:15, , рубрики: python, upd, Блог компании Productivity Inside, обратная разработка, Программирование
Всем привет! Я на какое-то время поселился в гостинице. Гостиница из современных, с умными телевизорами и всякими другими подключенными устройствами. Меня одолело любопытство, и я открыл Wireshark, как сделал бы на моем месте любой любитель покопаться в технике.

Я был очень удивлен, когда увидел большое количество UDP-трафика на порте 2046. Взглянул на него, но много толку это не дало – порт оказался не из стандартных, так что разбираться предстояло вручную.

Сначала я заподозрил, что эти данные нужны для стриминга телепередач на телевизоры, но размер пакета выглядел мелковатым, даже для единичного видеофрейма.

UDP-пакеты приходили не на мой IP, и я не проводил ARP-спуфинг, соответственно, эти пакеты рассылались всем. Изучив их повнимательнее, я установил, что это пакеты Multicast. По сути, это значит, что пакеты отправляются однократно и одновременно приходят на несколько устройств. Я заметил и еще кое-что: все пакеты были одинакового размера (634 байта).

Я решил написать скрипт для извлечения и анализа этих данных на Python. Начнем с кода, с помощью которого я стал принимать пакеты Multicast. В нижеприведенном фрагменте 234.0.0.2 – это IP, который я получил на Wireshark.

import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 2046))

mreq = struct.pack("4sl", socket.inet_aton("234.0.0.2"), socket.INADDR_ANY)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

while True:
    data = s.recv(2048)
    print(data)

Дополнительно я использовал binascii, чтобы конвертировать всё это в hex и облегчить себе процесс чтения байтов. Пронаблюдав, как тысячи пакетов сменяют друг друга на моей коносли, я заметил, что первые 15 байтов или около того у всех одинаковы. Эти байты, вероятно, указывали на протокол и ID пакета/команды, но так как мне приходило всё одно и то же, я не сумел ничего расследовать в этом плане.

Стыдно признаться, сколько времени мне потребовалось, чтобы заметить цепочку символов LAME3.91UUUUUUU в конце каждого пакета. Я заподозрил, что это аудиоданные, сжатые MPEG, но, когда для пробы сохранил один пакет как test.mp3, мультиплеер не смог его проиграть, а утилита file определила его только как test.mp3: data. То, что в пакете имеются данные, было и так очевидно, а если бы они представляли собой аудио MPEG, file должна была бы их узнать.

Поэтому я решил написать еще один скрипт на Python, который сохранял бы данные из пакетов со смещением. То есть файл test1 он должен был сохранить, пропустив один байт из пакета, файл test2 – пропустив два байта и так далее. Вот какой я использовал код и вот что из этого получилось:


data = s.recv(2048)
for i in range(25):
    open("test{}".format(i), "wb+").write(data[i:])

После этого я запустил file test* и вуаля! Теперь мы знаем, что, чтобы добраться до данных аудио MPEG, нужно пропустить восемь байтов:

$ file test*
test0:    data
test1:    UNIF v-16624417 format NES ROM image
test10:   UNIF v-763093498 format NES ROM image
test11:   UNIF v-1093499874 format NES ROM image
test12:   data
test13:   TTComp archive, binary, 4K dictionary
test14:   data
test15:   data
test16:   UNIF v-1939734368 format NES ROM image
test17:   UNIF v-1198759424 format NES ROM image
test18:   UNIF v-256340894 format NES ROM image
test19:   UNIF v-839862132 format NES ROM image
test2:    UNIF v-67173804 format NES ROM image
test20:   data
test21:   data
test22:   data
test23:   DOS executable (COM, 0x8C-variant)
test24:   COM executable for DOS
test3:    UNIF v-1325662462 format NES ROM image
test4:    data
test5:    data
test6:    data
test7:    data
test8:    MPEG ADTS, layer III, v1, 192 kbps, 44.1 kHz, JntStereo
test9:    UNIF v-2078407168 format NES ROM image
while True:
    data = s.recv(2048)
    sys.stdout.buffer.write(data[8:])

Дальше нам нужно просто непрерывно читать пакеты один за другим, пропуская в каждом по восемь байтов, и тогда всё отлично воспроизведется.

Что же кроется в этом аудио? Следы коварно спрятанного жучка, который подслушивает за мной? Что-то имеющее отношение к умному телевизору в моем номере? Что-то связанное с работой гостиничных систем? Есть только один способ узнать.

$ python3 listen_2046.py > test.mp3
* wait a little to get a recording *
^C

$ mplayer test.mp3
MPlayer (C) 2000-2016 MPlayer Team
224 audio & 451 video codecs

Playing test.mp3.
libavformat version 57.25.100 (external)
Audio only file format detected.
=====
Starting playback...
A:   3.9 (03.8) of 13.0 (13.0)  0.7%

Что за чертовщина? И на это я тратил своё время? Это музыка вызова лифта, её играют в коридорах возле лифтов. Ну ладно, зато теперь я могу слушать ее и у себя в номере.

Автор: Productivity Inside

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js