한 줄 요약

"indexed-btree"라는 악성 npm 패키지가 기존의 설치 스크립트 방식 대신 라이브러리 내부 실행 코드에 악성 코드를 숨기는 새로운 수법을 사용해 발견되었습니다. 이는 npm 버전 12에서 설치 시 자동 실행 스크립트를 제한한 보안 강화 조치에 공격자들이 빠르게 적응한 것으로, 수백만 건의 다운로드와 약 2억 3천만 원(109 ETH) 상당의 암호화폐 수익이 발생한 것으로 추정됩니다. 악성코드는 감염된 시스템 정보를 Slack과 텔레그램으로 전송하고, 블록체인을 통해 추가 공격 도구를 내려받는 방식으로 동작합니다. 연관 패키지 10개도 함께 발견되어 모두 삭제되었으며, 북한 연계로 알려진 PolinRider 캠페인도 PHP 패키지 저장소 Packagist에서 70만 다운로드 패키지를 침해한 것으로 확인되었습니다. 개발자들은 설치 시점 검사만으로는 이런 위협을 막을 수 없으므로 런타임(실행 중) 행동 분석까지 병행해야 합니다.

사건

npm 패키지 'indexed-btree'가 BTree.prototype.set() 메서드 내부에 악성 로더를 숨겨 설치 스크립트 제한을 우회했으며, 북한 연계 PolinRider 캠페인은 Packagist 패키지 'visanduma/nova-two-factor'의 소스 저장소를 침해해 악성 코드를 삽입했습니다.

영향

indexed-btree 관련 캠페인으로 약 109 ETH(€230,933)의 암호화폐 수익이 발생한 것으로 추정되며, Packagist 패키지는 누적 70만 건 이상의 다운로드를 가진 프로젝트로 다수의 개발자 환경이 잠재적으로 노출되었습니다.

원인

npm v12의 lifecycle 스크립트 제한 강화에 대응해 공격자들이 악성 코드 삽입 위치를 라이브러리 런타임 코드 내부로 이동했으며, PolinRider는 개발자 계정 탈취 및 Git 히스토리 조작을 통해 저장소 자체를 침해했습니다.

대응

npm 및 Packagist에서 해당 패키지들이 삭제되었고, 보안 연구기관들이 관련 패키지 목록과 침해 지표를 공개했습니다. 설치 시점 검사에만 의존하지 말고 런타임 행동 분석을 추가하도록 권고합니다.

실무 포인트

설치 스크립트 차단과 같은 단일 보안 통제만으로는 부족하며, 패키지 설치 전·실행 중·배포 후 전 단계에 걸쳐 다층적 모니터링 체계를 갖춰야 합니다. 오픈소스 패키지 도입 시 런타임 동작 분석 도구를 병행 사용하고, 개발 도구(VS Code, IDE) 자동 실행 설정도 점검해야 합니다.

본문

"indexed-btree"라는 악성 npm 패키지가 라이프사이클 스크립트 대신 애플리케이션 코드 내부에 악성 행위를 숨기는 방식을 사용한 것으로 확인되었습니다. 이는 위협 행위자들이 최근의 보안 통제 강화에 대응해 전술을 바꾸고 있음을 시사합니다.

Checkmarx는 "indexed-btree는 정상적인 B-트리/인덱싱 유틸리티인 sorted-btree 패키지를 모방한 악성 npm 패키지"라며 "공급망 공간에서 흔히 볼 수 있는 공격들과 달리, 이 패키지는 preinstall / postinstall에 전혀 의존하지 않습니다. 대신 런타임에 애플리케이션 코드에서 완전히 실행됩니다"라고 밝혔습니다.

해당 패키지와 관련 GitHub 저장소는 현재 npm에서 다운로드할 수 없는 상태입니다. 그러나 통계에 따르면 이 패키지는 2026년 6월 18일 "charlessadler25"라는 npm 사용자에 의해 처음 등록되었으며, 짧은 기간에 수백만 건의 다운로드를 기록했습니다.

설상가상으로, 이 캠페인은 위협 행위자에게 암호화폐(즉, 109 ETH)로 약 €230,933.57의 불법 수익을 안겨준 것으로 보입니다.

이번 사례는 npm 버전 12가 preinstall 또는 postinstall과 같은 라이프사이클 스크립트의 자동 실행을 방지하는 보안 변경 사항을 도입한 이후 나온 것입니다. 이 스크립트들은 저장소를 통해 배포되는 패키지에서 악성 코드가 실행되는 가장 일반적인 방법 중 하나였습니다.

Checkmarx는 "합법적으로는 필요한 코드 컴파일, 데이터 시딩, 또는 필수 구성 설정에 자주 사용됩니다"라며 "그러나 위협 행위자들에게는 악성 패키지 설치 중 사용자 동의 없이 악성 코드를 자동으로 실행하는 데 자주 악용됩니다"라고 설명했습니다.

소프트웨어 공급망 보안 기업의 최신 연구 결과에 따르면, 악성 행위자들은 이 변경에 대응해 전술을 바꾸고 있으며, 설치 훅 대신 악성 코드를 라이브러리 내부에 직접 삽입하는 방식을 택하고 있습니다.

이번 사례에서 악성 코드 로더는 "BTree.prototype.set()" 메서드 안에 숨겨져 있으며, 이 메서드가 "sharedLoad.min.js"를 실행합니다. 이 JavaScript 페이로드는 악성 코드 1단계를 난독화하여 포함하고 있습니다.

