1 điểm bởi GN⁺ 2025-12-19 | 1 bình luận | Chia sẻ qua WhatsApp
  • Sau khi phát hiện mức sử dụng CPU bất thường trên máy chủ Hetzner do cá nhân vận hành, tác giả điều tra và phát hiện chương trình đào tiền mã hóa Monero (xmrig) đang chạy
  • Nguyên nhân là container công cụ phân tích Umami chứa lỗ hổng thực thi mã từ xa của Next.js (CVE-2025-66478) đã bị tấn công
  • May mắn là container đó chạy bằng người dùng không phải root (non-root)không có host mount hay leo thang đặc quyền, nên cuộc xâm nhập bị giới hạn bên trong container
  • Kẻ tấn công đã lợi dụng lỗi giải tuần tự không an toàn trong server component của Next.js để thực thi payload độc hại và cài đặt trình đào
  • Trường hợp này cho thấy tầm quan trọng của quản lý dependency và cấu hình bảo mật container, và tác giả đã tăng cường các biện pháp bảo mật như bật tường lửa, siết chặt SSH và cập nhật định kỳ

Sự cố bị hack và phản ứng ban đầu

  • Nhận được email cảnh báo từ Hetzner rằng máy chủ đang quét mạng bên ngoài
    • Kèm theo thông báo rằng nếu không xử lý trong vòng 4 giờ thì máy chủ có thể bị chặn
  • Sau khi SSH vào để kiểm tra, tác giả phát hiện một tiến trình dùng 819% CPU cùng nhiều tiến trình xmrig tại đường dẫn /tmp/.XIN-unix/javae
  • Xác nhận rằng việc đào tiền mã hóa đã diễn ra khoảng 10 ngày

Điều tra đường xâm nhập

  • Tất cả tiến trình độc hại đều chạy dưới người dùng UID 1001, trùng khớp với container Umami
  • Phát hiện tệp thực thi trình đào trong thư mục /app/node_modules/next/dist/server/lib/xmrig-6.24.0/
  • Lệnh thực thi có chứa địa chỉ mining pool auto.c3pool.org:443 và khóa người dùng

Lỗ hổng Next.js và cách thức tấn công

  • Nguyên nhân là lỗ hổng giải tuần tự React Server Components của Next.js (CVE-2025-66478)
    • Khi kẻ tấn công gửi một yêu cầu HTTP đã bị chỉnh sửa, mã tùy ý có thể được thực thi trên máy chủ
    • Kết quả là có thể cài đặt và chạy trình đào tiền mã hóa
  • Tác giả từng nghĩ rằng “mình không trực tiếp dùng Next.js”, nhưng sau đó mới nhận ra Umami được xây dựng trên Next.js

Xác nhận khả năng cô lập của container

  • Xác nhận rằng /tmp/.XIN-unix/javae không tồn tại trên filesystem của host
    • Đây chỉ là hiện tượng tiến trình của container xuất hiện trong đầu ra ps của Docker, còn thực tế vẫn được cô lập
  • Kết quả docker inspect
    • Người dùng: nextjs
    • Privileged: false
    • Mounts: không có
  • Vì vậy mã độc không thể truy cập host, đăng ký cron, tạo dịch vụ hệ thống hay cài rootkit

Khôi phục và tăng cường bảo mật

  • Dừng và xóa container Umami bị nhiễm, sau đó mức sử dụng CPU trở lại bình thường
  • Kích hoạt tường lửa UFW để chỉ cho phép SSH, HTTP và HTTPS
  • Báo cáo kết quả điều tra cho Hetzner và ticket được đóng trong vòng 1 giờ

