
CVE-2026-74580(Linux vhost 메타데이터 캐시 버그)을 위한 수동적 인터넷 전역 탐색 + 책임 있는 공개 지원 도구 — 기존 스캔 데이터(Sonar/Shodan/Censys)를 조회하고, 노출 여부를 분류하며, 소유자에게 보낼 통지 초안을 작성합니다(자동 전송은 절대 하지 않음).
CVE-2026-74580("Vghost")를 위한 경계 점검 및 책임 있는 공개 도우미입니다.
이 취약점은 실제 Linux 커널 vhost 메타데이터 캐시 버그
(CVE 레코드,
OSV 항목)로, 노출된
vhost/하이퍼바이저 호스트에서 로컬 권한 상승 / VM 탈출을 가능하게 합니다.
주요 사용 사례: 자신의 경계 점검. 자신의 IP 범위, CIDR 또는 도메인
(import_list.py)을 내부든 외부든 입력하고, vhost 인접 노출(libvirt/Proxmox/QEMU
관리 포트)에 대해 분류한 다음, 자신의 트래커용 조치 노트를 받으세요
(run_pipeline.py --self, 아래 "자신의 경계 점검" 참조). 자동 탐색도,
대량 연락처 조회도 없습니다. 호스트는 이미 당신 소유입니다.
보조 기능: 공개 스캔 데이터를 통한 제3자 탐색. 이 프로젝트는 인터넷을 직접 스캔하지 않습니다. 선택적으로 이미 스캔을 수행한 데이터셋/API(Rapid7 Open Data / Sonar, Shodan, Censys)를 조회하여 다른 노출된 호스트를 찾은 다음, 소유자에게 보낼 공개 통지 초안을 작성하도록 도울 수 있습니다. 여기에 시간을 투자하기 전에 알아둘 점: 이에 대한 현상금은 없습니다(CSIRT는 지불하지 않으며, "알려진 CVE, 미패치 인스턴스" 보고는 현상금 대상이 되는 경우가 드뭅니다 — 아래 "영향" 참조). 이는 무보수 시민 알림 작업이며, 이 저장소의 실제 사용 대부분은 위의 경계 점검 사례가 아니라 이 경우입니다.
CVE-2026-74580은 커널 수준의 로컬 버그이지 웹/네트워크 대면 버그가 아닙니다. 이로 인해 분류에 중요한 몇 가지가 따릅니다:
다음 조건이 모두 충족될 때만 적용됩니다:
vhost-net/vhost-scsi, 일반적으로
libvirt 또는 Proxmox 경유)를 사용합니다. VM이 없는 베어메탈 호스트나
vhost 오프로드 없이 일반 virtio를 사용하는 VM은 패치 수준과 무관하게
이 버그에 노출되지 않습니다.실제 심각도를 결정하는 것은 호스트가 인터넷에 노출되어 있는지 여부가 아니라 누가 이미 코드 실행 권한을 가지고 있는지(또는 얻을 수 있는지)입니다. 인터넷 노출은 외부 공격자가 대상를 얼마나 쉽게 찾거나 초기 발판에 원격으로 도달하는지에만 영향을 미치며, 누군가 그 발판을 확보한 후 버그가 악용 가능한지 여부는 바꾸지 않습니다. 내부 전용 사설 인프라가 본질적으로 위험이 낮은 것은 아닙니다:
가장 중요한 경우, 인터넷 노출 여부와 무관하게:
인터넷 노출이 실제로 중요한 경우 (주요 요인이 아닌 부차적 요인):
merge_and_triage.py의 점수가 찾아내는 대상입니다. 하지만 노출된
포트 자체만으로는 아무것도 증명하지 못합니다 -- 공격자가 제어하는
무언가가 로컬에서 실행될 수 있을 때만 의미가 있으며, 수동 스캔
데이터로는 이를 보여줄 수 없습니다(이 저장소가 소유하지 않은 호스트를
대상으로 이를 확인하려 하지 않는 이유는 아래 "왜 수동 전용인가" 참조).실제로 심각도가 낮은 경우:
WAF가 도움이 될까요? 이 버그 자체에 대해서는 직접적으로 도움이 되지 않습니다 -- WAF는 HTTP(S) 트래픽을 검사하는데, 이 버그는 요청 파싱이 아니라 커널의 vhost 메타데이터 캐시 경로에 존재합니다. 취약점 자체의 노출 경로에 WAF는 그냥 포함되지 않습니다.
WAF가 실제로 중요한 지점은 한 단계 앞입니다: 가장 흔한 실제 공격 체인은 웹 앱 RCE → 게스트 내부에서의 코드 실행 → vhost 익스플로잇 → 호스트 탈출 → 다른 모든 테넌트로의 측면 이동입니다. WAF(또는 다른 웹 보안 통제)는 공격자에게 최초 발판을 제공하는 웹 앱 RCE를 차단할 수 있으며, 이는 공격자가 이 버그의 전제 조건에 도달하는 것 자체를 막습니다. 즉, vhost 버그 자체와는 무관하지만, 그 전제 조건으로 진입하는 가장 흔한 경로 중 하나와는 관련이 있습니다.
위험을 처음부터 끝까지 실제로 줄이는 방법: 커널 패치, 필요하지 않은 곳에서 vhost 오프로드 비활성화, libvirt/Proxmox 관리 포트를 인터넷에 노출하지 않기, 게스트 내부에서 실행되는 웹 앱/서비스 강화(최초 RCE 가능성 감소), 그리고 테넌트 격리 강화(seccomp, 네임스페이스)를 통해 어떤 발판이든 얻기 어렵게 만드는 것입니다.
소유하지 않았거나 서면 승인을 받지 않은 시스템을 능동적으로 포트
스캔하거나 SSH 프로빙하는 것은 대부분의 관할권에서 무단 접근입니다
(EU에서는 Directive 2013/40/EU 이행법에 해당하며, 체코 법에서는
§ 230 trestního zákoníku에 규정되어 있습니다). 또한 대부분의
호스트/클라우드에서 ToS 위반입니다 -- 선의의 의도와 무관하게
말입니다. 이 저장소는 제3자 스캐너가 자체 승인 하에 이미 수집하고
공개했거나 판매 접근 권한을 부여한 데이터만 읽습니다.
SCOPE.md를 참조하십시오.
특정 발견 사항을 검증하려면(호스트가 단지 "노출된 것처럼 보이는" 것이 아니라 실제로 취약한지 확인), 소유자의 허가가 필요합니다 -- 정확히 그것을 요청하는 공개 템플릿을 참조하십시오.
src/sonar_query.py — vhost 인접 포트/배너를 위해 Rapid7 Open Data / Sonar 스캔 파일(무료 다운로드, 계정 불필요)을 파싱합니다.src/shodan_query.py / src/censys_query.py — 선택 사항으로, 동일한 시그니처에 대한 무료 티어 API 쿼리입니다(Sonar의 주기적 덤프보다 최신 데이터에 유용).src/merge_and_triage.py — 결과를 병합하고, 중복을 제거하며, 노출 가능성을 점수화하여 reports/candidates.csv를 출력합니다.src/whois_contacts.py — 선택 사항(아래 참조) — 공개 라우팅을 위해 후보별 abuse/보안 연락처를 조회합니다(RDAP + security.txt 가져오기).src/draft_notices.py — 후보별로 templates/disclosure_email.md를 채워 reports/notices/에 저장하며, 이는 직접 검토하고 수동으로 발송하기 위한 것입니다.이 파이프라인에서 자동으로 이메일을 보내거나 누군가에게 연락하는 것은 아무것도 없습니다 — 통지는 수동 검토 및 발송을 위해 초안이 작성되며, 다수의 조직에 대한 발견 사항은 대신 국가 CSIRT를 통해 처리해야 합니다(아래 참조).
위의 4–5단계(연락처 조회, 공개 초안 작성)는 호스트 소유자가 누구인지 이미 알지 못할 때, 즉 낯선 사람에게 알릴 때만 의미가 있습니다. 대신 자신의 IP 범위/도메인(아래 옵션 B)을 입력하여 공개 스캔 데이터가 자신의 노출에 대해 무엇을 말하는지 확인하는 경우에는 소유자를 이미 알고 있으므로 whois_contacts.py를 완전히 건너뛰고 draft_notices.py 대신 **src/draft_remediation.py**를 사용하십시오 — 이는 후보별로 templates/remediation_note.md를 채워 reports/remediation/에 저장합니다(공개 이메일이 아닌 자신의 트래커용 티켓이며, RDAP/security.txt 조회가 필요 없습니다). run_pipeline.py --self가 이를 자동으로 수행합니다(아래 "선택 사항: 매주 실행하기" 참조).
이는 인터넷에 노출된 호스트뿐 아니라 내부 호스트에도 적용됩니다. import_list.py/merge_and_triage.py는 --self 모드에서 대상 호스트에 절대 연결하지 않습니다 — 도메인/FQDN에 대한 DNS 확인과 CIDR 연산만 수행한 뒤, 이미 제공한 메타데이터를 점수화합니다. 따라서 사설 IP 범위(10.x, 172.16.x, 192.168.x), 내부 FQDN, CNAME 모두 작동하며, 실행하는 위치에서 이를 확인/도달할 수 있으면 됩니다(예: 내부 네트워크 또는 VPN) — --self는 SSRF 제한이 있는 유일한 단계(whois_contacts.py)를 이미 건너뛰는데, 연락처를 조회할 제3자가 없기 때문입니다. Shodan/Censys/Sonar는 당연히 내부 호스트를 다루지 않습니다(공용 인터넷만 인덱싱함). 대신 자신의 내부 인벤토리를 옵션 B를 통해 입력하십시오.
플래그된 호스트를 단순히 분류하는 것이 아니라 확인하기: 위의 모든 것은 수동적 분류(포트/배너 신호)이며 — 특정 호스트의 커널이 실제로 패치되지 않았는지 여부는 알려주지 않습니다. 이를 위해서는 이미 권한이 부여된 호스트(SCOPE.md의 시나리오 B에 따라)에서 **src/vghost_scan.py**를 사용하십시오: 이는 uname -r과 vhost 커널 모듈이 로드되었는지 여부를 읽고(익스플로잇 관련 없음, 호스트를 수정하는 것도 없음), 이를 위의 수정 버전 표와 대조하여 확인합니다.
python3 src/vghost_scan.py --local # the machine you're already on
python3 src/vghost_scan.py --ssh-host [email protected] --confirm-authorized # a host you control, via your own SSH access
실행할 때마다 명시적으로 지정된 호스트 하나만 검사합니다. 대량/목록 입력도, 자격 증명 추측도, 탐색도 없습니다. --ssh-host는 기존 SSH 접근(키/에이전트/설정)을 그대로 사용하며, 자격 증명을 직접 읽거나, 프롬프트로 요청하거나, 저장하지 않습니다.
모든 작업은 저장소 루트에서 실행하세요. 모든 스크립트는 스크립트 자체가 아닌 현재 디렉터리 기준의 상대 경로(data/, reports/, templates/, config/)를 사용합니다.
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Option A: free Rapid7 Sonar datasets (no key, large download)
python3 src/sonar_query.py --file sonar_tcp_16509.json.gz --port 16509 --port 16514 --port 8006
# Option B: your own list -- CSV with an "ip" and/or "domain" column (+ optional "port", other columns kept).
# The "ip" column may also hold a CIDR range (e.g. 203.0.113.0/24); it's expanded to
# individual addresses as passive-lookup candidates, capped by --max-hosts (default 65536).
python3 src/import_list.py --in hosts.csv
python3 src/import_list.py --in ranges.csv --max-hosts 4096