scapy
scapy copied to clipboard
NTP Authenticator still broken
Brief description
Issue #2731 does not seem to be fixed.
Environment
- Scapy version:
2.4.4.
- Python version:
3.8.0
- Operating System:
Windows
How to reproduce
Use NTP packet capture with NTP Version 4 packets using SHA1, SHA256, SHA512 message authentication (produced by chrony or ntpd NTP server.) Use show() command to parse packet.
Actual result
###[ UDP ]###
sport= ntp
dport= ntp
len= 80
chksum= 0xdb3b
###[ NTPHeader ]###
leap= unknown (clock unsynchronized)
version= 4
mode= client
stratum= 0
poll= 6
precision= 232
delay= 0.0
dispersion= 0.0
ref_id= b'INIT'
ref= 0.0
orig= 0.0
recv= 0.0
sent= Tue, 02 Jun 2020 23:37:12 +0000
###[ Authenticator ]###
padding= '\x00\x00\x00\x0c'
key_id= 3523582088
dgst= b4a2adc11d2dbd1420a43560bf92c6f9
Expected result
###[ UDP ]###
sport= ntp
dport= ntp
len= 80
chksum= 0xdb3b
###[ NTPHeader ]###
leap= unknown (clock unsynchronized)
version= 4
mode= client
stratum= 0
poll= 6
precision= 232
delay= 0.0
dispersion= 0.0
ref_id= b'INIT'
ref= 0.0
orig= 0.0
recv= 0.0
sent= Tue, 02 Jun 2020 23:37:12 +0000
###[ Authenticator ]###
padding= '\x00\x00\x00'
key_id= 12
dgst= d2059888b4a2adc11d2dbd1420a43560bf92c6f9
key ID was included into the padding and portion of digest was incorrectly identified as key id.
Related resources
Capture uploaded issues2999.pcap.gz
I'm pretty sure this is AutoKey (https://tools.ietf.org/html/rfc5906#section-10) and that we don't support it. Feel free to contribute
No it is definitely not autokey. See linked issue.
Alright, could you find an NTP RFC that mentions a Message Digest that is not 128bits, therefore matches this issue ? Thanks
Maybe this one https://www.rfc-editor.org/errata/eid3627 ? I mean those packets are created by widely-used NTP server/client implementations, are being parsed correctly by Wireshark. And no, this is not Autokey.
I ran into the same problem as @Olegandr and hacked it like this:
diff --git a/scapy/layers/ntp.py b/scapy/layers/ntp.py
index 53743f9a..68cacafb 100644
--- a/scapy/layers/ntp.py
+++ b/scapy/layers/ntp.py
@@ -239,9 +239,9 @@ class NTPAuthenticator(Packet):
name = "Authenticator"
fields_desc = [
- _NTPAuthenticatorPaddingField("padding", ""),
+ #_NTPAuthenticatorPaddingField("padding", ""),
IntField("key_id", 0),
- XStrFixedLenField("dgst", "", length_from=lambda x: 16)
+ XStrFixedLenField("dgst", "", length_from=lambda x: 20)
]
def extract_padding(self, s):
The root cause is that Scapy doesn't handle properly anything other than MD5 (128 bits/16 bytes). The RFC uses MD5 as an example, but other algorithms are allowed. In my case, I was using SHA-1 which results in a 20-byte message digest.
Here's what Scapy's representation of my packet looked like without the hack (incorrect from NTPAuthenticator onwards):
<Ether dst=xx:xx:xx:xx:xx:xx src=xx:xx:xx:xx:xx:xx type=IPv4 |<IP version=4 ihl=5 tos=0xb8 len=100 id=16730 flags=DF frag=0 ttl=64 proto=udp chksum=0x65b1 src=192.168.8.228 dst=192.168.8.145 |<UDP sport=ntp dport=ntp len=80 chksum=0xc545 |<NTPHeader leap=unknown (clock unsynchronized) version=4 mode=client stratum=0 poll=6 precision=237 delay=0 dispersion=0 ref_id='INIT' ref=0 orig=0 recv=0 sent=Wed, 12 Jan 2022 03:12:22 +0000 |<NTPAuthenticator padding='\x00\x00\x00\x0b' key_id=1285752564 dgst=16dca620855921cffc11cee2da29a3ae |>>>>>
And here's what it looked like with the hack (correct):
<Ether dst=xx:xx:xx:xx:xx:xx src=xx:xx:xx:xx:xx:xx type=IPv4 |<IP version=4 ihl=5 tos=0xb8 len=100 id=16730 flags=DF frag=0 ttl=64 proto=udp chksum=0x65b1 src=192.168.8.228 dst=192.168.8.145 |<UDP sport=ntp dport=ntp len=80 chksum=0xc545 |<NTPHeader leap=unknown (clock unsynchronized) version=4 mode=client stratum=0 poll=6 precision=237 delay=0 dispersion=0 ref_id=b'INIT' ref=0 orig=0 recv=0 sent=Wed, 12 Jan 2022 03:12:22 +0000 |<NTPAuthenticator key_id=11 dgst=4ca306f416dca620855921cffc11cee2da29a3ae |>>>>>
Wireshark doesn't have this problem. The attached image, for example, shows Wireshark's representation of my packet above. The key_id that I'm using is indeed 11 (0xb), and the rest (20 bytes) is the message digest.
Unfortunately, I don't have time to look into this any further. I hacked the code just to be able to generate a correct graphical representation (with pdfdump()
) for a university report. I hope that the Scapy developers find this information helpful and fix this properly. I know there was a previous commit claiming to fix it (https://github.com/secdev/scapy/pull/2732/files#diff-585cfb5dec6341defbe2f6643ec31bd8f41b596acb295c9213ba8181fd18fc06). However, as @Olegandr has mentioned, the problem still exists.
Furthermore, I think that there needs to be some separation in Scapy between NTPv3 and NTPv4 packets. While both protocols are compatible with each other, they differ in the stuff at the end i.e. after the transmit timestamp. For example, in NTPv4 there is no padding before the key_id unless there is an Extension Field -- if I'm not mistaken. Thus, for NTPv4 packets, as soon as the code has read the transmit timestamp, the next 4 bytes are always the key_id, and the remaining bytes are the message digest. The Scapy code seems to start at the end and work backwards, hence throwing away useful bytes into what it thinks is padding.
FTR here are some information to help implementing this https://github.com/wireshark/wireshark/blob/eff7cd15b007bce10763253a131fa09d0e465206/epan/dissectors/packet-ntp.c#L1302
US government standard requires that NTP be authenticated using " SHA1, SHA256, SHA384, SHA512, AES-CBC-128, AES-CBC-256 as the message digest algorithm(s)". That is why support for those fields are requested.
@Olegandr do you have PCAP containing authenticators other than MD5 our SHA256?
@guedou, Here is a capture with all possible digests: alldigests2.zip Packets 1,2 SHA1 Packets 3,4 SHA256 Packets 5,6 SHA512 Packets7,8 SHA384, Packet 9 AES-CMAC 128 Packet 10 AES_CMAC 256 Sorry it took so long.
Thanks a lot. Sorry, I fail to provide an answer earlier while I was experimenting with these pcaps. #3821 parses them correctly yet introduces other issues. Can you tell me which NTP servers you used to generate them? All SHA* MAC seem to be 20 bytes long.
I was using chrony 4. afaik ntpd does not support AES-MAC.