
Shai-Hulud 공급망 공격에 대한 방어
Shai-Hulud 공급망 공격(2025년 9월 원본 및 2025년 11월 Shai-Hulud 2.0)으로부터 손상된 npm 패키지를 탐지하는 보안 도구입니다. package.json 및 package-lock.json 파일을 모두 스캔하여 정확한 설치 버전과 손상 지표(IoC)를 감지합니다. Python 및 Node.js 구현 모두에서 사용 가능하며, 중앙 집중식 YAML 구성을 통해 손쉬운 유지 관리가 가능합니다.
최신 업데이트: 2025년 11월 24일 - 738개 이상의 손상된 패키지 추적, 1,291개의 고유 package@version 조합. 이제 원본 Shai-Hulud와 Shai-Hulud 2.0 공격 변종을 모두 탐지합니다.
다중 생태계 스캔은 ore-mal-pkg-inspector를 참조하세요.
다중 생태계 악성 패키지 스캔(npm, PyPI, Maven, RubyGems, Go, Cargo)은 다음을 참조하세요. ore-mal-pkg-inspector - 동적 위협 인텔리전스를 갖춘 포괄적인 악성 패키지 스캐너.
OreNPMGuard는 npm 패키지에 대한 Shai-Hulud 공격 방어에 특화되어 있습니다.
Shai-Hulud는 2025년 9월 14~15일에 npm 패키지를 손상시키기 시작한 자가 복제 웜으로, npm 생태계에서 첫 번째로 성공한 자가 전파 공격이자 현재까지 관찰된 가장 심각한 JavaScript 공급망 공격 중 하나입니다. Frank Herbert의 Dune 시리즈에 등장하는 거대 모래벌레의 이름을 따서 명명된 이 악성코드는 여러 변종으로 진화했습니다.
원본 공격은 200개 이상의 npm 패키지(이 도구에서 추적 기준)를 감염시켰으며, 패키지당 여러 버전이 영향을 받았습니다.
2025년 11월에 등장한 새로운 변종으로, 중요한 변화가 있습니다.
postinstall뿐만 아니라 preinstall 스크립트 사용setup_bun.js 및 bun_environment.js (bundle.js에 추가)참조: Wiz Research - Shai-Hulud 2.0 블로그 게시물
Patient Zero: 손상된 "techsupportrxnt" npm 계정에 의해 2025년 9월 14일 17:58:50 UTC에 게시된 rxnt-authentication 패키지에서 공격이 시작되었습니다.
공격 체인 (원본 Shai-Hulud):
bundle.js(3MB 이상의 JavaScript 페이로드)를 실행하는 postinstall 스크립트 실행data.json(이중 base64 인코딩)이 있는 공개 "Shai-Hulud" 저장소 생성webhook[.]site로 유출하는 악성 GitHub Actions 워크플로(.github/workflows/shai-hulud-workflow.yml) 주입postinstall 후크 추가공격 체인 (Shai-Hulud 2.0 - 2025년 11월):
setup_bun.js 또는 bun_environment.js(새로운 페이로드 파일)를 실행하는 preinstall 스크립트 실행cloud.json, contents.json, environment.json, truffleSecrets.json 파일 생성.github/workflows/discussion.yaml 생성.github/workflows/formatter_*.yml 생성 (그런 다음 워크플로를 삭제하여 활동 숨기기)docker run --rm --privileged -v /:/host를 통해 루트 액세스 시도ghp_*, gho_*), npm 인증 토큰원본 Shai-Hulud (2025년 9월):
@ctrl/tinycolor, ngx-bootstrap 포함)Shai-Hulud 2.0 (2025년 11월):
확인된 자격 증명 도용(약 20,000개 분석된 저장소 기준):
중요: Wiz Research는 피해자 간 유출이 발생하고 있음을 확인했습니다. 즉,
조사 시사점: 저장소에서 유출된 데이터를 검토할 때, 데이터가 실제로 귀하의 조직에 속하는지 또는 다른 피해자의 것인지 확인하십시오.
이 공격은 2025년 8월의 s1ngularity/Nx 손상과 직접적으로 연결되며, 초기 GitHub 토큰 도용으로 더 광범위한 공급망 공격이 가능해졌습니다. 많은 초기 Shai-Hulud 피해자는 s1ngularity 공격의 알려진 피해자였습니다. 보안 연구원들은 또한 캠페인 내에서 AI 생성 콘텐츠의 통합을 지적하며, 악성 bash 스크립트를 생성하는 데 LLM이 사용되었을 가능성이 중간 수준으로 있다고 평가합니다.
원본 Shai-Hulud 캠페인:
rxnt-authentication 게시("Patient Zero")Shai-Hulud 2.0 캠페인:
PyYAML 필요 (pip install pyyaml)js-yaml 필요 (npm install js-yaml)# 실행 가능하게 만들기
chmod +x shai_hulud_scanner.py
# 단일 package.json 스캔
python3 shai_hulud_scanner.py ./package.json
# 정확한 버전을 위해 package-lock.json 스캔
python3 shai_hulud_scanner.py ./package-lock.json
# 전체 프로젝트 디렉토리 스캔
python3 shai_hulud_scanner.py ./my-project
# 현재 디렉토리 스캔
python3 shai_hulud_scanner.py .
# 먼저 종속성 설치
npm install
# 실행 가능하게 만들기
chmod +x shai_hulud_scanner.js
# 단일 package.json 스캔
node shai_hulud_scanner.js ./package.json
# 정확한 버전을 위해 package-lock.json 스캔
node shai_hulud_scanner.js ./package-lock.json
# 전체 프로젝트 디렉토리 스캔
node shai_hulud_scanner.js ./my-project
# 현재 디렉토리 스캔
node shai_hulud_scanner.js .
✅ 정확한 일치 탐지: 알려진 손상된 버전과 정확히 일치하는 패키지 식별
⚠️ 잠재적 위험 탐지: 동일한 이름이지만 다른 버전의 패키지 플래그 지정(여전히 위험할 수 있음)
🔍 이중 파일 지원: package.json(선언된 종속성) 및 package-lock.json(정확히 설치된 버전) 모두 스캔
📦 포괄적인 범위: package-lock.json 스캔에는 중첩된 종속성 및 전이 패키지 포함
🔄 재귀적 스캔: node_modules를 건너뛰면서 모든 하위 디렉토리 자동 스캔
📋 상세 보고: 패키지 이름, 버전, 종속성 섹션 및 영향을 받는 버전 표시
🔎 IoC 탐지: 원본 Shai-Hulud 및 Shai-Hulud 2.0 모두에 대한 손상 지표 식별:
"postinstall": "node bundle.js" 후크, bundle.js 파일, shai-hulud-workflow.yml"preinstall" 후크, setup_bun.js, bun_environment.js, discussion.yaml, formatter_*.yml 워크플로webhook.site 유출 엔드포인트 참조, SHA1HULUD 러너 패턴, Docker 권한 상승🚨 심각 (손상된 패키지 발견):
🚨 심각: 2개의 확인된 손상된 패키지를 발견했습니다:
• @ctrl/deluge v7.2.2 (dependencies)
영향을 받는 버전: 7.2.2, 7.2.1
• ngx-bootstrap v19.0.3 (devDependencies)
영향을 받는 버전: 18.1.4, 19.0.3, 20.0.4, 20.0.5, 20.0.6, 19.0.4, 20.0.3
⚠️ 경고 (버전 불일치):
⚠️ 경고: 다른 버전의 패키지 1개를 발견했습니다:
• @ctrl/deluge v7.2.0 (dependencies)
알려진 영향을 받는 버전: 7.2.2, 7.2.1
✅ 깨끗함:
✅ 영향을 받는 패키지가 없습니다
npm uninstall <package-name>npm cache clean --forcerm -rf node_modules"postinstall": "node bundle.js" 검색bundle.js 파일 찾기(3MB 이상, 악성 페이로드 포함).github/workflows/shai-hulud-workflow.yml 파일 검사"preinstall" 후크 검색setup_bun.js 및 bun_environment.js 페이로드 파일 찾기cloud.json, contents.json, environment.json, truffleSecrets.json.github/workflows/discussion.yaml 검사(자체 호스팅 러너 포함)패키지 데이터는 affected_packages.yaml에 중앙 집중화되어 있습니다. 새로운 손상된 패키지를 추가하려면:
affected_packages.yaml 편집- name: "package-name"
versions: ["1.0.0", "1.0.1"]
이 중앙 집중식 접근 방식은 새로운 위협이 발견될 때 여러 파일을 업데이트할 필요를 없앱니다.
# 중앙 스캔 스크립트 생성
curl -O https://your-domain.com/shai_hulud_scanner.py
chmod +x shai_hulud_scanner.py
# 여러 프로젝트 대량 스캔
for dir in /projects/*/; do
echo "$dir 스캔 중"
python3 shai_hulud_scanner.py "$dir"
done
# GitHub Actions 예제
- name: Shai-Hulud 패키지 스캔
run: |
curl -O https://your-domain.com/shai_hulud_scanner.js
npm install js-yaml
node shai_hulud_scanner.js .
if [ $? -ne 0 ]; then
echo "보안 경고: 손상된 패키지가 감지되었습니다!"
exit 1
fi
# 보안 툴킷에 추가
cp shai_hulud_scanner.py /usr/local/bin/
cp shai_hulud_scanner.js /usr/local/bin/
cp affected_packages.yaml /usr/local/bin/
# 쉬운 액세스를 위한 별칭 생성
echo 'alias scan-shai="python3 /usr/local/bin/shai_hulud_scanner.py"' >> ~/.bashrc
postinstall 사용, Shai-Hulud 2.0은 preinstall 사용(빌드 환경에서 노출 증가)원본 Shai-Hulud (2025년 9월):
"postinstall": "node bundle.js"bundle.js (일반적으로 3MB 이상 축소된 JavaScript)webhook.site 도메인 참조.github/workflows/shai-hulud-workflow.ymlshai-hulud 브랜치Shai-Hulud 2.0 (2025년 11월):
"preinstall": "node setup_bun.js" 또는 "preinstall": "node bun_environment.js"setup_bun.js, bun_environment.js (bundle.js에 추가)cloud.json, contents.json, environment.json, truffleSecrets.json.github/workflows/discussion.yaml (runs-on: self-hosted 및 RUNNER_TRACKING_ID: 0 포함).github/workflows/formatter_*.yml (패턴 일치, 비밀 유출에 사용됨)두 변종 공통:
webhook.site 도메인 참조preinstall 스크립트 감지(Shai-Hulud 2.0 실행 단계)setup_bun.js 및 bun_environment.js 스캔cloud.json, contents.json, environment.json, truffleSecrets.json 식별discussion.yaml 및 formatter_*.yml 워크플로 패턴 탐지prevention/block-shai-hulud.sh문제나 질문이 있는 경우:
.github/workflows/formatter_*.yml 파일 검사docker run --rm --privileged -v /:/host)webhook.site 참조 확인docker run --rm --privileged -v /:/host와 같은 명령어webhook.site 도메인 참조(원본과 동일)