[태그:] 공급망 공격

  • Claude 확장 백도어, 감염 점검과 업데이트 설정

    Claude 확장 백도어, 감염 점검과 업데이트 설정

    3줄 요약

    • Cursor 마켓플레이스의 Anthropic 공식 계정으로 Claude VS Code 확장의 악성 버전 2.1.313이 배포됐습니다. Cursor는 영향을 받은 사용자를 최대 5,000명으로 봤습니다. 확장 자동 업데이트가 기본값이어서 사용자가 아무것도 하지 않아도 설치될 수 있었습니다.
    • 백도어가 SSH 키를 추가하는 단계는 관리자 권한으로 실행하지 않았다면 코드 오류로 실패했습니다. 하지만 기기 정보 전송과 지속성 설치는 이 단계와 상관없이 시도됐습니다. 확장을 새 버전으로 바꿔도 시스템에 남은 흔적은 직접 지워야 합니다.
    • 점검은 지속성(LaunchAgent·예약 작업) → authorized_keys와 SSH 서비스 → 외부 통신 흔적 → 자격 증명 교체 순서로 합니다. 예방하려면 자동 업데이트를 ‘확인 후 수동 적용’으로 바꾸고, IDE를 관리자 권한으로 실행하지 않아야 합니다.

    SSH 백도어가 든 확장을 올린 건 정체불명의 배포자가 아니었습니다. Cursor 마켓플레이스에 등록된 Anthropic의 공식 계정이었거든요. 그 계정으로 배포된 Claude VS Code 확장 2.1.313은 개발자 PC에 SSH 백도어를 심으려 했고, Ars Technica 보도에 따르면 12시간 가까이 배포됐습니다. Cursor가 집계한 영향 사용자는 최대 5,000명.

    확장을 고를 때 흔히 보는 건 게시자 이름, 다운로드 수, 평점 정도인데요. 이번엔 이런 신뢰 신호가 아무 경고도 주지 못했습니다. 게시자는 진짜 공식 계정이었고, 같은 확장의 새 버전이었으니 다운로드 수나 평점이 달라질 이유도 없었으니까요. 더 큰 문제는 확장이 IDE와 같은 권한으로 돈다는 점입니다. 확장 업데이트 한 번이면 소스 코드와 자격 증명 전체에 접근할 수 있게 되는 구조예요.

    공식 계정이 뚫리면 악성 코드도 정상 업데이트 경로로 들어온다

    공급망 공격은 사용자를 직접 노리지 않습니다. 사용자가 이미 믿고 쓰는 소프트웨어, 그 배포 과정 한가운데에 끼어드는 방식이에요. 보안 업체 Phorion의 공동창업자이자 CTO인 루크 로버츠(Luke Roberts)도 이번 사건을 “공격자가 공식 배포 채널의 접근 권한을 얻은 공급망 공격”이라고 설명했습니다. 악성 버전 2.1.313은 Anthropic 공식 계정에 올라가, 바로 앞의 정상 버전 2.1.312를 밀어내고 그 자리를 차지했습니다.

    피해를 키운 건 자동 업데이트였습니다. 로버츠에 따르면 Cursor는 확장을 기본적으로 자동 업데이트하고, 설정에서 이걸 바꿀 수 있는데요. 기본값을 건드리지 않았다면 확장을 새로 깔지 않았어도, 편집기를 켜 두기만 했는데 2.1.313을 받았을 수 있다는 얘기입니다. 사용자는 아무것도 안 했는데 감염 경로는 열려 있었던 셈이죠. 독립 보안 연구자 케빈 보몬트(Kevin Beaumont)에 따르면 Anthropic은 몇 시간 뒤 2.1.314를 배포했습니다. 공격자가 계정을 어떻게 장악했는지는 Cursor도, Anthropic도 설명하지 않았고요.

    확장 하나가 왜 이렇게까지 위험할까요. 권한 구조 때문입니다. VS Code 계열 편집기의 확장에는 별도 샌드박스가 없어요. 편집기를 실행한 OS 사용자 계정의 권한을 그대로 씁니다. Cursor도 마찬가지라 확장은 IDE 권한으로 실행되고, 설치되는 순간 로컬 파일, 소스 코드, 터미널, Git 같은 개발 도구에 바로 손이 닿습니다. 게시자를 확인하는 습관은 모르는 사람이 만든 확장을 거르는 데는 쓸모가 있어요. 정상 게시자의 계정이 탈취된 경우엔 소용이 없고요. 이번이 딱 그 경우였습니다.

    악성 버전 2.1.313이 시도한 네 가지 동작과 실제 결과

    Cursor의 분석을 보면 악성 코드는 Windows, macOS, Linux 어디서든 돌도록 짜여 있었습니다. 노린 건 지속형 백도어. 공격자의 SSH 키를 등록하고, 로컬 SSH 서비스를 켠 다음, 역방향 SSH 터널을 여는 구성이었습니다. 동작별로 쪼개 보면 이렇습니다.

    동작 세부 내용 분석 결과
    기기·사용자 정보 수집 호스트 이름, 사용자 이름, OS, 아키텍처, 홈 디렉터리 경로, 환경 변수 이름, 작업 디렉터리, Git에 설정된 이메일, 공인 IP 환경 변수 이름만으로 클라우드 자격 증명과 API 토큰을 가진 기기를 골라낼 수 있음(Phorion)
    SSH 백도어 설치 공격자 SSH 키를 authorized_keys에 추가, 로컬 SSH 서비스 활성화, 역방향 SSH 터널 개방 Cursor를 관리자 권한으로 실행한 예외적인 경우가 아니면 코드 오류로 실패. 역방향 셸이 접속하던 서버는 Cursor가 호스팅 업체와 협력해 차단
    지속성 확보 macOS는 LaunchAgent, Windows는 SYSTEM 권한 예약 작업(실패하면 시작 스크립트로 대체) 백그라운드 스크립트가 약 60초마다 터널 연결을 재시도. Windows·macOS 코드의 버그로 일부 경우에는 작동하지 않음
    상태 보고 기기 정보와 백도어 상태를 8099번 포트의 /beacon 경로로 HTTP POST 전송 코드에 결함이 있어도 지속성 설치와 정찰 정보 전송은 이뤄지므로 여전히 중대한 위협(Phorion)

    이 표에서 놓치면 안 되는 게 하나 있습니다. 실패했다고 안전한 건 아니라는 점이에요. SSH 키 추가는 대부분의 환경에서 실패했지만, 정보 수집과 지속성 설치는 그 단계와 따로 굴러갑니다. 원격 셸이 안 열렸더라도 내 기기 정보는 이미 공격자에게 넘어갔을 수 있다는 뜻이죠.

    가장 눈여겨볼 대목은 환경 변수 이름 수집입니다. 값을 빼 갈 필요도 없어요. AWS_ACCESS_KEY_ID나 GITHUB_TOKEN 같은 이름만 봐도 그 기기에 어떤 클라우드 자격 증명과 API 토큰이 있는지 목록이 나오거든요. Phorion은 공격자가 이 목록으로 후속 공격 대상의 우선순위를 매기려 했을 것으로 봤습니다. 개발자 PC가 일반 사무용 PC보다 노릴 가치가 큰 표적인 이유가 바로 여기 있습니다. 변수 이름 몇 줄이 다음 공격의 지도 노릇을 하는 셈이고요.

    감염 여부는 확장 버전이 아니라 시스템에 남은 흔적으로 본다

    자동 업데이트를 켜 뒀다면 확장 버전은 이미 2.1.314 이후로 바뀌어 있을 가능성이 큽니다. 버전만 보고 ‘괜찮네’ 하고 넘어가면 곤란한 이유예요. LaunchAgent와 예약 작업은 확장 폴더 밖에 만들어지기 때문에, 확장을 업데이트하든 삭제하든 그대로 남아 있다고 보는 게 안전합니다. 버전은 영향 대상인지 가늠하는 데만 쓰고, 감염 여부는 흔적으로 판단하세요.

    기준이 되는 시간대는 미국 동부시간 오전 5시 27분부터 오후 4시 35분까지입니다. 악성 버전이 배포된 이 시간 동안 Cursor에서 이 확장을 설치하거나 업데이트했다면 영향을 받은 걸로 간주해야 하고, 그 전후에 업데이트한 경우도 감염 가능성을 열어 두는 편이 좋습니다. Cursor와 Phorion이 IP 주소와 파일 해시 같은 침해 지표(IOC)를 공개했으니, 아래 점검 결과를 그 목록과 하나씩 대조해 보세요. 아래 경로는 각 OS의 기본 설정 기준이고, OS 버전에 따라 화면 구성이 조금 다를 수 있습니다.

    공통: 확장 버전 확인

    • Cursor의 확장 뷰(Windows·Linux Ctrl+Shift+X, macOS Cmd+Shift+X)에서 Anthropic의 Claude 확장을 선택하면 상세 화면에 버전 번호가 뜹니다.
    • 터미널이 편하다면 cursor --list-extensions --show-versions로 목록을 뽑을 수 있어요. 단, Cursor 셸 명령이 PATH에 등록돼 있어야 하고, 이 옵션이 Cursor에서도 VS Code와 똑같이 동작하는지는 검증되지 않았습니다.

    macOS

    • ls -la ~/Library/LaunchAgents로 사용자 LaunchAgent 목록을 열고, 설치한 기억이 없는 .plist 파일과 그 생성 시각을 봅니다. 시스템 전체에 적용되는 /Library/LaunchAgents도 같이 확인하세요.
    • launchctl list를 실행해 지금 로드된 에이전트 중 이름이 낯선 항목을 찾습니다.
    • 시스템 설정 → 일반 → 공유 → 원격 로그인(macOS 12 이하는 시스템 환경설정 → 공유 → 원격 로그인)을 확인합니다. 켠 적이 없는데 켜져 있다면 의심 신호예요.
    • cat ~/.ssh/authorized_keys로 모르는 공개 키가 들어가 있지 않은지 봅니다.

    Windows

    • Win+R → taskschd.msc → 작업 스케줄러 라이브러리. 배포 시간대 이후에 만들어졌고 실행 계정이 SYSTEM인 낯선 작업이 있는지 살핍니다.
    • Win+R → shell:startup과 shell:common startup을 차례로 열어, 시작 프로그램 폴더에 낯선 스크립트 파일이 없는지 봅니다. 예약 작업 생성에 실패하면 시작 스크립트로 대체하도록 짜여 있었으니 이 폴더도 빼먹으면 안 됩니다.
    • 설정 → 시스템 → 선택적 기능(Windows 10과 초기 Windows 11은 설정 → 앱 → 선택적 기능)에서 ‘OpenSSH 서버’가 설치돼 있는지 확인하고, services.msc에서 ‘OpenSSH SSH Server’ 서비스 상태를 봅니다.
    • %USERPROFILE%\.ssh\authorized_keys를 엽니다. 관리자 그룹 계정이라면 Windows OpenSSH가 쓰는 C:\ProgramData\ssh\administrators_authorized_keys까지 확인해야 합니다.

    Linux

    • cat ~/.ssh/authorized_keys로 등록된 키를 확인합니다.
    • systemctl status ssh(Debian·Ubuntu) 또는 systemctl status sshd(Fedora·RHEL 계열)로 SSH 서비스가 켜져 있는지, 언제 활성화됐는지 봅니다.
    • Linux에서 쓰인 지속성 방식은 분석 자료에 구체적으로 나오지 않았습니다. 일반적인 자동 실행 위치인 crontab -l, systemctl --user list-unit-files, ~/.config/autostart를 함께 훑어보세요.

    공통: 외부 통신 흔적

    • macOS·Linux는 lsof -nP -i :8099, Windows는 netstat -ano | findstr :8099를 실행합니다. 결과에 PID가 나오면 작업 관리자의 ‘세부 정보’ 탭에서 찾아볼 수 있어요.
    • 역방향 셸 서버가 차단돼 있으니 연결 자체는 실패할 겁니다. 그래도 스크립트는 약 60초마다 재시도하거든요. 방화벽이나 보안 제품 로그에 IOC 목록의 IP로 향하는 반복 연결 시도가 남아 있다면, 지속성이 설치됐다는 신호로 보면 됩니다.

    흔적이 나왔다면 차단, 제거, 자격 증명 교체 순으로

    1. 통신 차단: 네트워크 연결을 끊거나, 방화벽에서 IOC 목록의 IP와 8099번 포트로 나가는 연결을 막습니다. Cursor가 서버를 차단하긴 했지만 공격자가 다른 서버로 옮겨 갈 수도 있어요. 로컬에서 한 번 더 막아 두는 편이 낫습니다.
    2. 지속성 제거: macOS는 launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/파일명.plist로 에이전트를 내린 다음 파일을 지웁니다. Windows는 작업 스케줄러에서 해당 작업을 삭제하고, 시작 프로그램 폴더의 스크립트도 함께 지우세요. 지우기 전에 파일 사본을 따로 챙겨 두면 좋습니다. 해시를 IOC와 대조하거나 보안 담당자에게 넘길 때 쓸 수 있거든요.
    3. SSH 정리: authorized_keys에서 모르는 키가 적힌 줄을 지웁니다. 원격 로그인을 쓸 일이 없다면 SSH 서비스를 끄고 OpenSSH 서버도 제거하세요.
    4. 자격 증명 교체: 공격자 손에 환경 변수 이름 목록이 들어갔습니다. 셸 설정 파일(~/.zshrc, ~/.bashrc)과 프로젝트의 .env에 있는 클라우드 키, API 토큰, Git 토큰부터 다시 발급하세요. 수집된 건 이름뿐이라도, 악성 확장은 IDE 권한으로 파일을 읽을 수 있었습니다. 값까지 노출됐다고 가정하는 게 맞습니다.
    5. 피해 범위 판단: Cursor를 관리자 권한으로 실행한 적이 있다면 얘기가 달라집니다. SSH 키 추가 단계가 성공했을 수 있거든요. 이 경우엔 외부에서 셸 접근이 가능했다고 보고 OS 재설치까지 검토하세요. 회사 기기라면 혼자 처리하지 말고 보안 담당 부서에 먼저 알리는 게 순서입니다. 그 기기에서 접근할 수 있던 저장소와 클라우드 계정의 감사 로그도 확인해야 하고요.

    Git 이메일이 수집됐다는 점도 그냥 넘기긴 어렵습니다. 이메일, 사용자 이름, 작업 디렉터리 경로가 한데 모이면 특정 회사나 프로젝트를 겨냥한 피싱 메일을 만들기가 훨씬 쉬워지니까요. 다만 이건 실제 악용 사례가 보고된 게 아니라, 수집 항목을 보고 추정한 위험입니다.

    국내 사용자도 판단 기준은 같고, 조직엔 숙제가 더 있다

    Cursor 마켓플레이스가 지역마다 다른 버전을 배포했다는 정보는 없습니다. 국내 사용자도 해외 사용자와 같은 기준으로 보면 돼요. 배포 시간대, 자동 업데이트 설정, 그리고 그 시간대에 Cursor를 실행했는지. 이 세 가지입니다.

    • 공지를 기다리지 않는다: Ars Technica 보도 시점까지 Anthropic은 고객에게 공개 경고를 내지 않았습니다. 한국어 안내가 따로 나오길 기다리느니, Cursor 공지와 Phorion이 공개한 IOC를 직접 대조하는 쪽이 빠릅니다.
    • 사내 보안 솔루션이 놓쳤을 가능성(추정): 악성 동작이 Cursor라는 정상 프로세스 안에서 일어났기 때문에, 백신이나 EDR이 이상 행위로 판단하지 못했을 수 있습니다. 보안팀에 IOC를 넘기고 기기 전체를 검색해 달라고 요청하는 게 가장 확실한 방법이에요.
    • IDE 확장도 승인 대상에 넣기(제안): 설치 프로그램은 승인 절차를 거치게 하면서 편집기 확장은 개인 재량에 맡기는 조직이 적지 않을 것으로 추정됩니다. 공식 게시자의 확장도 오염될 수 있다는 게 이번에 드러났으니 허용 목록만으로는 부족해요. 버전 고정까지 함께 운영해야 효과가 납니다.
    • 사내망과 재택 환경의 차이(추정): 8099처럼 흔히 쓰지 않는 포트로 나가는 트래픽을 막아 둔 사내망이라면 상태 보고 전송이 막혔을 수 있습니다. 반대로 재택 중에 집 네트워크에서 Cursor를 썼다면 이런 보호는 받지 못했던 거고요.

    확인된 것과 아직 불확실한 것

    확인된 것

    • 악성 버전은 2.1.313이며, Cursor 마켓플레이스의 Anthropic 공식 계정으로 배포되어 2.1.312를 대체했다.
    • Cursor가 집계한 영향 사용자는 최대 5,000명이다.
    • Anthropic은 몇 시간 뒤 2.1.314를 배포했고, Cursor는 악성 버전을 내리고 추가 배포를 막았다.
    • Cursor는 마켓플레이스를 잠시 닫고 키 교체, 접근 통제 감사, 다른 확장의 오염 여부 확인을 마친 뒤 다시 열었다.
    • Cursor 확장은 기본적으로 자동 업데이트되며, 설정에서 바꿀 수 있다.
    • SSH 키 추가 단계는 Cursor를 관리자 권한으로 실행하지 않았다면 코드 오류로 실패한다.
    • Cursor와 Phorion이 IP 주소와 해시 등 침해 지표를 공개했다.

    아직 불확실한 것

    • Anthropic 공식 계정이 탈취된 경로
    • Anthropic이 고객에게 공지하지 않은 이유
    • 5,000명 중 지속성 설치까지 성공한 실제 감염 기기 수
    • Linux에서 쓰인 지속성 방식
    • 환경 변수 값이나 소스 코드의 실제 유출 여부
    • Cursor 외 다른 배포 채널에 올라간 같은 확장의 영향 여부

    자동 업데이트는 끄기보다 ‘확인 후 수동 적용’으로 바꾼다

    자동 업데이트를 아예 꺼 버리면 이번 같은 악성 버전은 피할 수 있습니다. 대신 문제를 고친 2.1.314 같은 수정 버전도 늦게 받게 되죠. 악성 버전이 몇 시간 만에 교체됐다는 걸 떠올려 보면, 업데이트 알림은 받되 적용만 하루쯤 미뤘어도 2.1.313은 건너뛸 가능성이 높았습니다. 완전히 끄는 것보다 ‘확인 후 수동 적용’이 낫다고 보는 이유예요. 셸 명령을 실행하거나 파일 여러 개를 한꺼번에 고치는 AI 에이전트 확장처럼 권한이 큰 확장일수록 이 방식이 더 유리합니다.

    전체 확장의 자동 업데이트 끄기: 명령 팔레트(Windows·Linux Ctrl+Shift+P, macOS Cmd+Shift+P)에서 ‘Preferences: Open User Settings (JSON)’을 열고 아래 두 줄을 넣습니다.

    "extensions.autoUpdate": false,
    "extensions.autoCheckUpdates": true

    첫 줄이 자동 설치를 막고, 둘째 줄이 업데이트 확인과 알림은 그대로 살려 둡니다. 화면에서 바꾸고 싶다면 설정 검색창에 extensions.autoUpdate를 입력한 뒤 ‘Extensions: Auto Update’ 값을 None으로 고르면 돼요. 다만 Cursor에는 전용 설정 화면과 VS Code 방식의 설정 화면이 따로 있고, 후자로 들어가는 메뉴 경로는 확인되지 않았습니다. 명령 팔레트로 가는 편이 빠릅니다.

    특정 확장만 자동 업데이트 끄기: 확장 뷰 → 대상 확장 우클릭 → ‘Auto Update’ 체크 해제. 확장별 자동 업데이트를 지원하는 VS Code 버전에 있는 기능인데, Cursor에서도 같은 항목이 보일지는 장담하기 어렵습니다. 전체 자동 업데이트는 켜 두고 권한이 큰 확장만 손으로 관리하고 싶을 때 쓰는 방법이에요.

    버전 고정: 확장 우클릭 → ‘Install Specific Version…'(이전 표기 ‘Install Another Version…’) → 검증된 버전 선택. VS Code는 이렇게 설치한 확장의 자동 업데이트를 끄도록 동작합니다. 그래도 적용한 뒤엔 해당 확장의 Auto Update 체크 상태를 한 번 더 확인해 두세요.

    IDE를 관리자 권한으로 실행하지 않기: 이번 백도어는 SSH 키 추가 단계의 코드가 잘못 짜여 있어서, 관리자 권한으로 실행된 경우에만 이 단계가 성공했습니다. 공격자의 실수 덕을 본 셈인데요. 다음 공격자는 이 오류를 고쳐서 올 수 있으니 거기에 기댈 일은 아닙니다. Windows라면 Cursor 바로 가기 우클릭 → 속성 → 호환성 → ‘관리자 권한으로 이 프로그램 실행’ 체크를 해제하세요. macOS와 Linux에서는 sudo로 편집기를 실행하지 않으면 됩니다. 확장은 편집기 권한을 그대로 물려받으니까, 편집기 권한을 낮추는 게 피해 규모를 줄이는 가장 간단한 방법입니다.

    조직 단위 허용 목록: VS Code는 extensions.allowed 설정으로 설치할 수 있는 게시자, 확장, 버전을 제한할 수 있습니다. 허용 버전을 지정해 두면 공식 계정에 새 버전이 올라와도 검토를 마치기 전엔 설치되지 않아요. Cursor가 이 정책을 똑같이 지원하는지는 검증 전이니, 도입하기 전에 테스트 기기에서 먼저 돌려 보세요. 게시자가 공식 계정인지 따지는 건 이번엔 아무 소용이 없었습니다. 이런 공격에 실제로 효과가 있는 건 업데이트가 언제, 어떤 권한으로 적용되는지를 관리하는 쪽입니다.

    출처: Ars Technica