β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3301

CARP HMAC key used raw β€” no KDF on SIOCSVH, stock ifconfig stores zero-padded ASCII passphrase as the SHA1-HMAC key

Summary

The kernel stores carpr_key verbatim (:2476) and uses it directly as the HMAC-SHA1 key material (carp_hmac_prepare, :519-527). The stock front-end never hashes the passphrase - ifcarp.c:110-111 carries the literal 'XXX Should hash the password into the key here, perhaps?' above strlcpy. OpenBSD and FreeBSD both derive carpr_key = SHA1(passphrase). Result: the effective key is a zero-padded ASCII string with passphrase entropy, and every CARP advertisement is an offline-verifiable HMAC oracle - an L2-adjacent attacker can dictionary/GPU-attack captured ads and forge advertisements (compounding DF-0301's missing replay protection and DF-0302's unsynchronized state machine into active failover hijack of the virtual IP). Static (Low; the DF-3298 PoC's carp_hmac() forges valid ads for a known key, verifying the construction). Fix: derive SHA1(passphrase) at the kernel boundary (or fix ifconfig). [VERIFIED pass2: reproduced cryptographically - 4 of 4 captured adverts authenticate under HMAC-SHA1 with the zero-padded ASCII passphrase as the raw key, no stretching anywhere; KDF recommendation documented]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3301 Β· 8 files
FileTypeDescriptionSize
NOTES.md β€” 1.8 KB ↓ raw
README.md β€” 908 B ↓ raw
VERDICT.md β€” 2.0 KB ↓ raw
carp.pcap β€” 368 B ↓ download
carp_verify.txt β€” 421 B view raw
live4.log β€” 386 B view raw
manifest.json β€” 845 B view raw
verdict.json β€” 1.6 KB view raw

DF-3301 -- verification pack

Method: Live PoC on the QEMU guest (stock INVARIANTS kernel) Status: REPRODUCED | impact: none | confidence: certain

What this is

CARP HMAC key = raw zero-padded ASCII passphrase, no KDF anywhere: four captured advertisements (vhid 1, pass test123) ALL authenticate under HMAC-SHA1 with key b"test123"+13x00 (construction recomputed independently from carp_hmac_prepare/generate). A user choosing a weak passphrase gets exactly its low-entropy bytes as a 20-byte HMAC key.

Build

cc -O -o <prog> <prog>.c   (on the guest)

Run

(driver: ifconfig carp0 ... pass test123 + tcpdump)

(success criterion: see VERDICT.md)

Evidence

carp_verify.txt (fresh capture): 4/4 packets match HMAC(zero-padded ASCII); live4.log tcpdump lines

Kernel references: sys/netinet/ip_carp.c:2476-2538, sys/netinet/ip_carp.c:504-554, sys/netinet/ip_carp.c:556-575

VERDICT.md
↓ download raw

DF-3301 -- VERDICT

REPRODUCED (impact=none, confidence=certain) Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Summary

CARP HMAC key = raw zero-padded ASCII passphrase, no KDF anywhere: four captured advertisements (vhid 1, pass test123) ALL authenticate under HMAC-SHA1 with key b"test123"+13x00 (construction recomputed independently from carp_hmac_prepare/generate). A user choosing a weak passphrase gets exactly its low-entropy bytes as a 20-byte HMAC key.

How it was verified

  • Method: Live PoC on the QEMU guest (stock INVARIANTS kernel)
  • Kernel references: sys/netinet/ip_carp.c:2476-2538, sys/netinet/ip_carp.c:504-554, sys/netinet/ip_carp.c:556-575
  • Evidence: carp_verify.txt (fresh capture): 4/4 packets match HMAC(zero-padded ASCII); live4.log tcpdump lines
  • Reachability: local-unpriv where noted in the summary; root-config for tun/lagg/carp/ipfw3/gre items; remote-facing for the packet parsers (wlan harnesses model the RX/TX path verbatim because the guest has no 802.11 hardware; precedent DF-0393/DF-0594/DF-0621/DF-0350).
  • Privesc assessment: no uid0 chain exists for any finding in this batch -- the memory-safety items are bounded info reads (kernleak bucket) or fault-injection-gated NULL derefs; nothing yields a write primitive or control over privileged state. The one panic-class live item (DF-3414) is root-only (SIOCIFDESTROY).

Fix

fix_status: not_testable -- Fix would be a KDF (e.g. SHA1-stretch) in ifconfig/carp key setup - a userland+kernel compatibility change, out of scope for a guest A/B here.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

(No fix.diff for this item: documented recommendation only - see Fix above.)

DF-3301 β€” CARP HMAC key used raw (no KDF); ifconfig copies ASCII passphrase β€” STATIC ANALYSIS

Not guest-verified (Low severity); basis is source analysis.

Claim

The CARP HMAC treats carpr_key[20] as a ready-to-use HMAC key:

  • sys/netinet/ip_carp.c:2476 β€” bcopy(carpr->carpr_key, sc->sc_key, sizeof(sc->sc_key)) β€” stored and used verbatim (carp_hmac_prepare(), ip_carp.c:519-527).

The stock configuration front-end does NOT hash the passphrase:

  • sbin/ifconfig/ifcarp.c:95-111 β€” /* XXX Should hash the password into the key here, perhaps? */ strlcpy(carpr.carpr_key, val, CARP_KEY_LEN);

So the effective HMAC key is the zero-padded ASCII passphrase (e.g. "pocpass\0\0...\0"). OpenBSD and FreeBSD ifconfig both hash the passphrase with SHA-1 before handing it to the kernel (carpr_key = SHA1(passphrase)); DragonFly's comment shows the divergence is known but never fixed.

Impact

Any captured CARP advertisement (multicast 224.0.0.18, TTL 255, sent every advbase seconds) is an offline-verifiable HMAC guess oracle: an attacker can dictionary/brute-force the passphrase at full speed. Human-chosen passphrases routinely fall to GPU dictionaries. With the key recovered, the attacker can forge advertisements β€” combined with the known missing replay protection (DF-0301) and unsynchronized input state machine (DF-0302) this converts a passive position into active failover hijack (gratuitous-ARP-level traffic blackhole / MITM of the virtual IP).

Severity: Low (requires capture + offline attack and a weak passphrase; defense-in-depth), CWE-321/CWE-916-class.

Fix

Hash at the configuration boundary, as OpenBSD/FreeBSD do β€” either in ifconfig (SHA-1 of the passphrase into carpr_key), or better, in the kernel's SIOCSVH handler (derive sc_key = SHA1(carpr_key) when a new key is supplied) so every configuration path benefits.

Fix verification

not_testable

Fix would be a KDF (e.g. SHA1-stretch) in ifconfig/carp key setup - a userland+kernel compatibility change, out of scope for a guest A/B here.

per-fix-DF-3301

Confirmed kernel references

Detail

Evidence (decisive lines)

carp_verify.txt (fresh capture): 4/4 packets match HMAC(zero-padded ASCII); live4.log tcpdump lines

Verdict

CARP HMAC key = raw zero-padded ASCII passphrase, no KDF anywhere: four captured advertisements (vhid 1, pass test123) ALL authenticate under HMAC-SHA1 with key b"test123"+13x00 (construction recomputed independently from carp_hmac_prepare/generate). A user choosing a weak passphrase gets exactly its low-entropy bytes as a 20-byte HMAC key.