Remotely triggerable Denial of Service (#1249)

* header_encryption: require a full common header before decrypting

packet_header_decrypt() takes header_len from the decrypted magic and
only checked header_len <= packet_len.  For a packet of another
community (or a made-up one) the value is arbitrary; below 16 the
header_len - 16 argument to speck_ctr() wraps to a huge size_t and the
decryption reads and writes far past packet[].  One crafted UDP datagram
(or ~1 in 2^28 random ones per key) crashes any edge or supernode that
attempts header decryption; a supernode tries its federation key on
every non-plain header.  Require at least the 24-byte common header, as
the encrypt side already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* transform_cc20: decrypt only the ciphertext, not the IV length extra

transop_decode_cc20() passed in_len (iv + ciphertext) as the length of
the ciphertext that follows the iv, so cc20_crypt() read 16 bytes past
the input and wrote 16 past the output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HoneyBunnyQT
2026-10-08 11:28:41 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 4831375d6e
commit fdd969b9c7
2 changed files with 11 additions and 2 deletions
+10 -1
View File
@@ -44,6 +44,12 @@ int packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
uint32_t test_magic;
uint32_t checksum_high = 0;
// an encrypted header is at least the common part of the header, as
// packet_header_encrypt() makes it (which requires packet_len >= 24)
if(packet_len < 24) {
return 0;
}
// check for magic
// so, as a first step, decrypt last 4 bytes from where originally the community name would be
speck_ctr((uint8_t*)&test_magic, &packet[16], 4, packet, (speck_context_t*)ctx);
@@ -52,7 +58,10 @@ int packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
//extract header length (lower 2 bytes)
uint32_t header_len = test_magic - magic;
if(header_len <= packet_len) {
// header_len comes from the decrypted magic: for a packet of another
// community or a made-up one it can be anything, and below 24 the
// header_len - 16 below wraps, running the decryption far past packet[]
if((header_len >= 24) && (header_len <= packet_len)) {
// decrypt the complete header
speck_ctr(&packet[16], &packet[16], header_len - 16, packet, (speck_context_t*)ctx);
+1 -1
View File
@@ -117,7 +117,7 @@ static int transop_decode_cc20 (n2n_trans_op_t *arg,
cc20_crypt(outbuf,
inbuf + CC20_PREAMBLE_SIZE,
in_len,
len, /* cipher text length, without the iv in front */
inbuf, /* iv */
priv->ctx);
} else