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)
PoC verification
Evidence pack
findings/poc/DF-3301 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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
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_testableFix 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.
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.
No comments yet.