
취약점 감지 및 완화 도구: Copy Fail 및 Dirty Frag 버그 (CVE-2026-31431, CVE-2026-43284, CVE-2026-43500)
# vcheck SSH를 통해 원격 Linux 호스트를 감사하여 Copy Fail 및 Dirty Frag 커널 모듈 취약점을 확인하고, 선택적으로 완화 조치를 적용합니다: | CVE | 이름 | 영향받는 모듈 | | -------------- | --------------------- | ------------------------------------------------- | | CVE-2026-31431 | 카피 실패 (Copy Fail) | `algif_aead` | | CVE-2026-43284 | 더티 프래그 (IPsec) | `esp4`, `esp6`, `ipcomp4`, `ipcomp6`, `xfrm_user` | | CVE-2026-43500 | 더티 프래그 (RxRPC) | `rxrpc`, `kafs` | vcheck는 각 영향받는 모듈에 대해 현재 로드 여부, 실행 중인 커널에 내장(built-in)되었는지, 커널 로그에 과거 흔적이 있는지, 라이브 `AF_ALG` 소켓이 있는지(Copy Fail만 해당), 그리고 `/etc/modprobe.d/` 아래에 이미 블랙리스트에 등록되었는지를 보고합니다. `-fix` 옵션을 사용하면 vcheck가 초기 상태를 보고하고, 아직 블랙리스트에 없는 모듈에 대해 `cve-XXXX-XXXXX-disable.conf` 스니펫을 작성한 후 검사를 다시 실행하여 최종 상태를 보고합니다. `-fix -unload`를 사용하면 vcheck가 수정 전에 로드된 영향받는 모듈을 언로드하려고 시도한 후 최종 검사로 여전히 로드되어 있는지 확인합니다. `-fix -rebuild-initramfs`를 사용하면 vcheck가 스니펫이 작성된 후 현재 실행 중인 커널에 대해서만 initramfs를 재구축하므로 블랙리스트가 다음 부팅 이미지에 포함됩니다. 이전 커널 항목은 폴백(fallback)으로 원래 initramfs를 유지합니다. ## `-fix`는 검사 전용 실행 후에만 사용하세요 **항상 먼저 `-fix` 없이 vcheck를 실행하세요.** 보고서를 읽고 영향받는 모듈을 이 호스트에서 비활성화해도 안전한지 확인한 후 `-fix`로 다시 실행하세요. 합법적인 워크로드가 의존하는 커널 모듈을 비활성화하면 사용자에게 영향을 주고 애플리케이션을 손상시킬 수 있습니다. 특히 다음 사항을 유의하십시오: - `-fix`가 안전한 것은 영향받는 모듈이 **현재 로드되지 않은 경우**에만 해당합니다. 즉, 모든 모듈이 `mitigated` 또는 `module not blacklisted`로 보고되고 `VULNERABLE` 또는 `blacklisted but currently loaded` 줄이 없는 경우입니다. 로드된 모듈은 거의 항상 _호스트에서 무언가가 활발히 사용 중임_을 의미합니다. 블랙리스트에 추가하기 전에 확인하십시오. - IPsec 모듈(`esp4`, `esp6`, `ipcomp4`, `ipcomp6`, `xfrm_user`)은 IPsec/strongSwan/WireGuard-over-IPsec/IKE 배포에 필요합니다. `ipcomp4`/`ipcomp6` 모듈은 IPComp 페이로드 압축을 구현하며 명시적으로 구성되지 않은 경우에도 IPsec SA의 일부로 자동 협상될 수 있습니다. VPN 게이트웨이, IPsec 엔드포인트 또는 `ip xfrm policy`가 규칙을 반환하는 곳에서는 이들 중 어느 것도 블랙리스트에 추가하지 마십시오. `xfrm_algo` 프레임워크 모듈은 의도적으로 이 목록에 포함되지 않았습니다. 공급업체 지침(Red Hat, Ubuntu, AWS)에 따르면 ESP 및 IPComp 프로토콜 모듈과 `xfrm_user` netlink 구성 인터페이스를 차단하는 것으로 충분하며, `xfrm_algo`를 블랙리스트에 추가하면 추가 이점 없이 다른 모든 xfrm 변환을 손상시킵니다. - RxRPC 모듈(`rxrpc`, `kafs`)은 AFS 파일 시스템을 마운트하는 모든 호스트에 필요합니다. 비활성화하면 다음 부팅 시 해당 마운트가 중단됩니다. - `algif_aead`는 `AF_ALG` 소켓 패밀리를 통해 커널 암호화를 노출합니다. 애플리케이션 코드에서 직접 사용되는 경우는 드물지만, 블랙리스트에 추가하기 전에 라이브 소켓을 나열(`ss -p --af-alg`)하고 사용자 공간 소비자를 확인하십시오. vcheck가 작성하는 블랙리스트 스니펫은 모듈 로드 시점(일반적으로 다음 부팅 또는 시스템이 유휴 상태일 때 `modprobe -r <module>`)에만 적용됩니다. **이미 로드된** 모듈은 `-fix` 이후에도 계속 실행됩니다. vcheck는 이를 `blacklisted but currently loaded; run 'modprobe -r' or reboot`로 보고합니다. `-fix`와 함께 `-unload`를 전달하면 vcheck가 블랙리스트 스니펫을 작성한 후 로드된 영향받는 모듈에 대해 `modprobe -r`을 실행하도록 요청합니다. 실행 중인 커널에서 모듈을 제거해도 안전하다고 확인한 경우에만 사용하십시오. `-fix`와 함께 `-rebuild-initramfs`를 전달하면 **현재 실행 중인 커널에 대해서만** initramfs를 재생성합니다(Debian/Ubuntu에서는 `update-initramfs -u -k $(uname -r)`, RHEL/Fedora에서는 `dracut -f --kver $(uname -r)`). 다른 설치된 커널은 기존 initramfs를 그대로 유지하므로 재부팅 후 문제가 발생하면 부팅 메뉴에서 이전 커널 항목을 선택하여 복구할 수 있습니다. 향후 커널 설치 시 현재 `/etc/modprobe.d/` 상태에서 자체 initramfs를 재구축하므로 vcheck를 다시 실행하지 않고도 블랙리스트가 자동으로 전파됩니다. `update-initramfs`와 `dracut`이 모두 없는 경우(예: Arch, Alpine, 불변 이미지) vcheck는 경고하고 계속 진행합니다. 재부팅하기 전에 배포판 도구를 사용하여 수동으로 재구축하십시오. 재구축에는 몇 분이 걸릴 수 있으며(특히 드라이버가 많은 호스트에서 `dracut`), 이는 진단용 `-command-timeout`을 초과할 수 있습니다. 이 rebuild는 자체 `-initramfs-timeout`(기본값 `10m`) 아래에서 실행되므로 빠른 검사는 시간 제한을 유지하면서 rebuild에 충분한 시간을 할당합니다. 느린 하드웨어의 경우 `-initramfs-timeout`을 늘리거나 `0`을 전달하여 시간 제한을 완전히 비활성화하십시오. 장기 실행 원격 명령 중에 vcheck는 기본적으로 `30s`마다 SSH keepalive 요청을 보내 NAT/방화벽 유휴 타이머가 연결을 끊지 않도록 합니다. `-ssh-keepalive`로 조정하거나 `0`을 전달하여 비활성화하십시오. ## 설치 **Homebrew (macOS):** ```bash brew install --cask krisiasty/tap/vcheck ``` **미리 빌드된 바이너리** Linux, macOS 및 Windows용은 [릴리스 페이지](https://github.com/krisiasty/vcheck/releases)에서 제공됩니다. **소스에서 빌드** (Go 1.26+ 필요): ```bash go install github.com/krisiasty/vcheck@latest ``` ## 사용법 ```text vcheck -host HOST [flags] ``` | 플래그 | 기본값 | 설명 | | --------------------- | -------------- | -------------------------------------------------------------------------------------------------------- | | `-host` | _(필수)_ | 원격 호스트 | | `-user` | `$USER` | 원격 사용자 | | `-port` | `22` | 원격 SSH 포트 | | `-agent` | `true` | 인증에 SSH 에이전트 사용 | | `-identity` | _(비어 있음)_ | 개인 키 파일 경로 (암호화된 경우 암호문 입력 요청) | | `-password` | `false` | SSH 비밀번호 입력 요청 | | `-insecure` | `false` | `known_hosts`에 아직 기록되지 않은 호스트 키 허용; 기록된 키와 불일치는 여전히 실패 | | `-fix` | `false` | 아직 블랙리스트에 없는 모듈에 대해 `/etc/modprobe.d` 스니펫 작성 | | `-unload` | `false` | `-fix`와 함께 사용: 블랙리스트에 추가한 후 영향받는 모듈 언로드 | | `-rebuild-initramfs` | `false` | `-fix`와 함께 사용: 실행 중인 커널에 대해서만 initramfs 재구축 (`update-initramfs` 또는 `dracut`) | | `-skip-logs` | `false` | 커널 로그 기록 검사 건너뛰기 | | `-timeout` | `15s` | SSH 연결 시간 제한 | | `-ssh-keepalive` | `30s` | SSH keepalive 간격 (`0`은 비활성화) | | `-command-timeout` | `30s` | 원격 명령 시간 제한 (`0`은 비활성화) | | `-initramfs-timeout` | `10m` | initramfs 재구축 단계 시간 제한 (`0`은 비활성화); `-rebuild-initramfs`와 함께만 사용 | | `-debug` | `false` | 로그 상세도 증가 | | `-version` | `false` | 버전 표시 후 종료 | `-agent`, `-identity`, `-password` 중 적어도 하나는 사용 가능한 인증 방법을 생성해야 합니다. 메서드는 나열된 순서대로 시도됩니다. 대상에서 sudo가 필요합니다. 암호 없는 sudo가 구성된 경우 도구는 자동으로 진행됩니다. 그렇지 않으면 한 번 비밀번호를 입력하라는 메시지가 표시되고(입력이 숨겨짐) 이후 모든 명령에 대해 `sudo -S`를 통해 전달됩니다. ## 종료 코드 | 코드 | 의미 | | ---- | ------------------------------------------------------------------------------ | | `0` | 모든 영향받는 모듈이 블랙리스트에 등록, 언로드, 내장되지 않음, 비활성 상태 | | `1` | 사용법 오류 | | `2` | SSH 연결 실패 | | `3` | Sudo 인증 실패 | | `4` | 하나 이상의 모듈이 블랙리스트에 등록되지 않음 (현재 노출 없음) | | `5` | 하나 이상의 모듈이 현재 로드, 커널에 내장 또는 활성 사용 중 | | `99` | 내부/검사 실패 | ## 샘플 출력 ### 완전히 완화된 호스트 ```console $ vcheck -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF mitigated cve=CVE-2026-31431 module=algif_aead INF mitigated cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs ``` ### 완화되지 않고 부분적으로 로드됨 — 기본 검사 ```console $ vcheck -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF mitigated cve=CVE-2026-31431 module=algif_aead ERR VULNERABLE cve=CVE-2026-43284 module=esp4 loaded=true ERR module not blacklisted cve=CVE-2026-43284 module=esp6 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp4 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp6 ERR module not blacklisted cve=CVE-2026-43284 module=xfrm_user ERR module not blacklisted cve=CVE-2026-43500 module=rxrpc ERR module not blacklisted cve=CVE-2026-43500 module=kafs ``` ### 동일한 호스트에 `-fix` 적용 — 첫 실행 ```console $ vcheck -fix -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF findings before fix INF mitigated cve=CVE-2026-31431 module=algif_aead ERR VULNERABLE cve=CVE-2026-43284 module=esp4 loaded=true ERR module not blacklisted cve=CVE-2026-43284 module=esp6 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp4 ERR module not blacklisted cve=CVE-2026-43284 module=ipcomp6 ERR module not blacklisted cve=CVE-2026-43284 module=xfrm_user ERR module not blacklisted cve=CVE-2026-43500 module=rxrpc ERR module not blacklisted cve=CVE-2026-43500 module=kafs INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43284-disable.conf modules="[esp4 esp6 ipcomp4 ipcomp6 xfrm_user]" INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43500-disable.conf modules="[rxrpc kafs]" INF re-scanning after fix snippets_written=2 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF findings after fix INF mitigated cve=CVE-2026-31431 module=algif_aead ERR blacklisted but currently loaded; run 'modprobe -r' or reboot cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs ``` 블랙리스트는 적용되었지만 `esp4`는 스니펫이 작성되기 전에 이미 커널에 로드되었습니다. 완전히 해제하려면 대상에서 재부팅하거나 `sudo modprobe -r esp4`를 실행하십시오. ### 두 번째 실행 — esp4가 여전히 로드됨 ```console $ vcheck -fix -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF findings before fix INF mitigated cve=CVE-2026-31431 module=algif_aead ERR blacklisted but currently loaded; run 'modprobe -r' or reboot cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs INF fix: nothing to do — all affected modules already blacklisted ``` ### 세 번째 실행 — `modprobe -r esp4` 실행 후 ```console $ vcheck -host host.example.com -identity ~/.ssh/id_ed25519 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" INF checking vulnerability cve=CVE-2026-43284 name="Dirty Frag (IPsec)" INF checking vulnerability cve=CVE-2026-43500 name="Dirty Frag (RxRPC)" INF mitigated cve=CVE-2026-31431 module=algif_aead INF mitigated cve=CVE-2026-43284 module=esp4 INF mitigated cve=CVE-2026-43284 module=esp6 INF mitigated cve=CVE-2026-43284 module=ipcomp4 INF mitigated cve=CVE-2026-43284 module=ipcomp6 INF mitigated cve=CVE-2026-43284 module=xfrm_user INF mitigated cve=CVE-2026-43500 module=rxrpc INF mitigated cve=CVE-2026-43500 module=kafs ``` ### `-rebuild-initramfs` 사용 ```console $ vcheck -fix -rebuild-initramfs -host host.example.com -identity ~/.ssh/id_ed25519 ... INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43284-disable.conf modules="[esp4 esp6 ipcomp4 ipcomp6 xfrm_user]" INF writing modprobe.d snippet path=/etc/modprobe.d/cve-2026-43500-disable.conf modules="[rxrpc kafs]" INF rebuilding initramfs for running kernel timeout=10m0s INF initramfs rebuilt for running kernel tool=update-initramfs INF re-scanning after fix snippets_written=2 ... ``` 실행 중인 커널의 initramfs만 재구축됩니다. 다른 설치된 커널은 기존 initramfs를 유지하므로 새 initramfs가 문제를 일으키는 경우 부팅 메뉴의 이전 항목이 작동하는 폴백으로 남아 있습니다. `update-initramfs`와 `dracut`이 모두 없는 호스트에서는 vcheck가 `WRN no supported initramfs tool found ...` 로그를 남기고 계속 진행합니다. ### 첫 접속 호스트 — `-insecure` ```console $ vcheck -insecure -host host.example.com -identity ~/.ssh/id_ed25519 WRN host key not in known_hosts; accepting due to -insecure host=host.example.com:22 remote=192.0.2.42:22 fingerprint=SHA256:AAAAEXAMPLEfingerPrint000000000000000000000 INF connected user=ops host=host.example.com port=22 INF checking vulnerability cve=CVE-2026-31431 name="Copy Fail" ... ``` `-insecure`는 아직 `known_hosts`에 없는 호스트를 허용합니다. 호스트가 이미 기록되어 있고 다른 키를 제시하는 경우 연결은 여전히 실패합니다. 이 플래그는 "첫 접속" 재정의일 뿐, 알려진 호스트에 대한 중간자 공격 경고를 억제하는 방법이 아닙니다. ## 탐지 세부 사항 - **로드됨:** `lsmod`를 한 번 가져와 모듈 이름을 첫 번째 열과 비교합니다. - **내장(Built-in):** `/lib/modules/$(uname -r)/modules.builtin`과 `/sys/module`을 확인합니다. modprobe 스니펫은 실행 중인 커널에 컴파일된 코드를 비활성화할 수 없기 때문입니다. - **블랙리스트:** `/etc/modprobe.d/` 아래의 모든 파일을 검색(`grep -rE`)하여 `install <module> /bin/false` 지시문을 찾습니다. 이는 vcheck가 `-fix`로 작성하는 형식과 동일합니다. 다른 비활성화 방식(예: `blacklist`)은 인식되지 않습니다. - **과거 활동:** 먼저 `journalctl -k`를 확인하고, 실패 시 `/var/log/kern.log`로 대체합니다. 모듈당 마지막 다섯 개의 일치하는 줄을 유지합니다. 이 단계를 건너뛰려면 `-skip-logs`를 전달하십시오. - **활성 소켓(`algif_aead`만 해당):** `ss -p --af-alg`로 열린 `AF_ALG` 소켓을 나열합니다. 헤더 이외의 출력은 라이브 사용으로 간주됩니다. 모든 명령은 `sudo`를 통해 실행되며 `-command-timeout`으로 제한됩니다. `/var/log/kern.log` 읽기, `AF_ALG` 소켓 나열, `/etc/modprobe.d/` 아래에 쓰기에는 권한 있는 액세스가 필요합니다. `-unload`를 사용하면 `modprobe -r` 실행에도 권한 있는 액세스가 필요합니다. `-rebuild-initramfs`를 사용하면 vcheck가 `update-initramfs -u -k $(uname -r)` (Debian/Ubuntu) 또는 `dracut -f --kver $(uname -r)` (RHEL/Fedora)를 실행하며, 이 역시 루트 권한이 필요합니다.