기술

메갈로돈, 6시간 만에 GitHub Actions를 5,561개 저장소의 백도어로 바꿔놓다

Susan Hill

한 자동화 캠페인이 5월의 어느 월요일 아침, 6시간 동안 5,561개의 GitHub 저장소에 5,718개의 커밋을 밀어 넣었다. 커밋은 평범한 CI 정비 작업처럼 보였고(“ci: add build optimization step”, “build: improve ci performance”, “chore: optimize pipeline runtime”) build-bot, auto-ci, pipeline-bot 같은 평범한 이름의 작성자가 보낸 것이었다. 5월 18일 오전이 끝났을 때, 그 저장소들 안에는 모두 base64로 인코딩된 bash 페이로드가 든 워크플로 파일이 한 개씩 자리잡고 있었다.

캠페인의 이름은 메갈로돈이다. SafeDep의 연구팀은 5월 21일, 커밋을 분해해 산출물의 흔적을 따라 216.126.225.129:8443에 있는 단 하나의 지휘통제 서버까지 도달한 뒤 공개했다. 흥미로운 점은 GitHub가 공격당했다는 사실이 아니다. 흥미로운 점은 공격자가 GitHub를 침해할 필요가 전혀 없었다는 사실이다. 공격자는 코드의 무결성을 보장하려고 설계된 CI/CD 시스템인 GitHub Actions 자체를, 백도어 배달 차량으로 썼다.

대량형과 잠복형, 두 워크플로

메갈로돈은 두 가지 모드로 작동했다. 대량형 변종은 SysDiag라는 새 워크플로 파일을 추가했고, 모든 push와 모든 pull request에서 발사돼 그 안을 지나는 모든 것을 거둬들였다. 표적형 변종 Optimize-Build는 더 인내심이 깊었다. 기존 워크플로를 workflow_dispatch 트리거로 교체했고, 이 트리거는 누군가 수동으로 호출할 때까지 잠들어 있다. 프로젝트의 CI 디렉터리에서 잠든 백도어를 알아채는 것은 SysDiag라는 새 워크플로를 알아채는 것보다 훨씬 어렵다. 대부분의 유지보수 담당자는 자기가 한 번 쓴 파일을 다시 감사하지 않기 때문이다.

워크플로가 돌기 시작하면 페이로드는 CI 환경에서 닿을 수 있는 모든 것을 읽는다. CI 환경 변수. AWS의 액세스 키, 비밀 키, 세션 토큰. GCP의 액세스 토큰. SSH 개인 키. .npmrc 자격증명. Docker 설정. Kubernetes 설정. GitHub Actions의 OIDC 토큰은 공격자가 워크플로 자체로 가장해, 그 워크플로가 인증받았던 어떤 클라우드 계정에도 들어가게 해 준다. 종료하기 전에 페이로드는 사람의 손에 의해 어딘가 붙여 넣어졌을지 모를 비밀에 대비해, 저장소 소스에서 서른 가지 이상의 비밀 패턴(API 키, 비밀번호, 인증서 조각)을 grep으로 훑는다. AWS IMDSv2, GCP, Azure의 메타데이터 엔드포인트는 클라우드 머신 신원을 얻기 위해 따로 조회된다.

자신의 백도어를 출하하는 파이프라인

지금까지 가장 심각한 피해자는 Tiledesk다. 오픈소스 고객 관여 플랫폼으로, 아홉 개의 GitHub 저장소가 타격을 입었다. 5월 19일부터 21일 사이, Tiledesk는 백도어가 컴파일된 채로 tiledesk-server 패키지를 npm에 올렸다. @tiledesk/tiledesk-server의 2.18.6부터 2.18.12까지의 버전은 이제 그 창 안에서 npm install을 돌린 모든 하류 개발자에게 설치된 페이로드 코드를 안고 있다. 그것이 메갈로돈이 노린 지렛대다. 하나의 오픈소스 프로젝트에 백도어를 심어, 그 릴리스 파이프라인이 의존 프로젝트 수백 개에 백도어를 심도록 만드는 것.

Black-Iron-Project는 여덟 개의 저장소를 잃었다. 더 작은 프로젝트들 수백 곳(개인 개발자 계정, 대학교 클러스터, 버려진 샌드박스)은 한두 개씩 맞았다. 공격자는 가리지 않은 것처럼 보였다. 패턴은 정확성보다 폭이었다. 무작위 여덟 자 사용자명을 단 일회용 계정들이, 분 단위로 똑같은 커밋 메시지를 밀어 넣었다. C2 서버는 돌아오는 것을 조용히 기록했다.

CI 파일이 감사를 살아남은 이유

이 공격이 통한 이유는 2026년 남은 기간 동안 같은 일이 되풀이될 이유이기도 하다. CI/CD 파이프라인은 설계상 신뢰 위에 서 있다. 다운로드 속 낯선 바이너리는 의심하는 개발자가, 지난주에 자기 저장소로 들어온 워크플로 파일은 망설임 없이 돌린다. 워크플로 파일이란 정확히 그것이기 때문이다. 플랫폼이 돌려 줘야 하는 코드. 감사 로그는 존재하지만, 그것을 읽는 팀은 드물다. 새 커밋은 build-bot, ci-bot 같은 이름으로 들어온다. diff는 작다. 워크플로 맨 밑의 base64 문자열은 의도적으로 불투명하다.

방어용 매뉴얼은 단순하고 만족스럽지 않다. 5월 18일부터 지금까지 어떤 저장소든 거쳐 간 모든 비밀을 교체하라. 관리 중인 모든 프로젝트의 .github/workflows 디렉터리를 감사하라. 작성자 이메일이 알려진 팀 구성원과 일치하지 않는 커밋을 살펴라. Actions 파일 안의 어떤 base64 블롭도 해독되기 전까지는 유죄로 다루라. Tiledesk를 쓰는 조직은 2.18.5로 되돌아가거나 깨끗한 릴리스를 기다려야 한다. Actions와 클라우드 제공자 사이에 OIDC 신뢰가 있는 사람은 그 신뢰 관계를 폐기하고 다시 발급해야 한다.

메갈로돈은 CI 워크플로 자체를 무른 표적으로 다룬 이 규모의 첫 캠페인이다. 마지막은 아닐 것이다. 이 공격이 남긴 교훈은 개발자들이 더 작은 목소리로 이미 들어 본 것이다. 파이프라인에서 당신이 읽지 않는 부분은, 공격자가 당신을 대신해 써 주는 부분이다.

토론

댓글 0개가 있습니다.