Bài học và điểm cần cải thiện

  • Câu nói “tôi không dùng X” không bao gồm toàn bộ dependency
    • Cần kiểm tra các công cụ mình dùng được cấu thành từ stack công nghệ nào
  • Hiệu quả của việc cô lập container đã được chứng minh
    • Người dùng non-root, chế độ không đặc quyền và không dùng volume không cần thiết đã ngăn thiệt hại lan rộng
  • Sự cần thiết của phòng thủ nhiều lớp (Defense in Depth)
    • Tường lửa, fail2ban, giám sát và cập nhật định kỳ là bắt buộc
  • Nhấn mạnh tầm quan trọng của tự viết Dockerfilegiảm thiểu quyền của container

Các biện pháp sau sự cố

  • Triển khai lại Umami lên phiên bản mới nhất và kiểm tra toàn bộ container bên thứ ba
    • Rà soát người dùng chạy, mount, thời điểm cập nhật và mức độ cần thiết
  • Chuyển sang xác thực bằng SSH key, vô hiệu hóa đăng nhập bằng mật khẩu, cấu hình fail2ban
  • Tăng cường giám sát bằng Grafana và Node Exporter, áp dụng ngay các bản cập nhật bảo mật

Kết luận

  • Do lỗ hổng Next.js của Umami, máy chủ đã bị lợi dụng để đào Monero suốt 10 ngày, nhưng
    nhờ khả năng cô lập của container và cấu hình chạy non-root nên thiệt hại bị giới hạn
  • Qua trải nghiệm này, tác giả đã thấm thía tầm quan trọng của việc nắm rõ dependency, cấu hình bảo mật và quản lý cập nhật
  • Sự cố được xử lý trong khoảng 2 giờ và trở thành một trường hợp kiểm chứng hiệu quả thực tế của bảo mật container

