CVE-2026-53266 (Linux 커널 ebtables SNAT 범위 밖 쓰기) 분석
분류: CVE · 시스템·커널 · 범위 밖 쓰기(OOB Write) · CVE-2026-53266 · [표준]
Linux 커널에서 “이 패킷을 읽어도 안전하다”와 “이 패킷에 써도 안전하다”는 서로 다른 보증입니다. 브리지 방화벽(ebtables)의 출발지 MAC 변환(SNAT) 기능은 이더넷 헤더를 고칠 때는 쓰기 가능 여부를 확인했지만, 옵션으로 함께 고치는 ARP 본문 6바이트에는 같은 확인을 하지 않았습니다. 그 6바이트가 하필 파일에서 빌려 온 메모리 페이지 위에 놓여 있으면, 커널은 패킷이 아니라 그 페이지에 직접 값을 써 버립니다.
개요
CVE-2026-53266은 Linux 커널 netfilter 브리지 계층의 ebtables SNAT 타깃(net/bridge/netfilter/ebt_snat.c)에 있는 메모리 쓰기 결함입니다. SNAT 타깃은 브리지를 지나는 프레임의 출발지 MAC 주소를 바꾸는데, 프레임이 ARP(주소 결정 프로토콜)일 때는 ARP 본문 안의 송신자 하드웨어 주소(SHA, sender hardware address) 도 같은 값으로 맞춰 줍니다. 이 두 번째 쓰기가 “쓰기 가능”이 보장되지 않은 영역에 그대로 수행됩니다. 해당 영역이 비선형 소켓 버퍼(nonlinear skb)의 조각(fragment)이고 그 조각이 splice로 들여온 파일 페이지라면, MAC 값 6바이트가 그 페이지에 직접 기록됩니다. 이 서술은 패치 커밋 메시지가 밝히는 내용입니다(리서치 재료 기준).
이 취약점은 원격·무인증 취약점이 아닙니다. 공격자는 로컬 저권한 계정을 갖고 있어야 하고, 브리지 ebtables SNAT의 ARP 재작성 경로를 구성·유발할 수 있어야 합니다.
- CWE: CWE-787(범위 밖 쓰기). CWE-119도 함께 표기됩니다(OpenCVE 기준). ⚠️미확인(팩트체크 대상) — NVD 원본 대조 필요. OpenCVE에는 CWE-243(chroot 관련)도 올라 있으나 이 결함과 무관한 데이터 오류로 보여 이 글은 채택하지 않습니다.
- CVSS: 3.1 기준 8.8 (High), 벡터
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H. ⚠️미확인(팩트체크 대상) — 집계 사이트(OpenCVE) 기준입니다. NVD 페이지는 리서치 단계에서 로드되지 않아, NVD와 커널 CNA가 같은 벡터를 매겼는지 확인되지 않았습니다. 한 집계 사이트는 “로컬 또는 인접”이라고 요약했지만, 벡터상 값은 로컬(AV:L)이므로 “인접”은 채택하지 않습니다. - 영향 범위 시작점: 패치의
Fixes:태그는 커밋63137bc5882a(브리지 NAT에서 작은 패킷이 버려지던 문제의 수정, 5.10 무렵)를 가리킵니다. ⚠️미확인(팩트체크 대상) — ARP SHA 재작성 코드 자체는 그보다 오래됐고, CVE 레코드가 5.10을 실질 시작점으로 잡은 것인지는 커널 CVE 공지 원본 대조가 필요합니다. - 수정 버전: 메인라인 7.1(커밋
67ba971ae02514d85818fe0c32549ab4bfa3bf49), stable 5.10.259 / 5.15.210 / 6.1.176 / 6.6.143 / 6.12.94 / 6.18.36 / 7.0.13. ⚠️미확인(팩트체크 대상) — 상세는 아래 대응방안의 표를 보십시오. - 보고·수정: 보고자 Yiming Qian, 서명 Florian Westphal·Pablo Neira Ayuso(패치 커밋 트레일러, 리서치 재료 기준).
- 공개일: 2026-06-25(Ubuntu 보안 페이지, 리서치 재료 기준). ⚠️미확인
- 악용 현황: 미확인 — 어느 쪽도 단정하지 않습니다. 여러 집계 사이트가 “2026-09-18 CISA KEV(알려진 악용 취약점 목록) 등재”를 전하고, 이 초안에 주입된 공개 excerpt의 문구 형식도 KEV 카탈로그의 표기 관행과 닮았습니다. 그러나 리서치 단계에서 CISA 공식 카탈로그 원본으로는 확증되지 않았고, 해당 집계 사이트들은 같은 오류를 서로 되풀이했을 가능성이 있습니다. 팩트체커가 CISA KEV 공식 카탈로그(JSON)를 직접 조회해 등재 여부·등재일을 확정해야 합니다.
한 줄 요약: 헤더를 “읽을 수 있게” 해 주는 함수는 그 자리를 “써도 되게” 만들어 주지 않습니다. 패치는 ARP 재작성 직전에 쓰기 가능 확인 한 번을 추가했습니다.
기술 배경 — 소켓 버퍼의 선형·비선형 영역과 “빌려 온 페이지”
Linux 커널은 네트워크 패킷을 소켓 버퍼(sk_buff, 줄여서 skb)라는 구조로 다룹니다. skb의 데이터는 두 곳에 나뉘어 있을 수 있습니다.
- 선형(linear) 영역: skb가 직접 소유한 연속 메모리. 헤더는 대개 여기 있습니다.
- 비선형(nonlinear) 영역: 별도 메모리 페이지를 가리키는 조각(frag)들의 목록. 큰 데이터를 복사 없이 매달 때 씁니다.
문제는 조각이 가리키는 페이지가 skb의 것이 아닐 수 있다는 점입니다. splice·sendfile 같은 무복사(zero-copy) 경로는 파일의 페이지 캐시(page cache, 디스크 파일 내용을 메모리에 올려 둔 공유 사본)를 복사하지 않고 그대로 조각으로 매답니다. 이 페이지는 “읽어서 내보내라”고 빌려준 것이지, 네트워크 코드가 고쳐 써도 되는 메모리가 아닙니다.
그래서 커널에는 역할이 다른 두 도구가 있습니다(아래 설명은 커널 일반 지식 기준이며, 팩트체커는 해당 SHA의 net/core/skbuff.c로 대조할 수 있습니다).
skb_header_pointer()— 헤더를 안전하게 읽기 위한 도구입니다. 데이터가 선형 영역에 있으면 그 포인터를, 조각에 걸쳐 있으면 스택 임시 버퍼에 복사한 사본을 돌려줍니다. skb 자체는 바꾸지 않습니다.skb_ensure_writable(skb, len)— 앞쪽len바이트를 안전하게 쓰기 위한 도구입니다. 그 범위를 선형 영역으로 끌어오고(pull), 버퍼가 다른 곳과 공유 중이면 사본을 만들어 단독 소유로 바꿉니다.
반면 skb_store_bits()는 주어진 오프셋에 바이트를 써 넣는 저수준 함수입니다. 대상이 조각이면 그 조각의 페이지를 매핑해 거기에 직접 복사합니다. 그 페이지가 누구 것인지는 묻지 않습니다. 확인은 호출자의 몫입니다.
CVE 분석 요약 — 어느 코드가 원인인가
- 취약 파일:
net/bridge/netfilter/ebt_snat.c(Linux 커널, GPL-2.0). - 취약 함수: SNAT 타깃 함수
ebt_snat_tg. ⚠️미확인(팩트체크 대상) — 심볼명은 리서치 재료가 “불확실”로 표시했습니다. 수정 SHA의 원본에서 확인이 필요합니다. - 취약 상태 고정 SHA: 패치 커밋의 부모
3027ecbdb5fdf9200251c21d4818e4c447ef78e1. ⚠️미확인 — 리서치 재료가 GitHub 미러의 부모 표시로 얻은 값입니다. - 라인번호: 미확인. 리서치 재료에 라인 정보가 없어 이 초안은 라인번호를 적지 않습니다. 발행용 코드 그림은 위 부모 SHA의 실제 소스에서 렌더해야 합니다.
흐름은 세 걸음입니다.
1) 이더넷 헤더 쓰기는 보호됩니다. 함수는 먼저 skb_ensure_writable(skb, 0)으로 버퍼를 단독 소유로 만든 뒤 이더넷 출발지 주소를 고칩니다. 길이가 0인 이유는 Fixes: 태그가 가리키는 과거 수정과 이어집니다. 예전에는 더 긴 길이를 요구했는데, 그러면 페이로드가 그보다 짧은 작은 프레임이 조건을 못 채워 버려졌습니다. 그 회귀를 고치면서 길이를 0으로 낮춘 것으로 보입니다(분석·추정 — 커밋 63137bc5882a의 제목과 패치 메시지 서술 기준, diff 미대조).
2) ARP 본문 쓰기는 보호되지 않습니다. 프레임이 ARP이면 함수는 skb_header_pointer()로 ARP 고정 헤더를 읽어 하드웨어 주소 길이가 6인지 확인합니다. 여기까지는 읽기입니다. 이어서 skb_store_bits()로 ARP 헤더 바로 뒤, 즉 SHA 자리에 새 MAC 6바이트를 씁니다. 그런데 앞에서 확인한 쓰기 가능 범위는 0바이트입니다. SHA가 놓인 skb->data 기준 8~13바이트 구간(ARP 고정 헤더 8바이트 + SHA 6바이트)이 선형 영역인지, 단독 소유인지는 아무도 확인하지 않았습니다.
3) 그 구간이 빌려 온 페이지면 그 페이지가 바뀝니다. SHA 구간이 비선형 조각에 있고, 그 조각이 splice로 들여온 파일 페이지라면 skb_store_bits()는 그 페이지에 MAC 값을 직접 기록합니다.
/* 개념용 단순화, 실제 페이로드/원본 코드 아님 */
snat_target(skb, rule):
ensure_writable(skb, 0) /* (A) 이더넷 헤더용 확인 — 길이 0 */
eth_header(skb).source = rule.mac /* 보호된 쓰기 */
if frame_is_arp(skb) and rule.rewrite_arp:
arp = read_header_safely(skb, ARP_HDR_LEN) /* 읽기 전용 보증 */
if arp.hw_addr_len != 6: goto out
/* (B) 취약 지점: [ARP_HDR_LEN, ARP_HDR_LEN+6) 구간이
쓰기 가능한지 확인한 적이 없다.
구간이 파일 페이지 조각이면 그 페이지에 직접 쓴다 */
store_bits(skb, ARP_HDR_LEN, rule.mac, 6)
out:
return verdict
패치(diff 요지). 메인라인 커밋 67ba971a…는 ARP 분기 안에서, ARP 헤더를 읽고 skb_store_bits()를 부르기 전에 쓰기 가능 확인을 하나 추가합니다. 범위는 ARP 고정 헤더 크기에 SHA 6바이트를 더한 길이이고, 확인이 실패하면 프레임을 버립니다(EBT_DROP). 이렇게 하면 해당 구간이 선형·단독 소유 영역으로 옮겨진 뒤에 쓰기가 일어나므로, 빌려 온 페이지는 건드리지 않게 됩니다. ⚠️미확인(팩트체크 대상) — 리서치 재료가 얻은 diff는 추가된 가드 부분만 잘린 상태였습니다. 주변 라인·정확한 삽입 위치·커밋 전체 규모는 원본 대조가 필요합니다.
확인을 함수 첫머리가 아니라 ARP 분기 안에 둔 점은 눈여겨볼 만합니다. 첫머리 길이를 다시 늘리면 과거에 고친 “작은 패킷 드롭” 회귀가 되살아납니다. 분기 안에 두면 ARP가 아닌 작은 프레임은 영향받지 않고, 14바이트도 안 되는 ARP 프레임만 버려집니다. 그런 프레임은 어차피 형식에 맞지 않습니다(분석·추정).
공격 시나리오 · 영향도 + 대응방안
공격 시나리오 (개념 수준, 작동 절차 없음):
- 로컬 저권한 공격자가 브리지와 ebtables SNAT 규칙(ARP 재작성 포함)을 구성할 수 있는 위치를 확보합니다. 규칙 설정에는 네트워크 관리 권한(
CAP_NET_ADMIN)이 필요하며, 비특권 사용자 네임스페이스가 허용된 배포판에서는 네임스페이스 안에서 이 권한을 얻을 수 있는 것으로 보입니다(분석·추정 —PR:L평가의 배경으로 추정하나 1차출처 미확증). - SHA 구간이 파일 페이지 조각 위에 놓인 ARP 프레임이 그 규칙을 지나가게 만듭니다.
- 규칙에 적힌 MAC 값 6바이트가 해당 파일 페이지의 고정 오프셋에 기록됩니다.
2단계를 실제로 어떻게 성립시키는지는 1차출처에 없으며 이 글도 다루지 않습니다. 공개된 익스플로잇은 리서치 범위에서 확인되지 않았습니다.
영향도. 확인된 것은 “커널이 쓰면 안 되는 페이지에 6바이트를 쓴다”는 쓰기 원시 동작(primitive)까지입니다. 쓰는 값은 공격자가 규칙으로 정하는 MAC 주소이고 위치는 프레임 구조상 제한됩니다. CWE-787이라는 분류와 달리 실체는 “경계를 넘는 쓰기”라기보다 “소유하지 않은 공유 페이지에 대한 쓰기” 에 가깝습니다(분석). 대상이 페이지 캐시라면 공격자가 읽기 권한만 가진 파일의 메모리 내 사본이 바뀔 수 있고, 이는 파일 권한이라는 다른 보안 경계를 넘는 일입니다. CVSS가 범위 변경(S:C)으로 매겨진 배경이 이것으로 추정되지만, 채점 근거는 1차출처에서 확인하지 못했습니다(분석·추정). 권한 상승으로 이어지는지도 공개 자료로는 확인되지 않았습니다.
대응방안:
-
근본 — 수정 커널로 업데이트. 아래 값은 모두 리서치 재료(OpenCVE·배포판 트래커) 기준이며 ⚠️미확인(팩트체크 대상) 입니다.
계열 수정 버전 수정 커밋 5.10 5.10.259 bf84ad7c7a9ede46e31afaa41a1ba06a159e8c875.15 5.15.210 76280b78cc9f23bdc6438e10ad6dff148ef8375b6.1 6.1.176 b7e91939ba9be805a62a257fa4e227dffbb88fa06.6 6.6.143 afd64b59c3de9bbbdd3759e834fdc55cda716e0b6.12 6.12.94 153ea96c806aea395daba907a4f88480b6ad50936.18 6.18.36 b18675263db1147c8e1cab625400c13a0d87bd2d7.0 7.0.13 c9b5ff59feffb92a147a84a5aa28acd2cb8ff4c5메인라인 7.1 67ba971ae02514d85818fe0c32549ab4bfa3bf49배포판: Debian bullseye
5.10.259-1/ bookworm6.1.176-1/ trixie6.12.94-1(권고 DLA-4664-1·DLA-4665-1·DLA-4671-1), Ubuntu 26.04 LTSlinux 7.0.0-31.31. 실제 운영에서는 stable 버전 번호보다 사용 중인 배포판의 보안 공지를 기준으로 삼으십시오. 이 수정 이후 후속(미완결) 패치가 있었는지는 확인되지 않았습니다(미확인). -
차선(즉시 업데이트 불가 시):
- 브리지 필터링을 쓰지 않는 호스트라면 ebtables 관련 모듈(
ebtables,ebt_snat등)의 로드를 차단합니다(모듈 블랙리스트). 모듈명은 배포판 커널 설정에 따라 확인이 필요합니다. - 비특권 사용자 네임스페이스가 업무상 필요 없다면 제한합니다. 공격 전제인 네트워크 관리 권한의 확보 경로를 좁힙니다(위 추정에 근거한 완화책이며, 컨테이너 런타임 등 의존 기능에 미치는 영향을 먼저 점검해야 합니다).
- 컨테이너에
CAP_NET_ADMIN을 관성적으로 부여하지 않습니다.
- 브리지 필터링을 쓰지 않는 호스트라면 ebtables 관련 모듈(
-
탐지 관점: 브리지를 쓰지 않는 서버에서
ebt_snat·ebtable_nat모듈이 로드되는 사건, 일반 사용자 프로세스가 네임스페이스를 만든 직후 브리지·ebtables 규칙을 구성하는 행위는 평소에 드문 조합이므로 감사 로그(auditd) 조사 대상입니다.
결론
도서관에서 빌린 책을 복사기에 올려 복사하는 것과, 빌린 책 위에 직접 펜으로 고쳐 쓰는 것은 다릅니다. 이번 결함은 “내 공책인 줄 알고 썼는데 빌린 책이었던” 경우입니다.
왜 이 부류가 반복되는가. 무복사 최적화는 “데이터를 옮기지 않고 가리키기만 한다”는 약속으로 속도를 얻습니다. 그 대가로 “이 메모리는 누구 것인가, 써도 되는가”라는 질문이 모든 쓰기 지점의 숙제로 흩어집니다. 읽기 도구와 쓰기 도구가 분리돼 있어도, 한 함수 안에서 첫 번째 쓰기에만 확인을 붙이고 두 번째 쓰기를 빠뜨리면 같은 일이 일어납니다. 2022년의 Dirty Pipe(CVE-2022-0847)는 원인 코드가 전혀 다르지만(파이프 버퍼 플래그 초기화 누락), “splice로 빌려 온 페이지 캐시에 쓰기가 닿는다”는 결과의 모양은 같은 계열입니다(분석). 같은 날 다룬 CVE-2025-39964(AF_ALG 동시 쓰기)와도 닿아 있습니다. 거기서는 “한 번에 한 명만 쓴다”가, 여기서는 “쓰기 전에 쓰기 가능을 확인한다”가 설계자의 머릿속에만 있고 해당 코드 경로에는 없었습니다.
또 하나 남길 점은 회귀 수정이 남긴 그늘입니다. 확인 길이를 0으로 낮춘 과거 수정은 작은 패킷 문제를 옳게 고쳤지만, 그 길이에 암묵적으로 기대고 있던 다른 쓰기가 있는지는 다시 살피지 않은 것으로 보입니다(분석·추정). 검증 조건을 완화하는 패치를 볼 때는 “이 조건에 기대던 코드가 또 있는가”를 물어야 합니다. 이 한 줄은 고쳐졌지만, 이 질문은 다른 드라이버·다른 netfilter 타깃에서 또 시험대에 오릅니다. 그래서 우리는 도구가 아니라 방법을 남깁니다.
References / 참고자료
- Linux 커널(torvalds/linux), 패치 커밋
67ba971a“netfilter: bridge: make ebt_snat ARP rewrite writable” — 이 글이 재구성한 원 분석(1차출처). 근본원인 서술·Fixes:태그·보고자·추가된 가드·부모 SHA의 근거. GitHub 미러로 확인, 정본은 git.kernel.org. https://github.com/torvalds/linux/commit/67ba971ae02514d85818fe0c32549ab4bfa3bf49 - NVD, “CVE-2026-53266 Detail” — 취약점 식별 정본(설명·CVSS·CWE). 리서치 단계에서 본문 미획득, 팩트체크 재확인 대상. https://nvd.nist.gov/vuln/detail/CVE-2026-53266
- linux-cve-announce(미러), CVE-2026-53266 공지 — 커널 CNA의 영향/수정 버전 표와
Fixes:기준 시작점. https://ratatoskr.run/linux-cve-announce/2026/06/17175089 - OpenCVE, “CVE-2026-53266” — CVSS 벡터·CWE 표기·stable 수정 커밋 링크 목록. https://app.opencve.io/cve/CVE-2026-53266
- Debian Security Tracker, “CVE-2026-53266” — Debian 계열별 수정 버전과 DLA 권고 번호. https://security-tracker.debian.org/tracker/CVE-2026-53266
- Ubuntu Security, “CVE-2026-53266” — 공개일·Ubuntu 수정 버전. https://ubuntu.com/security/CVE-2026-53266
이 글은 위 원 자료를 우리 관점에서 다시 쓰고 논평을 더한 것입니다. 특정 문장·코드를 그대로 옮기지 않았으며, 자세한 내용은 원문을 참고하세요. 작성 시점에 원본 소스(부모 SHA 3027ecbd…)를 직접 대조하지 못했으므로 본문 코드는 실제 소스가 아닌 개념용 재구성입니다. ⚠️미확인 표시가 붙은 사실 주장(특히 CVSS·CWE·영향 시작점·수정 버전과 커밋 SHA·함수명·패치 diff 요지·CISA KEV 등재 여부)은 발행 전 독립 팩트체크로 1차출처 대조가 끝나야 확정됩니다.