BLOG

블로그

npm 패키지를 활용한 공격과 보안 대응 방안

  • 2025-05-12
  • npm 패키지를 활용한 공격과 보안 대응 방안


    개요

    Node.js는 JavaScript를 브라우저 외부에서 실행할 수 있도록 지원하는 런타임 환경으로, 다양한 서버 사이드 애플리케이션 개발에 널리 사용된다. 이때 Node.js 생태계의 중심에는 npm(Node Package Manager)이라는 공식 패키지 관리 도구가 존재한다. npm은 수많은 라이브러리와 패키지를 전 세계 개발자들이 공유하고 사용할 수 있도록 지원하며, 개발자가 손쉽게 의존성 패키지를 설치하고 관리할 수 있도록 한다.

    그러나 이러한 개방성과 편리성은 보안 위협이라는 문제점을 동반한다. npm에 등록된 방대한 패키지들 중 일부가 악의적으로 조작되거나, 의도하지 않게 악성 코드를 포함할 가능성이 존재하기 때문이다. 본 글에서는 npm의 개념과, 이를 악용한 실제 공격 사례, 그리고 대응 방안에 대해 다룬다.


    npm의 개념

    npm은 Node.js의 공식 패키지 관리 도구로, JavaScript 생태계에서 라이브러리와 모듈을 쉽게 설치, 관리할 수 있도록 한다. Python의 pip에 비유할 수 있으며, 수많은 개발자들이 직접 만든 패키지를 자유롭게 등록하고 배포할 수 있다. 이러한 구조 덕분에 npm은 방대한 생태계를 이루게 되었으나, 동시에 보안 상의 취약점을 내포하게 되었다.

    npm은 의존성 패키지를 자동으로 설치하는 방식으로 동작한다. 하나의 패키지를 설치할 때 그 패키지가 필요로 하는 다른 패키지들도 함께 설치된다. 이러한 의존성의 연쇄적 설치는 개발자가 최종적으로 설치된 모든 패키지를 직접 확인하거나 검증하기 어렵게 만든다. 결과적으로, 악의적인 패키지가 의존성으로 포함될 경우 사용자는 자신도 모르게 악성 코드를 설치하게 될 가능성이 존재한다.


    npm 패키지를 통한 공격의 위험성

    npm 생태계에서는 패키지의 자동 설치와 업데이트가 일반적인 방식으로 사용된다. 이는 의존성 관리를 자동화하여 개발 편의성을 제공하지만, 동시에 의존성 체인을 통한 공격이라는 위험을 유발한다. 사용자가 직접적으로 설치하지 않은 패키지라도, 의존성에 포함되어 있다면 설치 과정에서 악성 코드가 유입될 수 있다.

    특히 JavaScript 생태계의 특성상 의존성 관계가 매우 복잡하게 얽혀 있는 경우가 많아, 최종적으로 설치된 패키지가 몇 단계에 걸쳐 어떤 패키지를 불러왔는지 파악하기 어려운 상황이 발생한다. 이로 인해 악성 패키지가 숨겨진 채 설치 및 실행될 가능성이 높아진다.


    주요 공격 사례

    npm 패키지를 통한 공격 사례는 다양하게 보고되었으며, 그 방식과 목적 또한 다채롭다. 본 절에서는 대표적인 사례들을 살펴보고자 한다.


    1. 백도어가 삽입된 npm 패키지

    Reversing Labs에 따르면, ethers-provider2ethers-providerz라는 패키지에서 백도어가 발견되었다. 해당 패키지들은 ssh2를 기반으로 하며, install.js라는 설치 스크립트를 포함하고 있었다. install.js는 패키지 설치 과정에서 자동으로 실행되며, 외부 서버에서 2단계 페이로드를 다운로드하도록 설계되어 있었다.




    설치 시 install.js가 실행되면 외부 서버로부터 추가 페이로드가 다운로드되고 실행된다. 이 페이로드는 로컬에 설치된 ethers 패키지를 탐지한 뒤, provider-jsonrpc.js 파일에 3단계 악성 코드를 삽입한다. 이후 loader.js라는 파일을 생성하여 삽입된 악성 코드와 동일한 기능을 수행하는 코드를 작성하고 실행한다.

    최종적으로 삽입된 악성 코드는 ssh 클라이언트를 사용하여 공격자 서버에 접속하는 리버스 셸(reverse shell)을 구현한다. 이를 통해 공격자는 원격에서 피해자 시스템에 접근할 수 있게 된다.




    2. 정상 패키지를 하이재킹하여 민감 정보 수집

    Sonatype에 따르면, 암호화폐 관련 10개의 npm 패키지가 악성 코드로 변조되었다. 공격자는 해당 패키지에 난독화된 악성 스크립트를 삽입하여, 개발자의 시스템에서 API 키, 액세스 토큰, SSH 자격 증명 등을 수집하고 외부 서버로 전송하도록 했다.

    이 악성 스크립트는 luanch.jsdiagnostic-reports.js라는 두 개의 파일에 포함되었으며, 설치 시 자동으로 실행되었다. 수집된 정보는 sendToWebhook 함수에 의해 외부 서버로 POST 방식으로 전송되었다.



    해당 악성 패키지들은 다음과 같다.

    • country-currency-map 2.1.8
    • @keepkey/device-protocol 7.13.3
    • bnb-javascript-sdk-nobroadcast 2.16.16
    • @bithighlander/bitcoin-cash-js-lib 5.2.2
    • eslint-config-travix 6.3.1
    • babel-preset-travix 1.2.1
    • @travix/ui-themes 1.1.5
    • @veniceswap/uikit 0.65.34
    • @crosswise-finance1/sdk-v2 0.1.21
    • @veniceswap/eslint-config-pancake 1.6.2


    해당 패키지들은 현재 악성 코드가 포함되어 있지 않은 이전 버전으로 복구되었다.

    이 사건의 원인은 계정 탈취나 만료된 도메인 탈취로 추정된다. 특히 다수의 프로젝트에서 동시에 발생한 점을 고려할 때, 관리자의 계정 정보가 탈취되었을 가능성이 높게 평가된다.


    3. 라자루스 그룹의 npm 패키지를 이용한 공격

    북한의 사이버 공격 조직으로 알려진 라자루스(Lazarus)는 BeaverTail 악성코드 배포를 위해 악성 npm 패키지를 배포했다. 이 패키지들은 배열 처리, 로깅, 디버깅, 이벤트 처리, API 처리 등 일반적인 유틸리티 라이브러리로 위장했으나, 내부에는 C2 서버와 통신하는 악성 코드가 포함되어 있었다.

    라자루스는 일반적인 Base64 인코딩 대신 16진수 인코딩(hex encoding)을 사용하여 문자열을 은폐했다. 이는 정적 분석 도구나 수동 검토 시 악성 문자열 탐지를 어렵게 만들기 위한 기법이었다.

    function g(h) {
      return h.replace(/../g, match => String.fromCharCode(parseInt(match, 16)));
    }
    
    

    이렇게 은폐된 문자열을 디코딩하여 require, axios, get, then 등의 함수명과 C2 서버 URL 등을 프로그램 실행 시점에 동적으로 생성하였다.

    const hl = [
        g('72657175697265'),  // "require" — dynamic module import
        g('6178696f73'),      // "axios" — HTTP client
        g('676574'),          // "get" — HTTP GET method
        g('68747470...613662'), // C2 URL — hxxps://mocki[.]io/v1/32f16c80-602a-4c80-80af-32a9b8220a6b
        g('7468656e'),        // "then" — handles async response
    ];
    


    4. 암호화폐 지갑을 노린 악성 npm 패키지

    알려지지 않은 공격자들이 암호화폐 지갑 소프트웨어인 Atomic wallet과 Exodus에 악성코드를 주입하는 악성 npm 패키지를 게시했다. 해당 패키지는 pdf-to-office라는 패키지로, PDF파일을 Microsoft Office 문서로 변환 시 사용하는 라이브러리이다.

    해당 패키지가 설치, 실행되면, 로컬에 설치된 암호화폐 지갑 소프트웨어에 악성 코드를 주입하여 기존의 비 악성 파일을 덮어쓰게 되며, 다른 지갑으로 암호화폐 자금을 송금을 시도할 때 피해자는 보내고자 하는 주소가 공격자의 암호화폐 주소로 바뀌게 되어 암호화폐를 탈취당하게 된다.

    정상파일과 감염된 파일 차이


    코드가 실행되면 우선 0x59578f함수를 통해 Atomic Wallet의 설치 여부와 디렉토리 하위에 app.asar파일이 존재하는 지를 확인한다.

    asar 확장자는 Electron 애플리케이션을 패키징할 때 사용하는 아카이브 파일 형식이다. 이후 해당 파일이 존재하면 동일한 경로에 output이란 디렉토리를 생성 후, extratAll함수를 통해 app.asar파일의 압축을 해제한다.

    그 다음 공격자가 악성으로 제작한 js파일(a_2_9X_X.js)을 원래 존재하던 파일(vendors.XXXXX.js)에 덮어 씌운 후, 다시 패키징을 진행하여 원래 있던 asar패키지에 덮어 씌운다. 이후 공격자가 생성한 output디렉토리를 삭제하고 post메소드로 피해자의 홈 디렉토리와 type: A라는 패킷을 전송한다.

    추가된 코드를 통해 피해자가 암호화폐를 전송하려고 할 때, 인코딩 된 지갑주소를 디코딩 한 후 삽입하여 암호화폐를 가로챈다.


    5. 페이팔 사용자를 겨냥한 악성 npm 패키지

    공격자는 oauth2-paypal, buttonfactoryserv-paypal 등의 이름으로 패키지를 등록하여 PayPal 관련 키워드를 의도적으로 포함시켰다. 이는 개발자들이 신뢰할 수 있는 PayPal 관련 라이브러리로 착각하도록 유도하기 위한 목적이었다.

    이 악성 패키지는 설치 시 postResponse 함수를 통해 피해자의 PayPal 계정 정보와 암호화폐 전송 데이터를 공격자 서버로 전송하도록 구성되어 있었다.


    npm 보안 대응 방안

    npm 생태계의 보안 위협에 대응하기 위해서는 다음과 같은 방안을 실천해야 한다.


    1. npm 패키지 하이재킹 방지

    npm 패키지 관리자는 계정 보안을 강화하여 계정 탈취를 예방해야 한다. 이를 위해 2단계 인증(2FA) 활성화, 강력한 비밀번호 사용, 주기적인 비밀번호 변경, 소유 도메인 만료 여부 확인 등의 조치를 취해야 한다. 또한 패키지 접근 권한을 최소화하여 불필요한 권한 노출을 방지해야 한다.


    2. SBOM 작성과 관리

    npm 생태계에서는 의존성 관계가 복잡하여 최종적으로 어떤 패키지가 설치되었는지 파악하기 어렵다. 따라서 **SBOM(Software Bill of Materials)**을 작성하여 설치된 패키지의 이름, 버전, 출처 등을 체계적으로 기록하고 관리해야 한다.

    SBOM은 소프트웨어에 포함된 오픈소스, 라이브러리, 컴포넌트의 정보를 목록화한 문서로, 소프트웨어 공급망의 투명성을 확보하고 보안을 강화하는 데 필수적이다.


    SBOM의 필요성


    목적설명
    보안취약한 오픈소스를 빠르게 파악할 수 있다
    투명성소프트웨어 공급망을 추적할 수 있다
    라이선스 관리오픈소스 라이선스 준수를 확인할 수 있다
    규제 대응미국 EO 14028 등의 규제 준수에 대응할 수 있다

    SBOM 주요 요소

    SBOM에는 다음과 같은 정보가 포함된다.

    • 패키지명
    • 버전
    • 공급자
    • 파일 경로
    • 해시값
    • 라이선스 정보
    • 의존성 관계

    SBOM은 SPDX, CycloneDX, SWID 등의 표준 포맷으로 작성되며, JSON 또는 XML 형식으로 표현된다.

    SBOM 생성 도구

    대표적인 SBOM 생성 도구로는 Syft, SPDX tools, CycloneDX CLI, Trivy, GitHub Actions 등이 있다.


    도구특징
    SyftCLI 기반, Docker 이미지 분석 지원
    SPDX toolsSPDX 포맷 지원
    CycloneDX CLIOWASP 기반, 보안 중심
    Trivy컨테이너 보안 검사 및 SBOM 생성 지원
    Github ActionsCI 파이프라인에서 SBOM 자동 생성


    결론

    npm 생태계는 개발자에게 편리함과 생산성을 제공하는 동시에, 보안 취약성을 동반한다. 악성 npm 패키지를 통한 공격은 점차 교묘하고 정교해지고 있으며, 개인과 조직 모두 이에 대한 대응책을 마련해야 한다.

    계정 보안을 강화하고, SBOM을 통해 패키지 공급망을 관리함으로써 npm의 보안 위협에 선제적으로 대응할 필요가 있다. npm 생태계를 안전하게 활용하기 위해 이러한 노력이 필수적이다.