🔍 CVE-2026-79981

6.5
CVSS Score
MEDIUM
2026-10-23
2026-10-23 20:17
✅ 완료

🇰🇷 한글 설명

Zephyr RTOS의 DNS 스텁 리졸버가 초기화 시 서버마다 하나의 UDP 소켓을 바인딩하고 쿼리 간 소스 포트를 고정해 사용합니다. 이로 인해 공격자는 16비트 트랜잭션 ID만 추측하면 되며, 응답의 출발지 주소도 검사하지 않아 위조 응답으로 DNS 결과를 조작하고 캐시에 악성 레코드를 남길 수 있습니다.

💡 쉬운 설명

기기가 인터넷 주소를 찾을 때 사용하는 DNS 질의의 출발 포트가 계속 같은 번호로 고정되어 있습니다. 공격자가 같은 네트워크에 있다면 가짜 응답을 대량으로 보내 기기를 엉뚱한 주소로 유도할 수 있습니다.

🇺🇸 원문 (English)

The DNS stub resolver in subsys/net/lib/dns/resolve.c binds one UDP socket per configured server when the resolver context is initialised (dns_resolve_init_locked() -> register_dispatcher() -> dns_dispatcher_register()), with the local port left at 0 so the stack picks an ephemeral port exactly once. dns_write() then sends every subsequent query from that same socket without re-binding, so the source port is constant for the lifetime of the resolver context while only the 16-bit transaction identifier (ctx->queries[i].id, drawn with sys_rand16_get()) varies per query. RFC 5452 section 9.2 requires both to vary; with a fixed port, an off-path attacker has to guess only the identifier. The stable port is cheap to learn. Any single observed query reveals it permanently, and it can also be found by probing the ephemeral UDP range: subsys/net/ip/connection.c answers unmatched unicast UDP with an ICMP port-unreachable, so the resolver's socket is the one port in that range that stays silent. Acceptance of a reply is decided solely by get_slot_by_id() matching the transaction identifier and a CRC-16 of the queried name — the reply's source address is never checked (dispatcher_cb() does ARG_UNUSED(addr)), so forged answers need not even be spoofed to appear to come from the configured server; they only need to reach the resolver's port. An attacker with UDP reachability to the device (same LAN, Wi-Fi or mesh segment, or a globally routable device address) can therefore flood answers for a predictable query name across the 16-bit identifier space during a query window and race the legitimate server. A win makes the application resolve an attacker-chosen address, and with CONFIG_DNS_RESOLVER_CACHE enabled the forged record is retained for its attacker-chosen TTL. The attack still requires winning that race, and applications that validate TLS certificates for the resolved endpoint are largely protected. The fix draws a fresh local port before each query to a server that has nothing outstanding: dns_randomize_source_port() unregisters the dispatcher, closes and reopens the socket, and re-registers it bound to port 0 so the system selects a new port, raising the per-query guessing space from roughly 16 to roughly 31 bits. Multicast DNS and LLMNR are excluded because their ports are protocol-fixed. The behaviour is controlled by CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT (default y).

📍 영향받는 시스템

Zephyr RTOS의 DNS 리졸버(subsys/net/lib/dns)를 사용하며 CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT가 비활성화되었거나 해당 수정이 없는 버전

⚔️ 공격 벡터

동일 LAN/Wi-Fi 등 UDP 도달 가능한 공격자가 고정 포트를 파악한 뒤 예측 가능한 질의 이름에 대해 16비트 ID 공간을 대상으로 가짜 DNS 응답을 쏟아부어 정상 서버와 경쟁(레이스)합니다.

🛡️ 대응 방법

Zephyr를 소스 포트 무작위화가 포함된 최신 버전으로 업데이트하고 CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT=y 설정을 유지하며, 가능하면 TLS 인증서 검증을 강제합니다.

🔧 검증 코드

첫 번째 결과에서 설정값이 y로 나오거나 두 번째 명령에서 dns_randomize_source_port 함수가 존재하면 수정이 적용된 것이고, 아무 결과도 없으면 설정 누락 또는 취약한 버전일 가능성이 높습니다.

Shell / Script
grep -rn 'CONFIG_DNS_RESOLVER_RANDOMIZE_SOURCE_PORT' prj.conf 2>/dev/null; grep -rn 'dns_randomize_source_port' $ZEPHYR_BASE/subsys/net/lib/dns/resolve.c 2>/dev/null

📊 CVSS Vector String

CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N

💻 영향받는 소프트웨어

IBM WebSphere Application Server