
IPv4 IP 옵션이 포함된 TCP SYN을 호스트가 폐기하는지 확인합니다 (CVE-2026-98432 완화).
호스트가 IP 옵션이 있는 IPv4 TCP SYN을 폐기하는지 확인합니다. 이는 CVE-2026-98432(Linux 커널의 IPv4 TCP 핸드셰이크에서 발생하는 use-after-free, CVSS 9.8)에 대해 권장되는 네트워크 완화 조치입니다(수정된 커널이 배포될 때까지).
각 포트에 대해 일반 SYN 하나와 IPv4 Record Route가 포함된 SYN 하나를 전송하고 응답을 비교합니다. 무해합니다. 아무것도 익스플로잇하지 않고, 핸드셰이크를 시작만 하고(완료하지는 않음) 합니다.
이 테스트가 측정하는 것: IP 옵션이 포함된 SYN이 대상에 도달하여 수락되는지 여부입니다. 커널 버전을 읽지는 않습니다. 이미 수정된 커널도 IP 옵션을 계속 수락하므로
EXPOSTO로 나옵니다. 이 경우EXPOSTO는 단지 "IP 옵션 필터 없음"을 의미하며, 수정 여부는uname -r로 확인합니다.
./verifica-cve-2026-98432.sh <host-ou-ip> [porta ...] # porta padrão: 443
./verifica-cve-2026-98432.sh exemplo.com 443 80 22
스크립트 없이 이미지를 통해 직접 실행하는 경우(대상은 IPv4여야 함):
docker run --rm --network host --cap-add NET_RAW \
ghcr.io/marcelofmatos/cve-2026-98432-check:latest 203.0.113.10 443 22
| 출력 | Exit | 의미 |
|---|---|---|
MITIGADO | 0 | 정상 SYN 수락, IP options가 포함된 SYN은 폐기됨 — 그리고 경로상 어떤 홉도 IP options를 필터링하지 않음 |
EXPOSTO | 1 | IP options가 포함된 SYN도 수락됨: 경로상 어디에서도, 대상에서도 필터링하지 않음 |
INCONCLUSIVO | 2 | 포트 닫힘(RST) 또는 필터링됨 — 열린 포트를 사용하십시오 |
SEM HOST | 2 | 대상이 로컬 네트워크에 있고 해당 IP에 대해 ARP 응답이 없음: IP가 비어 있거나 머신이 꺼져 있음. TCP 프로브는 전송되지 않음 |
NÃO CONFIÁVEL | 3 | 어떤 경로 홉(VPN, 통신사)이 이미 IP options를 폐기함. "폐기됨"은 대상에 대해 아무것도 증명하지 못함: 네트워크의 다른 지점에서 테스트하십시오 |
| — | 64 | 잘못된 사용, 또는 IPv4가 없는 이름 |
포트가 여러 개인 경우 exit는 최악의 경우를 따릅니다: 어떤 것이든 EXPOSTO → 1.
세부 사항:
getent). 따라서 VPN/내부 DNS 이름도 작동합니다.prerouting을 통과합니다.CHECK_IMAGE (기본값 ghcr.io/marcelofmatos/cve-2026-98432-check:latest). 로그의 첫 줄은
버전입니다: cve-2026-98432-check <버전> iniciando.많은 VPN과 통신사가 IP options가 포함된 패킷을 폐기합니다. 그중 하나 뒤에서 테스트하면
모든 대상이 완화된 것처럼 보입니다. 그래서 검증기는 테스트 전에 경로를 홉 단위로(TTL
증가) 순회하며, 어떤 홉이 IP options를 폐기하면 NÃO CONFIÁVEL을 반환합니다.
한계: ICMP에 응답하지 않는 홉의 필터는 감지되지 않습니다. 완화가 없다고 알려진 대상에서
테스트 지점을 검증하십시오: EXPOSTO가 나와야 합니다.
취약한 Linux는 SYN-ACK에서 IP options를 반환합니다(Record Route가 포함된 SYN은
ihl=6과 RR 옵션과 함께 돌아옵니다). mitigacao/의 규칙이 있는 테스트 지점에서는
이 SYN-ACK이 prerouting에서 폐기됩니다. 그래도 결과는 정확합니다: scapy는 netfilter 이전에
패킷 소켓에서 응답을 캡처합니다. 측정 결과: 규칙이 있는 호스트에서 규칙이 없는 대상을 테스트했을 때
결과는 EXPOSTO였고 규칙 카운터는 1 증가했습니다(캡처된 후 폐기된 SYN-ACK). 테스트
규칙 없는 대상 (컨테이너) -> EXPOSTO가 CI에서 이 경우를 커버하며, CI는 규칙 없이 그리고 규칙과 함께
러너에서 테스트를 실행합니다.
예외: 테스트 지점 자체의 bridge 뒤에 있고 br_netfilter가 있는 대상. 모듈이
로드되어 있으면(net.bridge.bridge-nf-call-iptables = 1, Docker Swarm 호스트 및 많은
Proxmox의 기본값), IPv4 prerouting이 캡처 이전에 bridge 내부에서 실행됩니다. 이 경우 테스트 지점의
규칙이 해당 bridge의 컨테이너 또는 VM의 SYN-ACK을 폐기하여 결과가 **거짓 MITIGADO**가 됩니다.
일반 NIC(네트워크의 다른 머신)를 통해 도달하는 대상은 영향을 받지 않습니다.
br_netfilter가 있는 호스트의 컨테이너나 VM을 테스트하려면 그 외부의 테스트 지점을 사용하거나
규칙이 없는 테스트 지점을 사용하십시오. 테스트는 이 조합을 감지하면 해당 경우를 건너뜁니다(SKIP).
대상의 포트가 Docker에 의해 게시된 경우(컨테이너로의 DNAT), 대상 자체가 패킷을 포워딩하기 때문에
낮은 TTL의 프로브에 ICMP "TTL 초과"로 응답합니다. 검증기는 이 ICMP를 출발지 IP(대상의 IP)로
인식하여 경로 홉으로 취급하지 않습니다. 버전 1.1.0까지는 목록의 첫 번째 포트가 포워딩된 경우
완화된 대상에서 거짓 **NÃO CONFIÁVEL**을 반환했습니다. 테스트
완화된 대상에서 포워딩된 포트 -> MITIGADO가 이 경우를 커버합니다.
cve-2026-98432.nft: prerouting(priority -300)에서 ip hdrlength > 5인 TCP IPv4를 폐기하는
ip cve_2026_98432 테이블. 멱등적.cve-2026-98432-mitigation.service: 네트워크가 올라오기 전에 규칙을 로드하는 systemd unit.sudo install -m 644 mitigacao/cve-2026-98432.nft /etc/cve-2026-98432.nft
sudo install -m 644 mitigacao/cve-2026-98432-mitigation.service /etc/systemd/system/
echo 'net.mptcp.enabled = 0' | sudo tee /etc/sysctl.d/90-cve-2026-98432-mptcp.conf
sudo sysctl -w net.mptcp.enabled=0
sudo systemctl daemon-reload && sudo systemctl enable --now cve-2026-98432-mitigation
수정된 커널을 대체하지 않습니다: 배포판이 게시하는 즉시 설치하고 재부팅하십시오.
flowchart LR
U["Operador"] --> L["verifica-cve-2026-98432.sh<br/>resolve o nome com getent<br/>escolhe a rede do container"]
L -->|"docker run --cap-add NET_RAW"| C["Container cve-2026-98432-check<br/>Alpine + Python + scapy"]
C -->|"rede host: alvo remoto"| N["Caminho de rede<br/>VPN, operadora, internet"]
C -->|"bridge: alvo é a própria máquina"| H["prerouting do host"]
N --> A["Alvo IPv4<br/>porta TCP"]
REG["GHCR<br/>ghcr.io/marcelofmatos/cve-2026-98432-check"] -.->|"docker pull"| C
flowchart TD
S["Início: alvo e portas"] --> AQ{"Alvo na rede local<br/>e sem resposta ARP?"}
AQ -->|"sim"| SH["SEM HOST — exit 2"]
AQ -->|"não"| H["TTL = 1, 2, 3 ... até o alvo<br/>SYN normal e SYN com RR"]
H --> HQ{"Algum salto responde ICMP ao normal<br/>e some com o RR?"}
HQ -->|"sim"| FL["caminho FILTRA no salto N"]
HQ -->|"não, chegou ao alvo, ICMP veio do próprio alvo<br/>ou 4 saltos mudos seguidos"| OK["nenhum filtro visto"]
FL --> P
OK --> P
P["Por porta: SYN normal"] --> PQ{"SYN-ACK?"}
PQ -->|"não"| INC["INCONCLUSIVO — exit 2"]
PQ -->|"sim"| R["SYN com RR"]
R --> RQ{"Alguma resposta?"}
RQ -->|"sim"| EXP["EXPOSTO — exit 1"]
RQ -->|"não, caminho filtra"| NC["NÃO CONFIÁVEL — exit 3"]
RQ -->|"não, caminho limpo"| MIT["MITIGADO — exit 0"]
docker build --build-arg APP_VERSION=dev -t cve-2026-98432-check:dev .
# ESPERADO_LOCAL=1 num host sem a regra nft; 0 num host com a regra aplicada
CHECK_IMAGE=cve-2026-98432-check:dev ESPERADO_LOCAL=1 VERSAO_ESPERADA=dev ./tests/testes.sh
테스트는 호스트에 임시 리스너(포트 18098)를 띄우고 Docker 브리지의 컨테이너에서 이를 테스트합니다. CI(test.yml)에서는 러너가 두 번 실행됩니다: 규칙 없이(EXPOSTO가 출력되어야 함) 그리고 규칙을 적용한 상태로(MITIGADO가 출력되어야 함). 이는 양방향으로 방법을 검증합니다.
수동 워크플로 release-and-build.yml (Actions →
Release and build → patch/minor/major): 테스트를 실행하고, SemVer 태그와 릴리스를 생성하며, x.y.z, x.y, x, latest 태그로 GHCR에 이미지를 게시합니다. 버전은 APP_VERSION을 통해 이미지에 포함됩니다.
MIT