Transcript
00:00:00지금 또 하나의 거대하고, 정말 엄청난 공급망 공격이 발생했으며 여전히 진행 중입니다
00:00:06이 공격은 NPM에서 파이썬 생태계로까지 확산되었으니 지금 당장은 그 어떤
00:00:12NPM이나 파이썬 패키지도 설치하지 마세요. 그리고 전반적으로 시스템을 안전하게 설정해야 합니다. 관련해서
00:00:19다른 영상이 있으니 아래에 링크를 공유하겠고, 이번 영상에서도 다시 다루겠지만 먼저
00:00:23무엇이 영향을 받았는지, 본인이 대상인지 확인하는 방법에 대한 세부 정보를 알려드리고 싶습니다. 시작은
00:00:30TanStack 패키지들인 TanStack query, TanStack router, TanStack start 등이었습니다. 어제인 5월 11일,
00:00:36꽤 짧은 시간 동안 몇몇 악성 패키지들, 정확히는 모든 TanStack 패키지들이
00:00:43악성 버전으로 배포되었고 20분 만에 신속하게 격리되었습니다. 결국
00:00:50빠르게 감지되고 격리되었지만, 이 모든 악성 패키지들은 해당 기간,
00:00:57즉 이 짧은 시간 동안 배포되었습니다. 그리고 나서 계속 확산되었고 현재도
00:01:03확산 중입니다. 사용자가 4명뿐인 Mistral 패키지까지 퍼졌지만, 여전히
00:01:09영향을 받았는데, 이 맬웨어가 웜처럼 작동하여 데이터와 자격 증명을 훔치기 때문입니다. 여러분의 것도
00:01:16시스템에 설치되었다면 잠재적으로 위험합니다. 본인이 영향을 받았는지 확인하는 방법은 잠시 후에
00:01:20다시 설명하겠지만, 이것이 설계된 의도대로 더 많은 NPM 패키지로 계속 확산되었고
00:01:26심지어 파이썬 생태계까지 침투했으며 지금도 진행 중입니다. 이건 겨우 몇 시간 전의 일이고,
00:01:32제가 녹화하는 시점 기준으로는 2시간 전입니다. 자, 어떻게 영향을 받았는지 확인할까요?
00:01:39제 경우인 독일 시간 기준으로 어제 저녁에 TanStack 패키지를 하나라도 설치했다면,
00:01:45피해를 입었다고 간주해야 합니다. 그 시간대에 설치했다면, 해당 시간은
00:01:54UTC 기준이므로 본인의 시간대로 변환해서 생각해야 하며, 그 시간대라면 영향을 받은 것으로
00:02:00보아야 합니다. 하지만 이것이 Mistral 패키지와 제가 나열할 수 있는 것보다 훨씬 더 많은 자바스크립트 패키지로
00:02:06확산되고 있기 때문에, 여러분 자신이나 여러분의 기기가 영향을 받고 침해당했다고 생각해야 합니다.
00:02:13관련 게시물 링크를 아래에 공유해 드릴 테니 더 깊이 파고들어 배포된 모든
00:02:18영향받은 패키지의 전체 목록을 확인해 보세요. 하지만 언급했듯이 여전히 진행 중이므로,
00:02:22지금은 아무것도 설치하지 않는 게 좋을 수도 있습니다. 또한 침해 지표들도 존재합니다.
00:02:31특정 파일 해시들, 즉 라우터의 JS 파일에 대한 SHA 해시들을 찾아야 합니다. 이 게시물도 아래에 링크하겠습니다.
00:02:38그리고 본인의 기기에서 어떤 네트워크 요청이 발생했는지 모니터링할 방법이 있다면,
00:02:42이 URL로 향하는 아웃고잉 트래픽을 확인해 보세요. 이는 시스템에서 데이터가
00:02:48유출되었다는 또 다른 명확한 지표가 될 것입니다. 침해란 구체적으로 무엇을 의미할까요? 이는
00:02:55이 맬웨어가 크게 두 가지 일을 한다는 뜻입니다. 첫 번째 중요한 일은 데이터를 수집하는 것입니다.
00:03:03NPM 토큰, GitHub 토큰, AWS 자격 증명 및 기타 비밀 정보를 찾습니다. 즉, 자격 증명과 비밀 정보가
00:03:12저장되는 전형적인 위치를 시스템에서 스캔하여 수집한 다음, 제가 보여드린
00:03:18이 URL로 전송합니다. 그렇게 비밀 정보를 훔치는 것이죠. 하지만 그게 전부가 아닙니다. 언급했듯이,
00:03:26이것은 웜으로 작동하므로, 훔친 GitHub 토큰들도 활용합니다. 예를 들어,
00:03:33이 토큰들과 NPM 토큰을 사용하여 더 많은 오염된 패키지를 배포합니다. 여러분이 다른 패키지의
00:03:40관리자이거나, 해당 시간대에 실행된 CI/CD 워크플로가 있고 그것이
00:03:46어떤 TanStack 패키지에 의존하고 있었다면, 그 CI/CD 워크플로에서 악성 코드가 포함된,
00:03:53오염된 TanStack 패키지가 다운로드되었을 것입니다. 악성 코드가 거기서 실행되었을 수도 있고요. 그러면
00:04:00사용자의 기기가 아닌 해당 워크플로 내에서 특정 자격 증명을 훔쳐
00:04:06해당 CI/CD 워크플로가 빌드하려던 패키지의 악성 버전, 즉 오염된 버전을
00:04:14배포할 수도 있게 됩니다. 이것이 확산 방식입니다. 말씀드린 대로 웜처럼 행동하는 것이죠.
00:04:20훔친 자격 증명과 토큰을 사용하여 더 많은 오염된 패키지를 배포하는 것입니다. 그렇게
00:04:26Mistral로, 그리고 다른 자바스크립트 패키지로, 심지어 파이썬 생태계까지 퍼지게 됩니다.
00:04:32이것이 현재 상황입니다. 제가 아는 바로는 여전히 확산 중입니다. 그렇다면 어떻게
00:04:39방어할 수 있을까요? 제 다른 채널인 AkataMind에 관련 영상을 만들었습니다. 아래에 링크해 두겠습니다.
00:04:44요약하자면, 가능하다면 코드를 실행하거나 개발 작업을 수행할 때
00:04:51로컬 기기에서 직접 하지 말고, 가상 머신이나 데브 컨테이너(dev container) 같은 곳에서 하세요.
00:04:57가공되지 않은 비밀 정보를 기기에 저장하지 마세요. 예를 들어 AWS의 경우,
00:05:03기기에 IAM 자격 증명을 저장하는 대신 싱글 사인온(SSO) 방식을 사용하고,
00:05:10사용 중인 다른 서비스들에 대해서도 유사한 기술을 사용하세요. 추가로,
00:05:16비밀 정보를 로컬 하드 드라이브나 .env 파일에 저장하지 않고 클라우드에 저장하기 위해
00:05:25InPhysical이나 Doppler 같은 서비스를 사용하는 것도 고려해 볼 만합니다. 그렇게 하시는 게 좋습니다.
00:05:30다시 말씀드리지만, 그런 내용은 해당 영상에서 다룹니다. 또한 Bun이 지원하는 것처럼
00:05:38최소 릴리스 연령(minimum release age)을 설정할 수 있는 패키지 매니저와 구성을 사용하는 것이 좋습니다.
00:05:44bunfig.toml 파일에서 최소 릴리스 연령을 설정하면, bun install을 실행하더라도
00:05:49이 예시의 경우 최소 X초 또는 X일이 지난 패키지만 설치하도록 보장할 수 있습니다.
00:05:56pnpm에도 유사한 기능이 있고, npm의 최신 버전들에도 비슷한 기능이 있습니다.
00:06:02역시 다른 영상에서 다뤘습니다. Bun 같은 도구를 사용하거나 npm 설정을 제대로 해두면,
00:06:09예를 들어 Bun은 기본적으로 이를 수행하는데, 설치하려는 패키지의 수명 주기 스크립트인
00:06:15post install 스크립트 같은 것들의 실행을 차단합니다. 이는 또 다른 보안 메커니즘을 제공하는데,
00:06:21이러한 맬웨어들이 보통 시스템에서 그런 스크립트가 실행되는 것에 의존하기 때문입니다.
00:06:28따라서 안전한 패키지 매니저 혹은 패키지 매니저의 안전한 설정을 사용하고, 코드를 가상 머신이나
00:06:36데브 컨테이너에서 실행하며 시스템에 평문 비밀 정보를 저장하지 않는 것. 이것이 일반적으로
00:06:41권장되는 방법이지만, 이러한 공격들이 점점 더 심각해지고 있기 때문에 지금은 더욱 중요합니다.
00:06:46이 공격이 어떻게 작동했는지 살펴볼 텐데 정말 흥미롭습니다. 물론 우리는 앞으로 이런 일을
00:06:52더 많이 겪게 될 것입니다. 저는 거의 매달 또는 그보다 더 자주 이런 영상을 만들고 있는데,
00:06:58그 이유 중 하나는 이러한 공격이 실행하기가 더 쉬워졌다고 믿기 때문입니다. 이제 AI 시대에는
00:07:04영향을 주고자 하는 패키지나 종속성을 분석하고, 잠재적인 공격 벡터를 찾기 위해 소스 코드나
00:07:12CI/CD 설정을 분석하는 것이 더 쉬워졌습니다. 이번 TanStack의 경우도 바로 그런 일이 일어났습니다.
00:07:22유지 관리자의 기기가 감염된 것이 아니라, TanStack의 CI/CD 워크플로가
00:07:28공격을 받은 것입니다. 이 부분으로 다시 돌아오겠습니다. AI로 취약점을 찾는 것이 더 쉬워졌고,
00:07:34악성 코드를 포함한 코드를 작성하는 것도 물론 더 쉬워졌습니다. 동시에 소프트웨어가 폭발적으로 증가했습니다.
00:07:40그 어느 때보다 많은 소프트웨어가 작성되고 있습니다. 따라서 보안에 크게 신경 쓰지 않는
00:07:45많은 타겟을 포함하여, 공격할 대상이 더 많아졌습니다. 그래서 이러한 공격들이
00:07:51공격자들에게 더 매력적으로 다가오는 것입니다. 자, 이 모든 일이 어떻게 시작되었을까요?
00:07:57정말 흥미롭습니다. 말씀드린 것처럼 완전히 새로운 방식은 아니며 전에 본 적이 없는 것도
00:08:03아니지만, 여전히 꽤 정교합니다. TanStack 팀은 공격이 어떻게 일어났는지 설명하는
00:08:09사후 분석 기사를 게시했습니다. 그 링크도 아래에 걸어두겠습니다.
00:08:15하지만 여기서 요약을 해드리자면, 결과적으로 이번 공격은 제가 자세히 설명할
00:08:22주요 세 단계에 의존했습니다. 'Pull request target pwn request' 패턴. 이게 무엇인지
00:08:30설명하겠습니다. 그다음 '포크 기반 신뢰 경계를 넘나드는 GitHub Actions 캐시 오염'과
00:08:38'OIDC 토큰의 런타임 메모리 추출'입니다. 자, 이게 다 무슨 뜻일까요? 다시 말씀드리지만,
00:08:45모든 세부 사항은 기사를 읽어보시면 되지만, 제가 요약을 해드리겠습니다. 먼저
00:08:50'Pull request pwn request' 패턴부터 시작하죠. 그게 뭘까요? 이를 이해하려면
00:08:58GitHub Actions가 GitHub에서 제공하는 CI/CD 솔루션이자 제품이라는 점을 이해해야 합니다.
00:09:05참고로 GitHub Actions 설정 방법, CI/CD 작업에 제품을 사용하는 방법,
00:09:10패키지나 웹사이트 배포 방법 등을 배우고 싶으시다면 관련 강의도 준비되어 있습니다.
00:09:16모든 CI/CD 워크플로 도구와 마찬가지로 GitHub Actions는 워크플로를 트리거하는 이벤트에 의존합니다.
00:09:24CI/CD의 핵심은 무언가를 자동화된 방식으로 처리하는 것이니까요. 예를 들어 메인 브랜치에 푸시할 때
00:09:29웹사이트를 자동화된 방식으로 릴리스하거나 배포하는 것 등이 있습니다.
00:09:34워크플로를 트리거할 수 있는 다양한 이벤트가 있으며, 푸시(push)가 그중 하나입니다.
00:09:40메인 브랜치에 푸시하면 특정 작업을 수행하라고 명령할 수 있으며, 여러 브랜치에 대해
00:09:44필터링할 수도 있습니다. 그러면 종속성을 설치하고, 프로젝트를 빌드하고,
00:09:49서버에 업로드하는 등의 작업을 수행할 수 있죠. 자, 또 다른 트리거는
00:09:56'pull_request_target'입니다. 이 트리거는 본인의 저장소에
00:10:05풀 리퀘스트(PR)가 생성되었을 때 활성화됩니다. 즉, 누구나 본인의 저장소를 포크하고,
00:10:14거기서 무언가를 한 뒤 자신의 포크에 푸시하고, 본인의 저장소에 PR을 보낼 수 있다는 뜻입니다.
00:10:19그러면 이 워크플로가 트리거됩니다. 위험하게 들리나요? 실제로 좀 그렇습니다. 그리고 이게 공격의 시작이었습니다.
00:10:25일반적인 'pull_request' 트리거도 있습니다. 방금 'pull_request_target'을 말씀드렸지만,
00:10:31'pull_request' 역시 동일한 방식으로 작동하지만, 이는 CI/CD 워크플로를
00:10:38포크된 저장소의 컨텍스트에서 실행합니다. 따라서 거기서 어떤 악성 행위가 일어나더라도,
00:10:45기본 저장소가 아닌 포크된 저장소에서 발생하므로 문제가 되지 않습니다.
00:10:52반면에 'pull_request_target'은 기본 저장소의 컨텍스트에서 실행됩니다. 그리고 그것은
00:10:58잠재적으로 위험합니다. 누구나 PR을 열 수 있기 때문입니다. 이번
00:11:04TanStack 공격의 경우, 공격자는 해당 PR, 즉 해당 포크에
00:11:10악성 코드인 웜 코드와 맬웨어를 TanStack 저장소의 포크 안에 포함시켰습니다.
00:11:20그런 다음 공격자가 PR을 열었고, 이것이 'pull_request_target'의 실행으로 이어졌습니다.
00:11:26말씀드린 대로 그렇게 되면 GitHub Actions 러너가 가동되고, 기본 저장소의 컨텍스트에서
00:11:33실행되게 됩니다. 이것이 무엇을 의미할까요?
00:11:40공격자가 기본 코드에 접근하거나 악성 코드를 저장소에 병합할 수 있다는 뜻은 아니지만,
00:11:46예를 들어 거기서 사용되는 캐시가 기본 저장소에서 비롯된
00:11:53후속 GitHub Actions 실행들과 공유된다는 것을 의미합니다. 푸시 트리거와 같이 완전히
00:12:00다른 훅이나 이벤트 트리거로부터 발생한 실행들과도 말이죠.
00:12:05다음에 일어난 일은 캐시 오염이었습니다. 그런데 이게 무슨 뜻일까요?
00:12:11공격자는 자신의 포크에 코드를 추가하여, 'pull_request_target' 트리거로
00:12:17GitHub Actions가 실행될 때, 'hash files' 명령을 실행하도록 했습니다.
00:12:23이는 GitHub Actions가 지원하는 명령으로, 캐시에 무언가를 저장하는 데 쓰입니다.
00:12:28자, 그 캐시의 목적은 무엇일까요? GitHub Actions 캐시의 아이디어는 단순히
00:12:33워크플로의 속도를 높이는 것입니다. 예를 들어 종속성들을 해싱할 수 있습니다. 만약
00:12:39패키지가 의존하는 종속성이 바뀌지 않았다면, 굳이 전체 설치 과정을 다시
00:12:46거칠 필요가 있을까요? 시간은 곧 돈입니다. GitHub Actions 워크플로의 실행 시간에 따라 요금이
00:12:52청구되기 때문이죠. 그리고 당연히 워크플로가 영원히 걸리는 것을 원치 않으실 겁니다.
00:12:56그래서 대개의 워크플로에서, 예를 들어 TanStack 패키지를 빌드할 때,
00:13:00TanStack 패키지의 종속성을 설치한 다음 빌드 단계를 진행하여 패키지를 빌드합니다.
00:13:06다시 말하지만, TanStack의 종속성들이 변경되지 않았다면 왜 다시 설치하겠습니까?
00:13:12이것이 캐싱의 배경이고 일리가 있는 방식입니다. 하지만 문제는,
00:13:18문제는 pull request target GitHub actions 실행과 다른 GitHub action 실행들이,
00:13:24동일한 컨텍스트를 공유하기 때문에 캐시도 공유한다는 점입니다. 여기서 바로
00:13:31캐시 오염이 발생합니다. 공격자가 악성 버전을 캐싱하거나 악성 코드를
00:13:39TanStack의 종속성에 밀어 넣어 캐싱할 수 있었기 때문입니다. 그 후 공격자는
00:13:46TanStack 패키지에 대한 정상적인 GitHub Actions 워크플로가 실행되기를 기다리기만 하면 됐습니다.
00:13:53즉, 관리자가 코드를 푸시하면, 그 GitHub Actions 실행은 이전에 악성 실행에 의해
00:14:01설정된 동일한 캐시를 재사용하게 되고, 이제 악성 코드가 포함되어 준비된
00:14:08오염된 캐시를 끌어오게 됩니다. 이것이 악성 코드가 포크에서 시작해
00:14:13악성 코드의 영향을 받지 않은 일반 관리자의 정상적인 푸시에 의한 워크플로로 침투한 방법입니다.
00:14:21캐시가 두 GitHub Actions 실행 사이에서 전송 수단으로 사용된 셈입니다.
00:14:28그리고 세 번째 단계로, 악성 코드가 푸시 이벤트로 인해 정상적인
00:14:35TanStack CI/CD 워크플로 실행에 침투하자, 수명이 짧은 NPM 토큰, 즉 OIDC 토큰을
00:14:44훔쳐서 TanStack 패키지의 악성 버전을 배포하는 데 사용했습니다.
00:14:54제가 무엇을 말하는 걸까요? NPM에는 '신뢰할 수 있는 배포(trusted publishing)'라는 기능이 있는데,
00:15:00이론적으로는 NPM 패키지 배포를 더 안전하게 만들어줍니다. 왜냐하면
00:15:04NPM 패키지를 배포하는 방법은 크게 두 가지가 있다고 볼 수 있기 때문입니다. 하나는
00:15:11NPM 계정으로 토큰을 생성하고 이를 사용하여 새 버전의 패키지를 배포하는 것입니다. 문제는
00:15:19그 토큰을 도난당하면 누구든 해당 패키지의 새 버전을 배포할 수 있다는 점입니다. 보안을
00:15:26강화하기 위해 NPM은 '신뢰할 수 있는 배포' 프로세스를 도입하여, 본인의 기기에서 직접 패키지를
00:15:33배포할 수 없고 신뢰할 수 있는 공급자 중 하나를 거쳐야 한다고 규정했습니다. GitHub Actions가 그중
00:15:37하나이며, 이를 위해 설정할 수 있는 통합 기능이 있습니다. 그러면
00:15:44그 프로세스의 일부로 수명이 짧은 배포용 토큰이 검색되거나
00:15:50요청됩니다. 그리고 그 짧은 수명의 토큰이 배포되는 새 패키지 버전에
00:15:57서명하는 데 사용됩니다. 이론적으로는 어떤 관리자의 기기에도 토큰이 없기 때문에 훔치기 어렵고,
00:16:03게다가 수명도 짧다는 것이 장점입니다. 도난당하더라도 오래 활성화되지 않으니까요.
00:16:08문제는 해당 신뢰할 수 있는 토큰을 요청하는 CI/CD 워크플로에서 실행되는
00:16:15코드 자체가 감염되었다면, 그 악성 코드가 이 갓 생성된 따끈따끈하고 수명이 짧은
00:16:21신뢰할 수 있는 배포 토큰에 접근할 수 있게 된다는 점입니다. 바로 그 일이 여기서
00:16:27발생했습니다. 악성 코드는 이 토큰을 남용하거나 사용하여 NPM API에 접속했고,
00:16:36TanStack 패키지의 새 버전을 배포했습니다. 흥미롭게도 이 공격은 사실 약간 실패했는데,
00:16:44신뢰할 수 있는 토큰을 얻어 NPM API를 통해 웜과 악성 코드가 포함된
00:16:52TanStack 패키지의 새 버전을 배포하긴 했지만, 실제로는 CI/CD에 푸시된
00:16:58코드에 문제가 있어서 완료되지 못한 GitHub Actions 워크플로로 끝났기 때문입니다. 공격자들이
00:17:06유효한 코드가 푸시되는 시점에 공격을 수행하도록 주의를 기울였다면,
00:17:12해당 워크플로는 성공적으로 완료되었을 것이고, 그들은 NPM API에 개별적으로 접속해
00:17:19악성 패키지를 수동으로 배포할 필요 없이, 실제 워크플로에 악성 코드를 주입하여
00:17:26워크플로가 성공적으로 끝나게 뒀을 것입니다. 그러면 오염된 버전의 TanStack은 관리자의
00:17:32정상적인 푸시였고 워크플로도 성공했기 때문에 겉보기에는 매우 정당해 보였을 것입니다.
00:17:38공격이 진행된 방식이 워크플로 실패로 이어졌기 때문에, 외부 기여자가 결과적으로
00:17:45이 공격이 가능했던 이유는 해당 워크플로가 성공적으로 끝나지 않았기 때문이며,
00:17:51결과적으로 외부 기여자가 무슨 일이 일어나고 있는지 파악하기가 조금 더 수월했습니다.
00:18:00GitHub Actions 워크플로가 실패했음에도 불구하고 TanStack 패키지의
00:18:05새 버전이 게시된 것을 볼 수 있었기 때문이죠. 원래는 게시되지 않았어야 합니다.
00:18:12이러한 불일치 덕분에 공격을 감지하기가 좀 더 쉬웠고, 이 부분은
00:18:19TanStack 유지관리자들과 우리 모두에게 운이 좋았던 면이 있습니다. 하지만 상당히 정교한 공격이었죠.
00:18:26누구의 컴퓨터도 해킹하지 않고 이루어졌으며, 비록 빠르게 발견되었음에도
00:18:32심각한 피해를 입혔습니다. 말씀드렸듯이 여전히 확산 중이기 때문입니다.
00:18:41이 모든 내용에 대해 긴 에피소드였다는 것을 알지만, 여러분의 시스템을
00:18:49안전하게 만드는 데 힘써야 한다는 점을 강조하고 싶습니다. 이 영상에서 공유했듯이
00:18:56피해를 입을 위험을 줄여야 합니다. 이번 공격은 금방 발견되었지만 여전히 퍼지고 있습니다.
00:19:05그래서 아직 끝난 것이 아니며, 향후의 모든 공격이
00:19:11이렇게 빨리 발견되지 않을 수도 있습니다. 이번에는 운이 좀 좋았던 편이라
00:19:18감지가 더 어려웠다면 피해는 훨씬 컸을 것입니다. 지금도 이미 피해가 상당하고
00:19:24아직 끝나지 않았습니다. 앞으로도 이런 공격은 더 많아질 것이라 확신합니다.
00:19:31공격 표면이 점점 더 넓어지고 흥미로워지고 있기 때문입니다. 코드를 쓰는 사람은 많아졌지만
00:19:36자신이 무엇을 하는지 모르는 이들도 많고, AI는 이런 공격을 수행하는 데 도움을 줍니다.
00:19:42이것이 현재 상황입니다. 꼭 필요한 게 아니라면 설치를 자제하고 설정을 다시 확인하세요.
00:19:48더 자세히 알고 싶거나 영향을 받은 패키지 목록을 보려면 아래 링크를 확인해 주세요.
00:19:51목록 등을 확인해 보세요.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video