- 개인이 운영하던 Hetzner 서버에서 비정상적인 CPU 사용률이 발견되어 조사한 결과, 암호화폐 Monero 채굴 프로그램(xmrig) 이 실행 중이었음
- 원인은 Next.js의 원격 코드 실행 취약점(CVE-2025-66478) 을 포함한 Umami 분석 도구 컨테이너가 공격받은 것이었음
- 다행히 해당 컨테이너는 비루트(non-root) 사용자로 실행되고 호스트 마운트나 권한 상승이 없었기 때문에, 침입은 컨테이너 내부에 국한됨
- 공격자는 Next.js 서버 컴포넌트의 비안전한 역직렬화를 악용해 악성 페이로드를 실행하고 채굴기를 설치함
- 이번 사례는 의존성 관리와 컨테이너 보안 설정의 중요성을 보여주는 사례로, 작성자는 방화벽 활성화·SSH 강화·정기 업데이트 등 보안 조치를 강화함
해킹 발생과 초기 대응
- Hetzner로부터 서버가 외부 네트워크를 스캔했다는 경고 메일을 수신
- 4시간 내 조치하지 않으면 서버가 차단될 수 있다는 통보 포함
- SSH 접속 후 확인 결과, /tmp/.XIN-unix/javae 경로에서 819% CPU를 사용하는 프로세스와 여러 xmrig 프로세스가 발견됨
- 약 10일간 암호화폐 채굴이 진행된 것으로 확인
침입 경로 조사
- 모든 악성 프로세스가 UID 1001 사용자로 실행 중이었으며, 이는 Umami 컨테이너와 일치
-
/app/node_modules/next/dist/server/lib/xmrig-6.24.0/ 디렉터리에서 채굴기 실행 파일이 발견됨
- 실행 명령에는 auto.c3pool.org:443 마이닝 풀 주소와 사용자 키가 포함되어 있었음
Next.js 취약점과 공격 방식
-
Next.js의 React Server Components 역직렬화 취약점(CVE-2025-66478) 이 원인
- 공격자가 조작된 HTTP 요청을 전송하면 서버에서 임의 코드가 실행됨
- 결과적으로 암호화폐 채굴기 설치 및 실행이 가능
- 작성자는 “Next.js를 직접 사용하지 않는다”고 생각했으나, Umami가 Next.js 기반임을 뒤늦게 인지
컨테이너 격리 확인
-
/tmp/.XIN-unix/javae가 호스트 파일시스템에 존재하지 않음을 확인
- Docker의 ps 출력에 컨테이너 프로세스가 표시되는 현상일 뿐, 실제로는 격리 상태 유지
-
docker inspect 결과
- 사용자: nextjs
-
Privileged: false
-
Mounts: 없음
- 따라서 악성코드는 호스트 접근, 크론 등록, 시스템 서비스 생성, 루트킷 설치 등을 수행하지 못함
복구 및 보안 강화
- 감염된 Umami 컨테이너를 중지 및 삭제 후 CPU 사용률 정상화
-
UFW 방화벽 활성화로 SSH·HTTP·HTTPS만 허용
- Hetzner에 조사 결과 보고 후 티켓이 1시간 내 종료됨
교훈과 개선점
- “내가 X를 사용하지 않는다”는 말은 의존성까지 포함하지 않음
- 사용하는 도구가 어떤 기술 스택으로 구성되었는지 확인 필요
-
컨테이너 격리의 효과 입증
- 비루트 사용자, 비권한 모드, 불필요한 볼륨 미사용이 피해 확산을 막음
-
보안 다층 방어(Defense in Depth) 의 필요성
- 방화벽, fail2ban, 모니터링, 정기 업데이트가 필수
-
직접 Dockerfile 작성과 컨테이너 권한 최소화의 중요성 강조
사건 이후 조치
- Umami를 최신 버전으로 재배포하고 모든 서드파티 컨테이너를 감사
- 실행 사용자, 마운트, 업데이트 시점, 필요성 점검
-
SSH 키 기반 인증 전환, 비밀번호 로그인 비활성화, fail2ban 설정
-
Grafana와 Node Exporter를 통한 모니터링 강화, 보안 업데이트 즉시 적용
결론
- Umami의 Next.js 취약점으로 인해 10일간 Monero 채굴에 악용되었으나,
컨테이너 격리와 비루트 실행 설정 덕분에 피해가 제한적이었음
- 이번 경험을 통해 작성자는 의존성 파악, 보안 설정, 업데이트 관리의 중요성을 체득
- 사건은 약 2시간 내 수습되었으며, 컨테이너 보안의 실제 효과를 검증한 사례로 남음