1 bình luận

 
GN⁺ 2025-12-19
Ý kiến trên Hacker News
  • Trước đây người ta hay bật UFW, nhưng giờ tôi khuyên dùng firewalld
    UFW càng về sau càng khó quản lý, còn firewalld dùng cấu hình dựa trên XML nên ổn định hơn nhiều
    Có thể dùng lệnh firewall-cmd để cấu hình SSH, HTTPS, cổng 80, v.v., và nên dùng backend nftables
    Với Docker, khá thường gặp trường hợp nó mở cổng bằng cách vượt qua các quy tắc tường lửa, nên sẽ an toàn hơn nếu đặt StrictForwardPorts=yes trong /etc/firewalld/firewalld.conf

    • Đừng mở cổng kiểu 8080:8080, mà nên bind vào IP riêng như 192.168.0.1:8080:8080
      Tôi chạy Docker trên VM 10.0.10.11, chỉ cho truy cập qua WireGuard và đặt reverse proxy bằng Caddy nên khá tiện
    • Khuyên cài Podman thay vì Docker. Docker thường hay gặp vấn đề vượt qua tường lửa
    • Dù dùng frontend nào cho netfilter, nếu không có giới hạn kết nối outbound thì cũng vô nghĩa
      Malware sẽ cố kết nối ra ngoài tới mining pool hoặc máy chủ C2, nên phải chặn quyền truy cập mạng của các binary không được phép
      Việc gỡ quyền thực thi khỏi /tmp, /var/tmp, /dev/shm cũng hữu ích
    • Hetzner cung cấp dịch vụ tường lửa bên ngoài miễn phí, nên có thể dùng như tuyến phòng thủ đầu tiên
    • Cá nhân tôi thấy chỉ cần nftables.conf thôi cũng đã đủ đơn giản và rõ ràng
      iptables thực tế đã bị loại bỏ, nên không nhất thiết phải có thêm lớp như firewalld
  • Có vẻ đây là vấn đề liên quan đến “React2Shell CVE-2025-55182
    Thật lạ khi một lỗ hổng đã ảnh hưởng hơn 1 năm mà gần như không được chú ý
    Nếu là web app triển khai bằng Next.js trong 12 tháng qua thì rất có thể đã là một phần của botnet
    Thật bực khi cả ngành chỉ đưa ra lời khuyên kiểu “cứ dùng Docker đi”, “bật tường lửa lên”
    Dạo này tôi ngày càng hoài nghi hệ sinh thái frontend, đến mức đang cân nhắc chuyển sự nghiệp sang C++

    • Chu kỳ thay đổi công nghệ của frontend giờ đã nhẹ hơn nhiều so với trước
      Hiện tại tổ hợp Next.js, React, Tailwind, Postgres đã gần như thành chuẩn suốt 5 năm qua
      So với thời kỳ framework mọc loạn xạ cuối những năm 2000 đến đầu 2010 thì giờ ổn định hơn nhiều
      Nếu ghét trào lưu và thay đổi thì mảng phát triển AI còn biến động nhanh hơn rất nhiều
    • Không dùng framework JS mới nhất thì vẫn hoàn toàn làm được web app
      Backend cứ dùng stack công nghệ vững chắc như .NET, Java, Go, còn frontend thì chọn tự do
      Làm vậy sẽ giảm CVE và bớt mệt mỏi vì công nghệ hơn
    • Instance Pangolin của tôi cũng đã bị xuyên thủng bởi lỗ hổng này
      Thảo luận GitHub liên quan
    • Tôi cũng đã triển khai khoảng 100 frontend Next.js, và may là không bị ảnh hưởng vì không dùng Server Components
  • Nếu giới hạn mức dùng CPU của container Docker bằng --cpus="0.5", thì dịch vụ lỗi hoặc miner sẽ không ảnh hưởng tới toàn bộ hệ thống

    • Chạy container ở chế độ read-only cũng có thể giảm thêm bề mặt tấn công
    • Tuy nhiên nếu giới hạn CPU quá thấp thì xâm nhập có thể ít bị chú ý hơn, dẫn tới chậm phát hiện
    • Cần hiểu rõ hồ sơ hiệu năng của ứng dụng. Về sau nếu có burst traffic thì có thể vô tình bị throttle
    • Cũng nên đặt cả soft/hard limit cho bộ nhớ
  • Vận hành máy chủ mà không có tường lửa là một lựa chọn khá liều lĩnh
    Nếu dùng thêm tường lửa bên ngoài của Hetzner thì khi lỡ cấu hình sai vẫn có thêm một lớp phòng vệ
    Tôi chỉ cho phép SSH từ IP nhà mình, còn khi cần truy cập từ bên ngoài thì tạm mở qua website của Hetzner

    • Trong đa số trường hợp, tường lửa không mang lại hiệu quả lớn
      Điều thực sự quan trọng là không chạy phần mềm có lỗ hổng RCE
      Docker trông như vị cứu tinh thật ra phần lớn chỉ là do may mắn
    • Nếu là dịch vụ web công khai thì tường lửa cũng không giúp được nhiều
      Thay vào đó có thể dùng bastion host và kiểm soát vào/ra bằng HTTP proxy, nhưng cấu hình khá phức tạp
    • Trong 30 năm vận hành Linux, lần duy nhất tôi bị hack là khi mở các cổng nổi tiếng
      Chỉ riêng việc dùng cổng không chuẩn thôi cũng đã hiệu quả một cách bất ngờ
    • Bật xác thực bằng mật khẩu là nguy hiểm. Cá nhân tôi không nghĩ fail2ban là bắt buộc
    • Tôi đổi cổng SSH sang ngẫu nhiên để né port scanner
      Không chắc có hiệu quả rõ rệt không, nhưng giống như một chiếc ô tâm lý vậy
  • Tôi từng thắc mắc nếu chạy container Docker bằng root thì có thể tấn công lên cả host không

    • Docker không phải ranh giới bảo mật. Nó chỉ cung cấp mức cô lập ở cấp tiến trình
      Nếu muốn chạy mã không đáng tin cậy thì nên dùng VM (KVM/QEMU) hoặc công nghệ như gVisor(https://gvisor.dev/), Firecracker(https://firecracker-microvm.github.io/)
      Nên hiểu Docker không phải sandbox, mà chỉ là môi trường thực thi được cô lập
    • Kẻ tấn công vẫn có thể dùng CPU để đào Monero ngay trong container
      Cấu hình mặc định của Docker không giới hạn RAM, CPU, dung lượng đĩa nên cũng dễ bị tấn công DoS
      Hơn nữa, nhiều hướng dẫn còn khuyến nghị các tùy chọn nguy hiểm như --privileged hoặc CAP_SYS_PTRACE
    • chế độ privileged, có thể truy cập filesystem root của host thông qua Docker socket
      Cũng có thể khởi chạy container mới rồi leo thang lên quyền root
    • Cần bật user namespace thì mới có ranh giới bảo mật thực sự
      Docker hiện vẫn chưa để mặc định, nên nếu không cấu hình thì nguy cơ escape rất lớn
      Trước đây phần lớn các vụ container escape đều có thể được chặn bằng user namespace
    • Dù container escape có tồn tại, phần lớn vẫn chỉ là các cuộc tấn công đào coin tự động
      Nếu máy chủ không xử lý dữ liệu nhạy cảm thì chỉ cần dọn lại container cũng đã đủ
  • Để giảm bề mặt tấn công, những dịch vụ không cần công khai thì không nên phơi ra ngoài Internet
    Ví dụ, các công cụ phân tích chỉ nên cho truy cập qua WireGuard hoặc SSH SOCKS proxy

  • Tôi cũng từng bị nhiễm Monero miner trên máy chủ Hetzner
    May là nó chỉ xảy ra bên trong container LXC của Incus, và vì độ ưu tiên CPU thấp nên tôi không nhận ra
    Một SSH key đã được thêm vào tài khoản root và một agent quản trị từ xa đã được cài vào
    Cuối cùng tôi bỏ luôn container đó, nhưng cũng rút ra được vài bài học

    • Cần giả định rằng hệ thống rồi sẽ có lúc bị xuyên thủng và thiết lập cô lập cùng giới hạn tài nguyên
    • Nếu duy trì snapshot ZFS và backup định kỳ thì việc khôi phục sẽ dễ hơn
    • Lý tưởng nhất là loại bỏ hệ thống đã bị xâm phạm, nhưng tùy tình huống vẫn có thể rollback rồi harden lại
    • Miner bị lộ vì cấu hình không chuẩn, nhưng nếu xâm nhập âm thầm hơn thì có thể tôi đã không biết
    • Nó xảy ra trong container cài Umami
  • Bài viết có chứa nội dung AI ảo giác chưa được con người biên tập lại
    Nó liên tục khẳng định đây là lỗ hổng liên quan đến Puppeteer nhưng thực tế không phải vậy

    • Ngay đoạn đầu nguyên văn đã ghi rõ là bản chép lại một phiên Claude
  • Gần đây Monero miner lợi dụng lỗ hổng React 19 đang được cài khắp nơi
    Tôi cũng gặp đúng vấn đề này

    • Loại malware đào coin như vậy lại khá hữu ích vì nó dễ bị chú ý và thiệt hại cũng nhỏ
      Nó hoạt động như một kiểu bug bounty tự động, tức là giúp báo cho bạn biết có lỗ hổng
      Nếu giám sát mạng hoặc tiến trình tốt thì có thể phát hiện khá dễ
    • Một máy chủ Umami của tôi trên Oracle Cloud đã bị nhiễm và tôi đã reset máy chủ
      Nhờ đó mà tôi có dịp tốt để nâng cấp hệ thống backup
  • Nhìn những trường hợp như vậy làm tôi thấy mình thật đúng khi không tự vận hành VPS
    Trước đây tôi đã thử rồi, nhưng cảm giác mình chỉ ở mức quản trị viên bình thường, rất khó duy trì bảo mật tốt
    Nên giờ giao cho chuyên gia làm và trả tiền còn khiến tôi yên tâm hơn nhiều