Заставить scapy повторно анализировать слой после изменений
Я работаю с вилкой scapy (инструмент для манипулирования пакетами Python) под названием scapy-com. Это реализует разбор / манипулирование 802.15.4 и Zigbee, среди других протоколов.
Изюминка протокола Zigbee находится в заголовке безопасности сетевого уровня. Первоначально уровень безопасности (который определяет шифрование и длину кода целостности сообщения) устанавливается правильно, но затем устанавливается в 0 (без шифрования) перед его отправкой. Из спецификации:
Подполе уровня безопасности поля управления безопасностью должно быть перезаписано 3-битной строкой со всеми нулями '000'
Спецификацию можно найти здесь. Соответствующий раздел - "4.3.1.1 Обработка безопасности исходящих кадров".
Это означает, что перехваты пакетов указывают на то, что не используется ни код шифрования, ни код целостности сообщения. Уровень безопасности должен передаваться вне диапазона.
scapy-com с этим не справляется. Он наивно анализирует уровень безопасности и устанавливает длину MIC равной 0. Код, который делает это:
def util_mic_len(pkt):
''' Calculate the length of the attribute value field '''
# NWK security level 0 seems to implicitly be same as 5
if ( pkt.nwk_seclevel == 0 ): # no encryption, no mic
return 0
elif ( pkt.nwk_seclevel == 1 ): # MIC-32
return 4
elif ( pkt.nwk_seclevel == 2 ): # MIC-64
return 8
elif ( pkt.nwk_seclevel == 3 ): # MIC-128
return 16
elif ( pkt.nwk_seclevel == 4 ): # ENC
return 0
elif ( pkt.nwk_seclevel == 5 ): # ENC-MIC-32
return 4
elif ( pkt.nwk_seclevel == 6 ): # ENC-MIC-64
return 8
elif ( pkt.nwk_seclevel == 7 ): # ENC-MIC-128
return 16
else:
return 0
Проект, который использует scapy-com, пытается справиться с этим, установив уровень безопасности на 5:
#TODO: Investigate and issue a different fix:
# https://code.google.com/p/killerbee/issues/detail?id=30
# This function destroys the packet, therefore work on a copy - @cutaway
pkt = pkt.copy() #this is hack to fix the below line
pkt.nwk_seclevel=5 #the issue appears to be when this is set
mic = pkt.mic
Однако это не работает - код целостности сообщения уже установлен. Я работал над этим, просто изменив функцию util_mic_len для правильной установки длины микрофона.
Вопрос в том, как следует изменить синтаксический анализатор Zigbee, чтобы изменение nwk_seclevel после первоначального вскрытия приводило к обновлению длины микрофона?
Я вижу два решения:
- Измените код scapy-com так, чтобы изменение nwk_seclevel автоматически изменяло длину микрофона.
- Повторно рассмотрите пакеты снаружи scapy-com, когда они будут изменены.
Проблема с 1 - я понятия не имею, как это сделать.
Проблема с 2 заключается в том, что у меня есть идея, но я не могу заставить ее работать - я не могу понять, как вызвать анализ на пакет после его загрузки. Вызов pkt.dissect (pkt) не работает и выглядит странно.
Какое лучшее или рекомендуемое решение здесь?
2 ответа
Исправление звуков scapy правильное решение. scapy-com довольно старый. Специфичный для Zigbee код в scapy-com - это 1244 строки кода, которые в значительной степени являются перечислениями и списками полей. Таким образом, не должно быть слишком сложно перенести его на scapy-python3. Если бы вы помогли перенести его на scapy-python3 http://github.com/phaethon/scapy, я мог бы помочь решить проблему.
Проект, на который вы ссылаетесь, это KillerBee, и у меня была именно эта проблема с расшифровкой. Я просто "исправил" код таким образом:
from struct import pack
f = pkt.getlayer(ZigbeeSecurityHeader).fields
pkt.nwk_seclevel = 5
nwk_mic = pkt.mic
nwk_encrypted = f['data'][:-6]
ext_source = f['ext_source']
nwk_sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0]
nwk_nonce = struct.pack('Q',ext_source) + struct.pack('I',f['fc']) + nwk_sec_ctrl_byte
nwk_crop_size = 4 + 2 + len(pkt.getlayer(ZigbeeSecurityHeader).fields['data']) # The length of the encrypted data, mic and FCS
# the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later
zigbeeData = pkt.getlayer(ZigbeeNWK).do_build()
zigbeeData = zigbeeData[:-nwk_crop_size]
(nwk_payload, nwk_micCheck) = zigbee_crypt.decrypt_ccm(nkey, nwk_nonce, nwk_mic, nwk_encrypted, zigbeeData)