hostap association granted without completed authentication (assoc gate tests node-table existence, and a single auth REQUEST creates the node)
Summary
The ASSOC_REQ handler's only 'not authenticated' gate is 'if (ni == vap->iv_bss)' - i.e. node-table existence. But hostap_auth_shared() creates the node via ieee80211_dup_bss() upon a single seq-1 REQUEST, before the exchange completes, and nothing down to ieee80211_node_join() checks that auth finished. One 30-byte auth REQUEST + one ASSOC_REQ = associated station with AUTHORIZED=0. VERIFIED on stock kernel: control (no node) correctly gets DEAUTH (0xc0); after a lone REQUEST the AP sends ASSOC_RESP (0x10) and assigns associd 0xc001. Found while validating the DF-3323 fix - the patched kernel refused to authorize the station but still handed it an association. Impact: AID-space exhaustion (128 entries, 2 frames per fake station = remote assoc-flood DoS), list-sta presence, power-save eligibility, and EAPOL/PAE pass-through for a fully unauthenticated station. Same predicate exists upstream in FreeBSD. Fix validated (deny assoc when ni==iv_bss OR (authmode SHARED/AUTO and not authorized); 802.1x/WPA untouched): baseline grant replaced by DEAUTH, open-auth regression still associates.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3326 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fw4.c | β | 16.5 KB | view raw | |
| Makefile | β | 144 B | β download | |
| build.sh | β | 87 B | view raw | |
| run.sh | β | 111 B | view raw | |
| build.log | β | 5.6 KB | view raw | |
| run.log | β | 1.5 KB | view raw | |
| fix.log | β | 2.2 KB | view raw | |
| fixcheck.sh | β | 1.6 KB | view raw | |
| fix.diff | β | 925 B | view raw | |
| env.txt | β | 198 B | view raw | |
| README.md | β | 2.3 KB | β raw | |
| VERDICT.md | β | 3.6 KB | β raw | |
| verdict.json | β | 2.9 KB | view raw |
DF-3326 β hostap association granted without completed authentication
File: sys/netproto/802_11/wlan/ieee80211_hostap.c
Severity: Medium Β· CWE-287/863 Β· confidence: certain Β· REPRODUCED on the stock guest kernel
What
The ASSOC_REQ handler's only authentication gate is node-table existence:
if (ni == vap->iv_bss) { /* ieee80211_hostap.c:1953 */
... deny "sta not authenticated" (DEAUTH, ASSOC_NOT_AUTHED)
}
But a node-table entry is created by a single shared-key auth REQUEST
(hostap_auth_shared() :1072-1083 ieee80211_dup_bss()) β before the
exchange ever completes. So on a shared-key (or auto) AP:
AUTH(shared, seq=1) # 30 bytes; AP replies with the challenge ASSOC_REQ # never sent the seq-3 response at all => ASSOC_RESP, AID assigned # associated, AUTHORIZED=0
802.11-2016 11.3 requires authentication before association. Impact: AID
assignment + list sta entry + power-save queue eligibility + EAPOL (PAE)
pass-through for an unauthenticated station; repeated with distinct MACs it
exhausts the 128-entry AID space (cheap remote association-flood DoS).
(Discovered while validating the DF-3323 fix β the patched kernel refused to
authorize the station but still handed it an association.)
How to reproduce
sh findings/poc/DF-3326/build.sh sh findings/poc/DF-3326/run.sh
Success criterion (run.log):
control: fw4.attack=4 with no node -> AP TX MGMT subtype 0xc0 (DEAUTH) [correct]
attack: fw4.attack=1 (request only) -> node AUTHORIZED=0
fw4.attack=4 -> AP TX MGMT subtype 0x10 (ASSOC_RESP)
associd 0xc001 AUTHORIZED=0 [bug]
Fix validation
fix.diff widens the gate: deny association when ni == iv_bss or
(ni_authmode β {SHARED, AUTO} and the port is not authorized) β those
authmodes complete authentication at the 802.11 layer, so authorized ==
authenticated; 802.1x/WPA legitimately defer auth until after association.
Validated on the rebuilt kernel (#1 21:29, both DF-3323+DF-3326 fixes):
attack=1 β attack=4 now yields DEAUTH (0xc0) and associd 0x0; the
regression leg (open-authmode vap: open auth attack=6 β AUTHORIZED=1 β
assoc) still gets associd 0xc001. See fix.log.
DF-3326 β VERDICT
Status: reproduced (baseline, stock INVARIANTS kernel #0 Thu Jul 2 06:02:54 UTC 2026) Β· impact: association (AID, power-save, EAPOL pass-through, assoc-flood DoS) granted without any completed authentication Β· fix: validated (kernel #1 21:29 with DF-3323+DF-3326 fixes).
Root cause (path:line)
sys/netproto/802_11/wlan/ieee80211_hostap.c:1953-1962β the ASSOC_REQ "not authenticated" gate tests onlyni == vap->iv_bss(node-table existence).sys/netproto/802_11/wlan/ieee80211_hostap.c:1072-1083βhostap_auth_shared()creates the node (ieee80211_dup_bss) upon a seq-1 REQUEST, i.e. before the shared-key exchange completes (or fails).hostap_auth_open()does the same at:947-950(harmless there: open auth is by definition complete on request).- Nothing between node creation and
ieee80211_node_join()(:2169, node.c:2524) checks that authentication completed. For shared-key modeieee80211_node_is_authorized()is only set by a successful seq-3 (:1149) β which the assoc path never consults.
The same shape exists for AUTH_AUTO (hostap_auth_shared accepts AUTO
nodes at :1023-1024). For 802.1x/WPA, association-before-auth is the
designed flow (auth deferred to EAPOL/4-way), so the correct predicate is
authmode-dependent (see fix).
Reproduction (fw4 software radio, guest stock kernel)
- Control:
fw4_attack=4with no node in the table β AP transmits DEAUTH (subtype 0xc0) β the intended "not authenticated" refusal exists in the code and is reached whenni == iv_bss. - Attack:
fw4_attack=1β one 30-byte AUTH(shared, seq1) REQUEST; node created,AUTHORIZED=0.fw4_attack=4β ASSOC_REQ; AP transmits ASSOC_RESP (subtype 0x10), node gainsassocid 0xc001whileAUTHORIZED=0;ifconfig wlan0 list stashows AID 1 with noAflag (compare DF-3323 baseline: authorized bypass showsA). - Found while validating the DF-3323 fix: on the DF-3323-patched kernel
the cleartext seq-3 was correctly dropped, yet the follow-on ASSOC_REQ
still returned
associd 0xc001β a fully independent second bypass.
Impact
- Unauthenticated station occupies the AID space (default
iv_max_aid128): 2 frames per fake station β cheap remote association-flood DoS until the inactivity timer reaps them. - Appears associated to userland (
list sta), eligible for the power-save queue, and β because the data path's unauthorized-port filter passes PAE frames (:776) β can inject EAPOL into the AP's network stack / bridge. - Not authorized: non-PAE data still blocked at
:767(and by DROPUNENC when set) β this is the complement of DF-3323, which gained authorization itself.
Fix validation (kernel #1 21:29, DF-3323+DF-3326 fixes applied)
fix.diff widens the gate to
ni == vap->iv_bss || ((ni_authmode == SHARED || AUTO) && !authorized).
- baseline: attack=1 β attack=4 = ASSOC_RESP (0x10), associd 0xc001.
- patched: attack=1 β attack=4 = DEAUTH (0xc0), associd stays 0x0.
- regression: open-authmode vap, open auth (attack=6) β AUTHORIZED=1 β ASSOC_REQ β associd 0xc001 (legit flow unbroken). 802.1x/WPA vap types are untouched by the predicate (auth deferred by design).
fix_baseline_reproduced=1, fix_patched_reproduced=0 β fix_status=fixed.
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.
Fix verification
fixedmake -j6 nativekernel rc=0 with DF-3326 fix.diff (+DF-3323 fix); baseline assoc grant (0x10 + associd 0xc001) is gone: DEAUTH 0xc0, associd 0x0; regression: open-auth vap authorizes + associates normally (0xc001).
findings/poc/DF-3326/fix.log (kernel #1 21:29, both fixes)
Confirmed kernel references
Detail
Exploit chain
1) inject AUTH shared seq1 (node created, not authorized); 2) inject ASSOC_REQ -> ASSOC_RESP + AID; 3) repeat with distinct source MACs to exhaust the 128-entry AID space (remote assoc-flood DoS) or hold assoc state + EAPOL passthrough
Evidence (decisive lines)
run.log: control 'AP TX MGMT subtype 0xc0' (DEAUTH, correct), attack 'AP TX MGMT subtype 0x10' (ASSOC_RESP) + 'associd 0xc001 ... AUTHORIZED=0'; fix.log: patched = 0xc0 + associd 0x0; regression open-auth assoc still 0xc001
PoC changes
same fw4 harness as DF-3323; fw4.c extended with generic mgmt-subtype TX capture (0xc0/0x10 distinction), attack=4 fallback to iv_bss for the no-node control, attack=6 open-auth regression leg
Verified recommended fix
Widen the assoc gate: deny when ni==iv_bss OR (ni_authmode in {SHARED, AUTO} AND port not authorized); see fix.diff
Verdict
hostap_recv_mgmt's ASSOC_REQ gate (:1953) tests only ni == iv_bss, but hostap_auth_shared creates the node on a single auth REQUEST (:1072 dup_bss) before the exchange completes. One 30-byte REQUEST + one ASSOC_REQ = associated station (associd 0xc001) with AUTHORIZED=0, reproduced on the stock kernel; the no-node control correctly gets DEAUTH (0xc0). Found while validating the DF-3323 fix, where the patched kernel still handed out the association.
No comments yet.