1P by GN⁺ 1일전 | ★ favorite | 댓글 1개
  • 개인이 운영하던 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시간 내 수습되었으며, 컨테이너 보안의 실제 효과를 검증한 사례로 남음
Hacker News 의견들
  • 예전에야 UFW를 켰지만, 지금은 firewalld를 추천함
    UFW는 시간이 지나면 관리가 어려워지지만 firewalld는 XML 기반 설정이라 훨씬 안정적임
    firewall-cmd 명령으로 SSH, HTTPS, 80포트 등을 설정할 수 있고, nftables 백엔드를 쓰는 게 좋음
    Docker의 경우 방화벽 규칙을 우회해 포트를 열어버리는 경우가 많으므로, /etc/firewalld/firewalld.conf에서 StrictForwardPorts=yes로 설정하는 게 안전함

    • 포트를 8080:8080처럼 열지 말고 192.168.0.1:8080:8080처럼 사설 IP에 바인딩하는 게 좋음
      나는 10.0.10.11 VM에서 Docker를 돌리는데, WireGuard로만 접근 가능하게 해서 Caddy로 리버스 프록시를 두는 방식이 편리했음
    • Docker 대신 Podman을 설치하라고 권함. Docker는 방화벽 우회 문제가 흔함
    • 어떤 netfilter 프론트엔드를 쓰든, 아웃바운드 연결 제한이 없으면 무의미함
      악성코드는 외부 마이닝 풀이나 C2 서버로 연결하려 하기 때문에, 허용되지 않은 바이너리의 네트워크 접근을 막아야 함
      /tmp, /var/tmp, /dev/shm의 실행 권한을 제거하는 것도 유용함
    • Hetzner는 무료 외부 방화벽 서비스를 제공하므로, 1차 방어선으로 활용할 수 있음
    • 개인적으로는 nftables.conf만으로도 충분히 단순하고 명확하다고 느낌
      iptables는 이미 폐기된 상태라 firewalld 같은 추가 계층이 꼭 필요하진 않음
  • 이건 “React2Shell CVE-2025-55182” 관련 이슈로 보임
    1년 넘게 영향을 준 취약점인데도 주목을 거의 못 받는 게 이상함
    지난 12개월간 Next.js로 배포한 웹앱이라면 이미 봇넷 일부일 가능성이 높음
    업계가 “Docker 써라”, “방화벽 켜라” 수준의 조언만 하는 게 답답함
    요즘 프론트엔드 생태계에 회의감이 들어서 C++ 쪽으로 커리어를 옮길까 고민 중임

    • 프론트엔드의 기술 교체 주기는 예전보다 훨씬 완화되었음
      지금은 Next.js, React, Tailwind, Postgres 조합이 5년째 표준처럼 굳어 있음
      2000년대 후반~2010년대 초반의 프레임워크 난립 시절에 비하면 안정적임
      유행과 변화가 싫다면 AI 개발 쪽이 훨씬 더 빠르게 변하고 있음
    • 최신 JS 프레임워크를 안 써도 웹앱은 충분히 만들 수 있음
      백엔드는 .NET, Java, Go 같은 견고한 기술 스택을 쓰고, 프론트는 자유롭게 선택하면 됨
      이렇게 하면 CVE도 줄고 기술 피로도도 낮아짐
    • Pangolin 인스턴스도 이 취약점에 뚫렸음
      관련 GitHub 토론
    • 나도 100개 정도의 Next.js 프론트를 배포했는데, Server Components를 안 써서 다행히 영향은 없었음
  • Docker 컨테이너의 CPU 사용량을 --cpus="0.5"로 제한하면, 오작동 서비스나 마이너가 시스템 전체에 영향을 주지 않음

    • 컨테이너를 read-only 모드로 돌리면 공격 표면을 더 줄일 수 있음
    • 다만 CPU 제한이 너무 낮으면 침입이 눈에 띄지 않아 탐지 지연이 생길 수도 있음
    • 앱의 성능 프로파일을 잘 알고 있어야 함. 나중에 버스트 트래픽이 생기면 의도치 않게 쓰로틀될 수 있음
    • 메모리의 soft/hard limit도 함께 설정하는 게 좋음
  • 방화벽 없이 서버를 운영하는 건 꽤 대담한 선택
    Hetzner의 외부 방화벽을 함께 쓰면 실수했을 때도 방어층이 하나 더 생김
    나는 SSH를 집 IP로만 허용하고, 외부에서 필요할 땐 Hetzner 웹사이트에서 임시로 열어둠

    • 대부분의 경우 방화벽은 큰 효과가 없음
      진짜 중요한 건 RCE 취약점이 있는 소프트웨어를 돌리지 않는 것
      Docker가 구세주처럼 보이는 건 사실상 운이 좋았던 것뿐임
    • 퍼블릭 웹서비스라면 방화벽이 큰 도움이 안 됨
      대신 bastion host를 두고 HTTP 프록시로 입출력을 제어하는 방법이 있지만 설정이 복잡함
    • 30년 동안 리눅스를 운영하면서 해킹당한 유일한 경우는 잘 알려진 포트를 열었을 때였음
      비표준 포트를 쓰는 것만으로도 의외로 효과적이었음
    • 비밀번호 인증을 켜두는 건 위험함. 개인적으로는 fail2ban이 꼭 필요하진 않다고 생각함
    • SSH 포트를 무작위로 바꿔서 포트 스캐너 회피를 시도함
      효과가 확실한지는 모르겠지만, 일종의 심리적 우산 같은 느낌임
  • Docker 컨테이너를 root로 돌리면, 호스트까지 공격 가능한가 궁금했음

    • Docker는 보안 경계가 아님. 단순히 프로세스 수준의 격리만 제공함
      신뢰할 수 없는 코드를 돌리려면 VM(KVM/QEMU)이나 gVisor(https://gvisor.dev/), Firecracker(https://firecracker-microvm.github.io/) 같은 기술을 써야 함
      Docker는 샌드박스가 아니라 격리된 실행 환경 정도로 이해해야 함
    • 공격자는 컨테이너 안에서도 CPU를 써서 Monero 채굴을 할 수 있음
      Docker의 기본 설정은 RAM, CPU, 디스크 사용량 제한이 없어 DoS 공격에도 취약함
      게다가 많은 가이드가 --privilegedCAP_SYS_PTRACE 같은 위험한 옵션을 권장함
    • privileged 모드에서는 Docker 소켓을 통해 호스트 루트 파일시스템에 접근 가능함
      새 컨테이너를 띄워서 루트 권한으로 변경할 수도 있음
    • user namespace를 활성화해야 진짜 보안 경계가 생김
      Docker는 아직 기본값이 아니라서, 설정하지 않으면 탈출 위험이 큼
      과거 대부분의 컨테이너 탈출은 user namespace로 막을 수 있었음
    • 컨테이너 탈출이 존재하긴 하지만, 대부분은 단순한 자동화된 마이닝 공격
      민감한 데이터를 다루지 않는 서버라면 컨테이너만 정리해도 충분함
  • 공격 표면을 줄이려면 공개할 필요 없는 서비스는 외부에 노출하지 말아야 함
    예를 들어 분석 툴은 WireGuard나 SSH SOCKS 프록시를 통해서만 접근하도록 하면 됨

  • 나도 Hetzner 서버에서 Monero 마이너 감염을 겪었음
    다행히 Incus의 LXC 컨테이너 안에서만 발생했고, CPU 우선순위가 낮아 눈치채지 못했음
    root 계정에 SSH 키가 추가되고 원격 관리 에이전트가 설치되어 있었음
    결국 컨테이너를 폐기했지만, 몇 가지 교훈을 얻었음

    • 시스템이 언젠가 뚫릴 걸 가정하고 격리와 자원 제한을 설정해야 함
    • ZFS 스냅샷과 백업을 주기적으로 유지하면 복구가 쉬움
    • 침해된 시스템은 폐기하는 게 이상적이지만, 상황에 따라 롤백 후 강화도 가능함
    • 마이너가 제대로 설정되지 않아 눈에 띄었지만, 만약 조용히 침입했다면 몰랐을 수도 있음
    • Umami를 설치한 컨테이너에서 발생했음
  • 글에 사람이 교정하지 않은 AI 환각 내용이 포함되어 있었음
    Puppeteer 관련 취약점이라고 반복 주장하지만 사실이 아님

    • 원문 첫 문단에 Claude 세션의 전사본이라고 명시되어 있었음
  • 최근 React 19 취약점을 이용한 Monero 마이너가 여기저기 설치되고 있음
    나도 같은 문제를 겪었음

    • 이런 마이닝 악성코드는 눈에 잘 띄고 피해도 적어서 오히려 유용함
      일종의 자동 버그 바운티처럼 작동해서, 취약점을 알려주는 셈임
      네트워크나 프로세스 모니터링이 잘 되어 있다면 쉽게 탐지 가능함
    • Oracle Cloud에서 Umami 서버가 감염되어 서버를 초기화했음
      덕분에 백업 시스템을 업그레이드할 좋은 계기가 되었음
  • 이런 사례를 보면 VPS를 직접 운영하지 않길 잘했다는 생각이 듦
    예전에 해봤지만, 나는 평범한 관리자 수준이라 보안 유지가 어렵다고 느낌
    그래서 지금은 전문가에게 맡기고 비용을 지불하는 편이 훨씬 마음이 편함