Post

Shai-Hulud 2.0: 25,000개 이상의 GitHub 저장소를 감염시킨 NPM 공급망 공격

가짜 Bun 런타임을 통해 수천 개의 NPM 패키지를 감염시킨 자가 복제형 웜 악성코드 분석


Shai-Hulud 2.0: 25,000개 이상의 GitHub 저장소를 감염시킨 NPM 공급망 공격

원본 링크: Shai-Hulud Returns: Over 1K NPM Packages and 27K+ Github Repos infected via Fake Bun Runtime Within Hours

2025년 11월, NPM 생태계를 겨냥한 역대 최대 규모의 공급망 공격이 발생했습니다. “Shai-Hulud 2.0”이라 불리는 이번 공격은 단 몇 시간 만에 25,000개 이상의 GitHub 저장소와 수백 개의 NPM 패키지를 감염시켰습니다. 특히 가짜 Bun 런타임을 악용한 새로운 공격 기법으로 보안 커뮤니티에 큰 충격을 주고 있습니다.

공격 개요와 피해 규모

2025년 11월 21일부터 23일 사이, 트로이목마화된 NPM 패키지들이 대량으로 업로드되었습니다. 약 350명의 고유한 GitHub 사용자의 25,000개 이상의 저장소가 감염되었으며, 공격은 30분마다 약 1,000개의 새로운 저장소를 감염시키는 속도로 확산되었습니다.

주요 피해 사례로는 Zapier, ENS Domains, PostHog, Postman 등 유명 프로젝트들이 포함되었습니다. Wiz의 조사에 따르면 일부 감염된 패키지는 클라우드 및 코드 환경의 약 27%에 존재하는 것으로 확인되었습니다.

가짜 Bun 런타임을 통한 공격 메커니즘

이번 공격의 핵심은 Bun 런타임을 악용한 새로운 기법입니다.

1. Preinstall 스크립트 주입

공격자는 package.json 파일에 preinstall 스크립트를 추가합니다. setup_bun.js라는 드로퍼가 가짜 Bun 설치 프로그램으로 위장하여 실행됩니다. 이 스크립트는 시스템에 Bun 런타임을 은밀히 설치하거나 기존 Bun을 찾아 악성 스크립트를 실행합니다.

2. 대규모 난독화된 페이로드

bun_environment.js라는 10MB 크기의 악성 스크립트가 실행됩니다. 이 파일은 극도로 난독화되어 있으며 다음과 같은 기법을 사용합니다.

수천 개의 항목을 가진 대규모 hex 인코딩 문자열, 분석 방지 루프, 모든 문자열을 검색하는 난독화된 함수 등을 통해 보안 도구의 탐지를 회피합니다.

Bun 런타임을 선택한 이유는 명확합니다. Node.js에 비해 모니터링이 덜 이루어지며, 고성능과 자체 포함 아키텍처를 활용하여 대용량 페이로드를 더 은밀하게 실행할 수 있기 때문입니다.

자격 증명 탈취 및 데이터 유출

TruffleHog를 활용한 비밀 정보 스캔

악성코드는 실행되면 TruffleHog 비밀 스캐닝 도구를 다운로드하여 로컬 시스템을 스캔합니다. NPM 토큰, AWS/GCP/Azure 자격 증명, 환경 변수 등 민감한 정보를 수집합니다.

GitHub를 통한 데이터 유출

탈취한 정보는 다음과 같이 GitHub에 자동으로 유출됩니다.

“Sha1-Hulud: The Second Coming”이라는 설명이 달린 GitHub 저장소가 자동으로 생성되며, cloud.json, contents.json, environment.json, truffleSecrets.json 등의 파일에 탈취한 비밀 정보가 저장됩니다.

지속성 확보와 원격 접근

Self-Hosted GitHub Runner 등록

악성코드는 감염된 시스템을 ‘SHA1HULUD’라는 이름의 self-hosted runner로 등록합니다. 이후 .github/workflows/discussion.yaml이라는 워크플로우를 추가하여 공격자가 GitHub 저장소에서 discussion을 생성하는 것만으로 감염된 시스템에서 임의의 명령을 실행할 수 있게 됩니다.

컨테이너 탈출 및 권한 상승

악성코드는 다음 명령을 실행하여 루트 권한 획득을 시도합니다.

1
docker run --rm --privileged -v /:/host ubuntu bash -c "cp /host/tmp/runner /host/etc/sudoers.d/runner"

이 명령은 호스트의 루트 파일시스템을 특권 컨테이너에 마운트하여 악성 sudoers 파일을 복사함으로써 비밀번호 없이 루트 접근 권한을 부여합니다.

파괴적 기능

악성코드는 다음 상황에서 사용자의 전체 홈 디렉토리를 삭제하려고 시도합니다.

GitHub 인증 실패, GitHub 저장소 생성 실패, GitHub 토큰 획득 실패, NPM 토큰을 찾지 못한 경우 등입니다. 이는 공격 흔적을 제거하거나 분석을 방해하기 위한 것으로 보입니다.

대응 방안

즉시 조치 사항

의존성을 알려진 안전한 버전으로 고정하거나 2025년 11월 21일 이전 빌드로 롤백해야 합니다. NPM 토큰, GitHub PAT, SSH 키, 클라우드 프로바이더 자격 증명을 즉시 폐기하고 재생성해야 합니다.

장기 보안 강화

개발자 및 CI/CD 계정에 피싱 방지 MFA를 강제 적용하고, CI/CD에서 lifecycle 스크립트(postinstall, preinstall)를 제한하거나 비활성화해야 합니다. 의존성 검증 프로세스를 강화하고 패키지 설치 전 자동 스캔을 도입하는 것이 필요합니다.

마치며

Shai-Hulud 2.0 공격은 NPM 생태계에서 발생한 가장 심각한 공급망 공격 중 하나입니다. 자가 복제 능력과 Bun 런타임을 악용한 새로운 기법은 기존 보안 도구로는 탐지하기 어려운 위협입니다.

이번 사건은 오픈소스 생태계의 보안 취약성을 다시 한번 드러냈습니다. 개발자와 조직은 의존성 관리에 대한 근본적인 접근 방식을 재고하고, 다층 보안 전략을 구축해야 합니다.

Quick questions

Shai-Hulud라는 이름은 무엇을 의미하나요?

Shai-Hulud는 공상과학 소설 “듄(Dune)”에 등장하는 거대한 모래 벌레를 의미합니다. 이 악성코드가 자가 복제를 통해 빠르게 확산되는 특성을 비유적으로 표현한 것으로 보입니다.

일반 개발자도 이 공격의 영향을 받을 수 있나요?

네, 감염된 NPM 패키지 중에는 널리 사용되는 라이브러리도 포함되어 있어 일반 개발자도 영향을 받을 수 있습니다. package-lock.json을 확인하고 의심스러운 패키지 버전이 있는지 점검해야 합니다.

Bun 런타임 자체는 안전한가요?

Bun 런타임 자체는 안전한 도구입니다. 이번 공격은 Bun의 보안 문제가 아니라 악성코드가 Bun을 실행 환경으로 악용한 것입니다. Node.js 대신 Bun을 선택한 이유는 모니터링이 덜 이루어지기 때문입니다.

이 포스트는 블로그 주인장이 흥미롭다고 생각하는 주제를 AI를 통해 요약한 글입니다.
주인장이 개인적으로 읽으려고 만든게 맞으니 참고 바랍니다!


This post is licensed under CC BY 4.0 by the author.