리눅스 커널의 IPv4 TCP 핸드셰이크에서 발견된 CVE-2026-98432는 특정 조건에서 원격 공격자가 인증 없이 루트 권한을 얻을 수 있는 취약점이다. 우분투와 레드햇의 수정 커널이 아직 나오지 않은 상황에서, 서버 관리자는 IPv4 옵션이 포함된 TCP 패킷을 차단해 취약점의 촉발 조건을 막을 수 있다.
취약점은 커널 4.4부터 존재하며, 커널팀은 심각도를 9.8로 평가했다. 레드햇은 경쟁 조건을 성립시키기 어렵다는 이유로 더 낮게 평가한다. 앤스로픽의 레드팀은 자사 AI 모델 중 하나가 다중 경로 TCP(MPTCP) 리스너가 있는 서버에서 인증 없이 루트 셸을 얻는 익스플로잇을 만들었다고 보고했다. 공개한 설명에 따르면 KASLR을 우회하는 데 약 48분, 셸을 얻는 데 추가로 5분이 걸렸다. 익스플로잇은 공개되지 않았으며, 현재까지 이 취약점이 공격에 이용됐다는 보고도 없다.
수정 사항은 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, 7.3에 포함됐다. 데비안, Oracle Linux, SUSE는 이미 수정 커널을 배포했다. Amazon Linux 2023은 선택형 6.12 및 6.18 커널에만 수정 사항을 제공한다. 우분투는 지원 중인 모든 릴리스를 ‘작업 중’으로 표시했고, 레드햇은 수정을 연기해 대부분의 리눅스 서버에는 아직 설치할 커널이 없다.
취약점이 작동하는 조건
취약점은 IPv4 Record Route 또는 Timestamp 옵션이 붙은 TCP 연결 요청(SYN)으로 촉발된다. 커널은 이 옵션을 연결이 완료되기 전까지 보관했다가 연결이 설정되면 복사본을 만들지 않고 새 소켓에 넘긴다. 그 순간 다른 CPU가 같은 연결의 재전송 SYN을 처리하면, 이미 해제된 옵션을 읽을 수 있다. IPv6에서는 커널이 옵션을 복사하므로 영향을 받지 않는다.
일반 트래픽에는 IPv4 옵션이 실리지 않는다. RFC 7126은 라우터와 방화벽이 Record Route 또는 Timestamp 옵션이 포함된 패킷을 버리도록 이미 권고한다. 따라서 서버에서도 이런 패킷을 차단해도 일반 트래픽에는 문제가 없다는 설명이다.
앤스로픽의 익스플로잇에는 MPTCP 리스너가 있는 서버가 필요하다. 앤스로픽은 그 이유를 밝히지 않았고 CVE에도 MPTCP가 언급되지 않으므로, MPTCP 리스너가 없는 서버가 안전하다고 단정할 수는 없다. 다만 우선 확인할 대상은 MPTCP 리스너가 있는 서버다.
브라이언 비트코(Brian Vitko)는 자신의 우분투 실험용 가상 머신에서 직접 설정하지 않은 MPTCP 리스너를 발견했다. 포트 9000에서 step-ca가 수신 대기 중이었다. Go 1.24부터 리눅스에서는 커널이 허용하는 경우 Go로 작성한 서버가 기본적으로 MPTCP를 사용해 수신 대기한다. 우분투 26.04는 기본 설정에서 이를 허용하지만(net.mptcp.enabled = 1), Rocky 9.8 가상 머신에서는 비활성화돼 있었다.
서버와 차단 규칙 확인
실행 중인 커널에 수정 사항이 들어갔는지는 버전 번호만 보지 말고 배포판의 커널 변경 기록에서 확인해야 한다. 우분투와 레드햇은 자체 커널에 수정 사항을 백포트하므로, 버전이 오래돼 보여도 수정이 포함됐을 수 있다. 우분투에서는 다음 명령으로 확인한다.
zgrep -c CVE-2026-98432 /usr/share/doc/linux-modules-$(uname -r)/changelog.Debian.gz
RHEL, Rocky, Alma에서는 다음 명령을 사용한다.
rpm -q --changelog kernel-core-$(uname -r) | grep -c CVE-2026-98432
결과가 0보다 크면 실행 중인 커널에 수정 사항이 포함된 것이다. 우분투와 RHEL에서는 현재 결과가 0이 나온다.
MPTCP 리스너는 다음 명령으로 확인할 수 있다.
sudo ss -lnMp
아무것도 출력되지 않으면 MPTCP로 수신 대기 중인 항목이 없다. 브라이언 비트코의 우분투 가상 머신에서는 *:9000의 step-ca가 표시됐다.
sysctl -w net.mptcp.enabled=0을 해결책으로 제시하는 경우도 있다. 이 설정은 프로그램이 새 MPTCP 소켓을 여는 것을 막고, Go 프로그램은 일반 TCP로 전환한다. 하지만 이미 열린 리스너에는 적용되지 않는다. 브라이언 비트코가 가상 머신에서 설정을 끈 뒤에도 step-ca는 MPTCP로 계속 수신 대기했고, 새 MPTCP 소켓 연결만 거부됐다. 이 방법을 쓴다면 ss -lnMp에 표시된 프로그램을 재시작한 뒤 명령을 다시 실행해 리스너가 사라졌는지 확인해야 한다.
Go 서비스에서는 Go 팀이 환경 변수 GODEBUG=multipathtcp=0을 쓰거나, 직접 빌드하는 경우 go.mod에 godebug multipathtcp=0을 설정하라고 권고한다. 이 설정은 해당 프로그램에서 MPTCP를 끈다. Canonical은 이미 Pebble에 이 변경을 적용했으며, Go에서 기본적으로 MPTCP를 끄자는 제안도 진행 중이다. MPTCP 리스너가 없는 서버의 안전성이 확인된 것은 아니므로, 취약점을 촉발하는 패킷도 차단하는 편이 필요하다.
다음 nftables 규칙은 IP 옵션이 있는 IPv4 TCP 패킷을 모두 버린다. 옵션이 없는 IPv4 헤더는 항상 20바이트이며, ip hdrlength는 4바이트 단위로 길이를 세므로 값이 5다. 따라서 ip hdrlength gt 5는 옵션이 있는 패킷만 찾는다. 규칙은 연결 추적보다 먼저 적용되는 우선순위 -300에서 동작한다.
sudo nft add table ip cve_2026_98432
sudo nft add chain ip cve_2026_98432 pre '{ type filter hook prerouting priority -300; }'
sudo nft add rule ip cve_2026_98432 pre meta l4proto tcp ip hdrlength gt 5 counter drop
이 규칙은 패킷을 버리기만 하므로 방화벽에서 막아 둔 연결을 허용하지 않으며, ufw 및 firewalld와 함께 동작한다. IPv6, UDP, ICMP에는 영향을 주지 않는다. 서버가 다른 장비의 트래픽도 라우팅한다면, 서버를 통과하는 IP 옵션 포함 TCP 패킷도 버려진다. IP 옵션을 정상적으로 사용하는 네트워크는 CIPSO를 사용하는 라벨 네트워크(SELinux 또는 Smack NetLabel)다. 이런 네트워크에는 이 규칙을 추가하지 않아야 한다. 규칙은 기본 설정으로는 재부팅 후 사라진다.
테스트와 여러 서버에 적용하기
리눅스에서는 setsockopt(IP_OPTIONS)로 일반 TCP 소켓에 IP 옵션을 넣을 수 있으며, 커널은 SYN을 포함해 전송하는 모든 패킷에 옵션을 추가한다. 브라이언 비트코는 Rocky 가상 머신에서 우분투 가상 머신의 SSH에 두 차례 연결했다. 하나는 일반 SYN, 다른 하나는 Record Route 옵션을 넣은 SYN을 사용했다. 규칙이 없을 때는 두 연결 모두 성공했고, 규칙을 적용한 뒤에는 일반 연결은 성공했지만 Record Route 연결은 차단됐으며 규칙의 카운터가 증가했다.
Rocky에서도 firewalld를 실행한 채 같은 방식으로 시험해 같은 결과를 얻었다. 규칙은 firewall-cmd --reload 뒤에도, 재부팅 뒤에도 남아 있었다. 이 테스트는 촉발 조건이 차단됨을 보여주지만, 익스플로잇 자체를 실행한 것은 아니다.
RFF Script Library에는 리눅스용 항목 두 개가 추가됐다. TCP IP-options bug (CVE-2026-98432) - Exposure Check (Linux)는 실행 중인 커널과 배포판 변경 기록을 비교하고, 수정된 커널이 설치됐지만 아직 부팅되지 않았는지, 차단 규칙이 현재 로드됐는지, 어떤 프로그램이 MPTCP로 수신 대기하는지, 루프백 외부에서 열려 있는 IPv4 포트가 무엇인지 보고한다. Block CVE-2026-98432 (TCP IP options) (Linux)는 규칙과 systemd 유닛을 추가해 재부팅 또는 nftables 재시작 뒤에도 규칙이 돌아오게 한다. 이어 실제 규칙 집합에서 규칙이 로드됐는지 확인한다. 먼저 드라이런을 할 수 있고 나중에 되돌릴 수도 있다.
Rocky에서 처음 만든 스크립트는 규칙 파일을 /tmp에 쓴 뒤 /etc로 옮겼다. mv가 SELinux 레이블을 유지해 nftables가 파일을 읽지 못했고, 부팅 시 규칙도 로드되지 않았다. 자체 유닛을 만든다면 파일을 처음부터 /etc에 생성해야 한다.
배포판이 수정 커널을 제공하면 설치한 뒤 재부팅하고 확인 명령을 다시 실행한다. 그 뒤 차단 규칙을 제거할 수 있다.
관련 자료:
- The Hacker News: Linux kernel TCP flaw with 9.8 CVSS score — 배포판별 상태, 수정 버전, 앤스로픽의 익스플로잇
- Atlas: CVE-2026-98432 — 촉발 옵션과 nftables 규칙
- 우분투: CVE-2026-98432
- 레드햇: CVE-2026-98432
- Go 1.24 release notes — 리스너에서 기본적으로 MPTCP 사용
- Go issue 82717: disable MPTCP by default —
GODEBUG=multipathtcp=0권고 및 Pebble PR 1146 - PatchMon: CVE-2026-98432 status — 배포판별 상태와 익스플로잇 미공개 현황
- typhoon1217/cve-2026-98432-mitigation — 같은 차단 규칙의 독립 테스트와 CIPSO 주의사항
- RFC 7126: Recommendations on filtering of IPv4 packets containing IPv4 options
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요