
IPv4 TCP 패킷에 포함된 IP 옵션을 드롭하는 nftables 규칙셋과 systemd 유닛으로, 패치된 커널이 배포될 때까지 CVE-2026-98432 Linux 커널 use-after-free 취약점을 완화합니다.
Ubuntu 24.04(noble)에서 CVE-2026-98432에 대한 임시 방화벽 완화책으로, 수정된 커널이 아직 제공되지 않는 상황에서 공용 TCP 리스너(예: 포트 30303의 Geth 노드)를 노출하는 호스트를 위한 것입니다.
CVE-2026-98432는 Linux 커널의 IPv4 TCP 핸드셰이크 코드에 존재하는 use-after-free 취약점입니다. 수신되는 SYN이 IPv4 IP 옵션을 포함할 경우, 해당 옵션은 복사되지 않은 채 새 자식 소켓에 전달됩니다. 이후 다른 CPU에서 동시에 처리되는 재전송된 SYN이 이미 해제된 옵션을 읽을 수 있습니다. 요청 소켓 마이그레이션(net.ipv4.tcp_migrate_req=1 또는 BPF_SK_REUSEPORT_SELECT_OR_MIGRATE 프로그램)을 통한 두 번째 트리거도 존재합니다.
Ubuntu는 이를 High 우선순위(CVSS 3: 9.8)로 평가합니다. 이 글을 작성하는 시점에 noble linux 커널 수정은 아직 진행 중입니다.
MPTCP 리스너도 별개의 사례가 아닙니다. Go 1.24+ 바이너리(최근 Geth 포함)는 기본적으로 리스너를 MPTCP로 열기 때문에 ss에서 mptcp로 표시됩니다. MPTCP 서브플로우는 동일한 IPv4 TCP SYN 경로를 거치므로 일반 TCP와 정확히 동일하게 노출됩니다. MPTCP를 비활성화하는 것(GODEBUG=multipathtcp=0)은 이 취약점을 완화하지 못합니다.
자체 테이블에 있는 단일 nftables 규칙으로, 헤더 길이가 5가 아닌 모든 IPv4 TCP 패킷(즉, IP 옵션을 포함한 모든 패킷)을 커널의 TCP 스택이 처리하기 전에 차단합니다:
ip protocol tcp ip hdrlength != 5 counter drop
ip hdrlength != 5)은 Router Alert 옵션을 포함하는 IGMP 멤버십 쿼리도 차단하여 LAN 멀티캐스트(mDNS/Avahi, 캐스팅)를 조용히 망가뜨릴 수 있었습니다.inet cvefix)에 존재하므로 ufw와 공존하며 ufw 재로드의 영향을 받지 않습니다.| 파일 | 설치 위치 | 용도 |
|---|---|---|
nftables-cve-2026-98432.nft | /etc/nftables-cve-2026-98432.nft | 규칙셋(멱등적이며 재실행해도 안전함) |
cve-2026-98432.service | /etc/systemd/system/cve-2026-98432.service | 부팅 시 규칙셋을 로드하는 oneshot 유닛 |
이 규칙을
/etc/nftables.conf에 넣지 마십시오. 해당 파일은flush ruleset으로 시작하므로nftables.service가 실행되면 ufw의 규칙을 지워버립니다.
git clone <this-repo> && cd <this-repo>
sudo install -m 0644 nftables-cve-2026-98432.nft /etc/nftables-cve-2026-98432.nft
sudo install -m 0644 cve-2026-98432.service /etc/systemd/system/cve-2026-98432.service
sudo systemctl daemon-reload
sudo systemctl enable --now cve-2026-98432.service
sudo nft list table inet cvefix
또한 마이그레이션 트리거가 꺼져 있는지 확인하세요(기본값):
sysctl net.ipv4.tcp_migrate_req # expect: 0
nping을 설치하세요. Ubuntu에서는 nmap 패키지에 포함되어 있으며, 별도의 nping 패키지는 없습니다:
sudo apt install nmap
먼저 규칙 세트를 다시 로드하여 카운터를 0으로 초기화한 다음, 루프백을 통해 일반 SYN(IP 옵션 없음)을 전송합니다:
sudo nft -f /etc/nftables-cve-2026-98432.nft # reload; resets the counter to 0
sudo nping --tcp -p 30303 --flags syn -c 3 127.0.0.1
sudo nft list table inet cvefix
예상 결과: SA(SYN-ACK) 응답이 오며 리스너가 여전히 도달 가능함을 보여주고, 카운터는 packets 0 bytes 0에 머무릅니다. 응답이 전혀 없다면 nping이 루프백에서 패킷 캡처에 실패하고 있을 수 있습니다. 이 경우 이 테스트와 다음 테스트를 127.0.0.1 대신 호스트의 LAN IP를 대상으로 실행하십시오.
동일한 SYN을 보내되, 이번에는 IP 옵션(Record Route)을 실어 보냅니다. 루프백 트래픽은 prerouting 훅을 통과하므로, 중간에 아무것도 없이 이 규칙을 시험하게 됩니다:
sudo nping --tcp -p 30303 --flags syn --ip-options R -c 3 127.0.0.1
sudo nft list table inet cvefix
예상 결과: nping은 응답을 받지 못하며(Lost: 3 (100.00%)), 카운터는 정확히 다음과 같이 표시됩니다:
ip protocol tcp ip hdrlength != 5 counter packets 3 bytes 240 drop
(3개의 프로브 × 80바이트.)
원격 테스트는 프로브가 실제로 호스트에 도달하는 경우에만 해당 규칙을 검증합니다. 동일한 LAN에 있는 다른 머신에서 호스트의 LAN 주소를 대상으로 지정하십시오:
sudo nping --tcp -p 30303 --flags syn --ip-options R -c 3 <host-lan-ip>
그런 다음 보호된 호스트에서 카운터를 확인합니다:
sudo nft list table inet cvefix
예상 결과: 응답이 없고, 카운터가 3만큼 증가합니다(2단계를 먼저 실행했다면 packets 6 bytes 480이 됨).
외부에서 공인 IP를 프로빙하는 것은 보통 결론을 내리기 어렵습니다. 많은 라우터와 ISP 장비는 IP 옵션 패킷 자체를 거부합니다. 전형적인 징후는 ttl=250처럼 높은 TTL을 가진 RA(reset) 응답인데, 이는 초기 TTL이 64인 Linux 호스트가 아니라 초기 TTL이 255인 장비를 가리킵니다. 프로브가 호스트에 도달하지 않으므로 카운터는 움직이지 않습니다. 4단계에서 구별하는 방법을 보여줍니다.
보호된 호스트에서 다음을 실행하십시오.
원격 프로브가 도착하는지 확인합니다. 이것을 시작한 다음, 다른 머신에서 3단계 프로브를 반복하십시오:
sudo tcpdump -ni any 'tcp port 30303 and (ip[0] & 0x0f) > 5'
| 호스트의 tcpdump | nft 카운터 | nping 응답 | 의미 |
|---|---|---|---|
| 패킷 표시됨 | 증가 | 없음 | 완화 조치 작동 중 |
| 패킷 표시됨 | 변화 없음 | SA | 규칙 비활성; nft list table inet cvefix 확인 |
| 아무것도 없음 | 변화 없음 | 없음 또는 RA | 업스트림에서 프로브 중단됨; LAN 또는 루프백에서 테스트 |
다른 트래픽이 잡히지 않는지 확인하십시오. 카운터를 몇 분간 그대로 두십시오. 테스트 횟수에 머물러 있어야 합니다. 이 규칙이 의도적으로 통과시키는, TCP가 아닌 옵션을 포함한 트래픽이 도착하는 것을 보려면:
sudo tcpdump -ni any '(ip[0] & 0x0f) > 5 and not tcp'
LAN 라우터에서 오는 IGMP 쿼리(예: 224.0.0.1로 보내는 igmp query v3)는 정상이며 카운터를 증가시키지 않아야 합니다.
systemctl is-enabled cve-2026-98432.service # expect: enabled
sudo nft list table inet cvefix # table present
sysctl net.ipv4.tcp_migrate_req # expect: 0
이것은 임시방편입니다. 패치된 커널이 나오는지 주기적으로 확인하세요:
uname -r
sudo pro fix CVE-2026-98432
수정 사항이 제공되는 경우:
sudo apt update && sudo apt full-upgrade
sudo reboot
Livepatch(무료 개인 Ubuntu Pro 구독을 통해; pro status, canonical-livepatch status)를 사용하면 재부팅을 피할 수 있지만, 이 CVE에 대한 livepatch가 제공된다는 보장은 없습니다.
수정된 커널을 실행한 후에는(이를 유지하는 것도 무해합니다):
sudo systemctl disable --now cve-2026-98432.service
sudo nft delete table inet cvefix
sudo rm /etc/systemd/system/cve-2026-98432.service /etc/nftables-cve-2026-98432.nft
sudo systemctl daemon-reload
패치 전까지 추가 여유를 두려면 인바운드 30303을 완전히 닫을 수 있습니다(Geth는 피어 수가 줄어들지만 아웃바운드 피어를 통해 계속 동기화합니다):
sudo ufw deny 30303/tcp
# later:
sudo ufw delete deny 30303/tcp