악성 코드는 호스트 정보를 수집(핑거프린팅)하고, 하드코딩된 Slack 채널 및 텔레그램 봇으로 해당 정보를 전송하며, EtherHiding 기법을 사용해 Sepolia 테스트넷에 배포된 스마트 컨트랙트에서 암호화된 다음 단계 블롭(blob)을 가져와 최종적으로 2단계 페이로드를 구성합니다.

마지막 단계에서는 악성 아티팩트를 삭제하고 패키지 코드에서 트리거를 제거해 흔적을 지웁니다.

Checkmarx에 따르면 indexed-btree는 동일한 작전과 연관된 다수의 npm 패키지 중 하나이며, 해당 패키지들은 모두 npm에서 제거되었습니다.

  • ordered-kv-index
  • btree-leaderboard
  • priority-slot-queue
  • btree-range-store
  • btree-core
  • btree-time-index
  • btree-lru-cache
  • neighbor-key-map
  • sliding-score-window
  • mutex-forge

이 위협에 대응하기 위해 개발자들은 설치 시점 검사와 라이프사이클 스크립트 차단에만 의존하지 말고 런타임 행동 분석도 함께 활용할 것을 권고받고 있습니다.

SOCRadar의 CISO인 Ensar Seker는 The Hacker News와 공유한 성명에서 "이 캠페인이 특히 중요한 이유는 공격자들이 더 강화된 소프트웨어 공급망 방어 수단에 거의 즉각적으로 적응하는 모습을 보여주기 때문"이라며 "npm은 의존성 라이프사이클 스크립트를 제한해 설치 시점 보안을 개선했지만, 이 캠페인은 공격자들이 악성 실행을 합법적으로 보이는 런타임 기능 안으로 단순히 이동시킬 수 있다는 것을 보여줍니다"라고 말했습니다.

"더 넓은 교훈은 보안 통제가 근본적인 위협을 제거하는 것이 아니라 공격자의 행동을 변화시킨다는 것입니다. 라이프사이클 스크립트 차단은 중요한 개선이지만, 공격자들은 대안적인 실행 경로를 계속 찾을 것입니다. 따라서 방어자들은 설치 전, 실행 중, 배포 후 단계에서 악성 행동을 탐지할 수 있는 다층적 통제 수단이 필요합니다."

Packagist에서 PolinRider 재등장

이번 공개는 Socket이 북한 연계 악성 사이버 캠페인인 PolinRider의 일환으로, 누적 다운로드 70만 건 이상의 Packagist 패키지 "visanduma/nova-two-factor"의 "dev-main" 버전에서 악성 코드를 삭제했다고 밝힌 것과 동시에 이루어졌습니다.

PolinRider의 두드러진 특징은 위협 행위자가 개발자 계정을 침해해 소스 코드 저장소에 악성 콘텐츠를 삽입하고, 저장소 클론이나 IDE(통합 개발 환경)에서 열기와 같은 일상적인 개발자 행동을 감염 체인의 트리거로 활용한다는 점입니다.

이는 Git 히스토리 재작성, 설정 파일이나 폰트 파일 내 페이로드 은닉, 악성 VS Code 자동 실행 태스크 설정, 그리고 블록체인을 통한 단계적 페이로드 전달을 위해 테이크다운에 저항하는 EtherHiding 기법과 그 후계 기법인 스텔스 중심의 NullReceiver에 의존하는 방식을 포함합니다.

Socket의 보안 연구원 Karlo Zanki는 "Visanduma GitHub 조직 분석 결과, 해당 저장소들이 2026년 6월 중순부터 침해된 것으로 나타났습니다"라며 "악성 변경 사항은 LaHiRu 개발자 계정을 통해 도입되었습니다"라고 말했습니다.

최신 반복 버전에서 관찰된 주목할 만한 변화는 강하게 난독화된 JavaScript를 "index.php"에 직접 삽입하고 PHP의 "shell_exec()" 함수를 통해 실행한다는 점입니다. 이 방식은 PHP 진입점이 JavaScript 감염 체인을 호출할 수 있게 할 뿐만 아니라, 위협 행위자들이 고정된 전달 경로 대신 침해된 프로젝트에 맞춰 실행 방법을 적응시키고 있음을 시사합니다.

Socket은 "이 활동은 PolinRider의 핵심 특성을 재확인시켜 줍니다. 패키지 레지스트리 침해는 캠페인의 주요 목표가 아닌 더 광범위한 Git 기반 침입의 결과인 경우가 많습니다"라며 "운영자들은 일반적인 소스코드 협업을 활용해 개발자 환경에 접근하고, 추가 저장소로 확산하며, 장기간 접근을 유지합니다"라고 밝혔습니다.

"침해된 소스 저장소는 운영자들에게 기여자를 감염시키고, 비공개 프로젝트에 접근하고, 일반적인 개발 워크플로우를 통해 전파할 기회를 제공합니다. 패키지 배포는 침해된 저장소가 새 릴리즈를 생성할 때 추가적인 배포 경로가 됩니다."

출처
The Hacker News · thehackernews.com
원문 보기

분야별 뉴스

관심 분야의 보안 이슈를 모아 보세요.

TORUN SECURITY

투런이 제공하는 보안 솔루션

공격 표면 관리부터 엔드포인트·내부정보 보호까지, 기업 환경에 맞는 보안 솔루션을 투런이 함께 설계합니다.