[Перевод] Как я проводил обратную разработку таинственного UDP-трафика в гостиничном номере
Всем привет! Я на какое-то время поселился в гостинице. Гостиница из современных, с умными телевизорами и всякими другими подключенными устройствами. Меня одолело любопытство, и я открыл 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%
Что за чертовщина? И на это я тратил своё время? Это музыка вызова лифта, её играют в коридорах возле лифтов. Ну ладно, зато теперь я могу слушать ее и у себя в номере.