들어가며
2026년 3월 31일, JavaScript 생태계에서 가장 많이 사용되는 HTTP 클라이언트 라이브러리 axios가 해킹당했다. 주간 다운로드 수 약 1억 건에 달하는 이 패키지의 메인테이너 계정이 탈취되어, 원격 접근 트로이(RAT)가 삽입된 악성 버전이 npm에 배포된 것이다.
더 충격적인 것은 이 공격의 배후가 북한 연계 해킹 그룹 UNC1069로 지목되었다는 점이다. 2024년의 xz-utils 백도어 사건에 이어, 오픈소스 공급망 보안에 대한 경각심을 다시 한번 일깨운 초대형 보안 사고를 기술적으로 분석한다.
1. 사건 타임라인
| 시간 (UTC) | 사건 |
|---|---|
| 3월 30일 ~ | 메인테이너 jasonsaayman 계정 탈취 (이메일이 ProtonMail로 변경됨) |
| 3월 31일 00:21 | axios@1.14.1 배포 (latest 태그) |
| 3월 31일 01:00 | axios@0.30.4 배포 (legacy 태그) |
| 3월 31일 01:50 | Elastic Security Labs가 GitHub 보안 어드바이저리 제출 |
| 3월 31일 03:15 | npm이 악성 패키지 삭제 |
| 3월 31일 ~ | Socket Security가 최초 공개 경보 발령 |
공격자는 latest와 legacy 두 태그 모두에 악성 버전을 게시함으로써, 신규 설치와 레거시 프로젝트 모두를 타겟으로 삼았다. 약 3시간 동안 악성 버전이 공개 상태로 유지되었다.
2. 공격 메커니즘 상세 분석
2-1. Stage 1: plain-crypto-js 드로퍼
악성 axios 버전에는 plain-crypto-js@4.2.1이라는 새로운 의존성이 추가되었다. 이 패키지의 postinstall 훅이 핵심이다.
// npm의 postinstall 라이프사이클 훅을 악용
// 패키지 설치 시 사용자 상호작용 없이 자동 실행됨
"scripts": {
"postinstall": "node setup.js"
}
setup.js는 2단계 난독화를 사용했다:
- Layer 1: 문자열 역순 배치 + Base64 디코딩
- Layer 2: XOR 암호화 (키:
OrDeR_7077, 위치 기반 인덱싱)
모든 주요 문자열, URL, 명령어가 인코딩된 배열에 저장되어 런타임에 복호화되므로, 정적 분석으로는 탐지가 어려웠다.
2-2. 플랫폼 감지 및 페이로드 전달
드로퍼는 os.platform()으로 운영체제를 감지한 후, C2 서버로 HTTP POST 요청을 전송한다:
| 플랫폼 | 요청 경로 | 페이로드 |
|---|---|---|
| macOS | packages.npm.org/product0 |
C++ 바이너리 (com.apple.act.mond) |
| Windows | packages.npm.org/product1 |
PowerShell 스크립트 (6202033.ps1) |
| Linux | packages.npm.org/product2 |
Python 스크립트 (ld.py) |
C2 서버 주소는 sfrclak[.]com:8000이며, 요청 경로를 npm 레지스트리 트래픽처럼 위장했다.
2-3. 안티포렌식 기법
공격자는 흔적 제거에도 신경을 썼다:
fs.unlink(__filename)으로 드로퍼 자기 삭제- 악성
package.json을 정상package.md로 덮어씌움 node_modules안에는 증거가 남지 않으며, lockfile과 npm audit 로그에만 흔적이 남음
3. Stage-2 RAT 임플란트 분석
3개 플랫폼 모두 동일한 스펙의 RAT가 설치되었다. 구현 언어만 다를 뿐(PowerShell, C++, Python), 핵심 동작은 동일하다.
공통 특성
// RAT 공통 스펙
- HTTP POST 기반 C2 통신 (Base64 인코딩 JSON)
- User-Agent: "mozilla/4.0 (compatible; msie 8.0;
windows nt 5.1; trident/4.0)"
- 비콘 주기: 60초
- 세션 UID: 16자리 랜덤 영숫자
- 아웃바운드: FirstInfo, BaseInfo, CmdResult
- 인바운드: kill, peinject, runscript, rundir
특이한 점은 User-Agent가 IE8/Windows XP 시절의 것이라는 점이다. macOS나 Linux에서 이 User-Agent가 나타나면 즉시 이상 탐지가 가능한 강력한 탐지 지표가 된다.
초기화 및 정찰
RAT 실행 시 다음 순서로 동작한다:
- 16자리 랜덤 세션 UID 생성
- OS/아키텍처 감지 (windows_x64, macOS, linux_x64)
- 주요 디렉토리 열거 (프로필, 문서, 데스크톱, 설정)
- FirstInfo 비콘 전송 (UID, OS, 디렉토리 스냅샷)
이후 수집하는 시스템 정보: 호스트명, 사용자명, OS 버전, 시간대, 부팅 시간, 설치일, 하드웨어 모델, CPU 타입, 전체 프로세스 목록.
명령어 세트
| 명령 | 기능 | 플랫폼별 구현 |
|---|---|---|
kill |
자기 종료 | Windows: 레지스트리 키 + 배치파일 영속성은 유지됨 |
runscript |
코드 실행 | Win: PowerShell (-NoProfile -ep Bypass) Mac: osascript Linux: Shell/Python |
peinject |
바이너리 페이로드 | Win: .NET 리플렉션 로드 Mac/Linux: Base64 디코딩 후 실행 |
rundir |
파일시스템 탐색 | 파일명, 크기, 타입, 타임스탬프, 하위 항목 수 |
4. 배후: 북한 해킹 그룹 UNC1069
Google Threat Intelligence Group(GTIG)과 Mandiant가 공동으로 분석한 결과, macOS 변종이 WAVESHAPER.V2 백도어와 상당한 유사성을 보였다. WAVESHAPER는 Mandiant가 추적하는 UNC1069(북한 연계 위협 그룹)의 시그니처 도구로, 2018년부터 활동이 확인되었다.
북한 해킹 그룹이 npm 생태계를 타겟으로 삼은 것은 이번이 처음이 아니다. 하지만 주간 1억 다운로드급 패키지의 메인테이너 계정을 직접 탈취한 것은 공급망 공격의 심각성을 보여주는 사례다.
5. 영향 범위와 IOC
영향받은 버전
| 구분 | 버전 | 비고 |
|---|---|---|
| 악성 | axios@1.14.1 |
latest 태그 |
| 악성 | axios@0.30.4 |
legacy 태그 |
| 악성 | plain-crypto-js@4.2.1 |
드로퍼 패키지 |
| 안전 | axios@1.14.0 |
마지막 정상 1.x (SLSA 검증됨) |
| 안전 | axios@0.30.3 |
마지막 정상 0.30.x |
침해 지표 (IOC)
# SHA-256 해시
Windows: 617b67a8e1210e4fc87c92d1d1da45a2f311c08d
26e89b12307cf583c900d101
macOS: 92ff08773995ebc8d55ec4b8e1a225d0d1e51efa
4ef88b8849d0071230c9645a
Linux: fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa
551af135a8402bf980375cf
# C2 인프라
Domain: sfrclak[.]com
IPv4: 142.11.206[.]73
6. 내 프로젝트가 영향받았는지 확인하는 법
다음 명령어로 즉시 확인할 수 있다:
# 1. 설치된 axios 버전 확인
npm ls axios
# 2. lockfile에서 악성 버전 검색
grep -r "1.14.1\|0.30.4" package-lock.json
# 3. plain-crypto-js 존재 여부 확인
grep "plain-crypto-js" package-lock.json
# 4. npm audit 실행
npm audit
# 5. 네트워크 로그에서 C2 통신 확인
# macOS/Linux
grep -r "sfrclak" /var/log/ 2>/dev/null
netstat -an | grep "142.11.206.73"
영향받았다면?
- 즉시 안전한 버전으로 업그레이드:
npm install axios@1.14.0 - npm lockfile에서 postinstall 훅 실행 이력 감사
- C2 인프라로의 네트워크 송신 모니터링
- Windows:
%TEMP%디렉토리의 배치파일 + 레지스트리 영속성 키 확인 - Linux/macOS:
/tmp디렉토리의 숨겨진 실행 파일 스캔
7. 개발자를 위한 공급망 보안 체크리스트
이번 사건을 계기로, 모든 Node.js 개발자가 점검해야 할 항목들이다:
의존성 관리
# package.json - 정확한 버전 고정
"dependencies": {
"axios": "1.14.0" // "^1.14.0" 대신 정확한 버전 사용
}
# .npmrc - 자동 postinstall 차단
ignore-scripts=true
# 설치 후 명시적으로 스크립트 실행
npm rebuild
CI/CD 파이프라인
- SLSA 프로비넌스 검증:
npm audit signatures로 패키지 출처 확인 - 의존성 잠금:
package-lock.json을 반드시 커밋하고, CI에서npm ci사용 - 보안 스캔 자동화: Socket, Snyk, npm audit를 파이프라인에 통합
- 네트워크 모니터링: 빌드 환경에서 의심스러운 외부 통신 차단
계정 보안
- npm 계정에 2FA(TOTP) 필수 적용
- 팀 관리: publish 권한을 최소 인원에게만 부여
- npm token 주기적 갱신 및
npm token list로 활성 토큰 관리
마치며
2024년 xz-utils 백도어, 그리고 이번 axios 공급망 공격. 패턴은 명확하다. 오픈소스 메인테이너 한 명의 계정이 곧 수억 개 프로젝트의 보안 경계선이라는 것이다.
우리가 매일 npm install로 설치하는 패키지들은 대부분 소수의 메인테이너가 관리한다. 그리고 국가 단위의 해킹 그룹은 바로 이 약한 고리를 노린다.
지금 당장 할 수 있는 일은 간단하다:
npm ls axios로 내 프로젝트 확인.npmrc에ignore-scripts=true추가- CI/CD에
npm audit통합 - npm 계정 2FA 활성화
npm install 한 줄이 당신의 서버에 백도어를 설치할 수 있다는 사실을 잊지 말자.