From 1232bb30d0ed6333d90ee1f35a387885011ba236 Mon Sep 17 00:00:00 2001 From: ImanAfaneh293 Date: Mon, 29 Apr 2024 17:18:40 +0300 Subject: [PATCH 1/2] ipsec: Fix IPsec decrypt_esp for NAT-Traversal When having nat_header, encrypted.underlayer will return UDP/ESP, so when decrypting IPv6 packet, the decrypt packet will be return with nat_header (UDP), which will return a corrupted packet. Example: original packet: IPv6/TCP/Raw encrypted packet: IPv6/UDP/ESP Decrypted packet: IPv6/UDP/TCP/Raw Signed-off-by: Iman Afaneh --- scapy/layers/ipsec.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py index f8f52d9bf1c..0815cabdbbc 100644 --- a/scapy/layers/ipsec.py +++ b/scapy/layers/ipsec.py @@ -1191,8 +1191,13 @@ def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None): # recompute checksum ip_header = ip_header.__class__(raw(ip_header)) else: - encrypted.underlayer.nh = esp.nh - encrypted.underlayer.remove_payload() + if self.nat_t_header: + # drop the UDP header and return the payload untouched + ip_header.nh = esp.nh + ip_header.remove_payload() + else: + encrypted.underlayer.nh = esp.nh + encrypted.underlayer.remove_payload() ip_header.plen = len(ip_header.payload) + len(esp.data) cls = ip_header.guess_payload_class(esp.data) From 39218a17022ee715606a4ff9d2bd93fba863542b Mon Sep 17 00:00:00 2001 From: ImanAfaneh293 Date: Wed, 8 May 2024 09:57:27 +0300 Subject: [PATCH 2/2] ipsec.uts: add unit test for IPsec NAT-Traversal Signed-off-by: Iman Afaneh --- test/scapy/layers/ipsec.uts | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/scapy/layers/ipsec.uts b/test/scapy/layers/ipsec.uts index 7ccf0f2b2ef..0af1eefdc0b 100644 --- a/test/scapy/layers/ipsec.uts +++ b/test/scapy/layers/ipsec.uts @@ -3385,6 +3385,46 @@ d * after decryption the original packet payload should be unaltered assert d[TCP] == p[TCP] +############################################################################### += IPv6 / ESP - NAT-Traversal - Transport +~ -crypto + +import socket + +p = IPv6(src='11::22', dst='22::11') +p /= TCP(sport=3333, dport=55) +p /= Raw('testdata') +p = IPv6(raw(p)) +p + +sa = SecurityAssociation(ESP, spi=0x222, + crypt_algo='NULL', crypt_key=None, + auth_algo='NULL', auth_key=None, + nat_t_header=UDP(dport=5000)) + +e = sa.encrypt(p) +e + +assert isinstance(e, IPv6) +assert e.src == '11::22' and e.dst == '22::11' +assert e.chksum != p.chksum +* the encrypted packet should have an UDP layer +assert e.nh == socket.IPPROTO_UDP +assert e.haslayer(UDP) +assert e[UDP].sport == 4500 +assert e[UDP].dport == 5000 +assert e[UDP].chksum == 0 +assert e.haslayer(ESP) +assert not e.haslayer(TCP) +assert e[ESP].spi == sa.spi + +d = sa.decrypt(e) +d + +* after decryption the original packet payload should be unaltered +assert d[TCP] == p[TCP] +assert not d.haslayer(UDP) +assert d[Raw] == p[Raw] ############################################################################### + IPv6 / ESP