Giám sát an ninh mạng với Zeek trên Linux: Phân tích giao thức thời gian thực và trích xuất metadata

1. Vấn đề thực tế: Điểm mù mạng và cạn kiệt dung lượng lưu trữ

Trong một đợt đánh giá an ninh định kỳ trên toàn bộ hạ tầng cốt lõi, một tín hiệu beacon bất thường gửi ra ngoài đã kích hoạt cảnh báo netflow mức ưu tiên thấp. Cứ mỗi mười lăm phút, một máy chủ nội bộ lại gửi dữ liệu đến một địa chỉ IP chưa phân loại (198.51.100.45) qua cổng TCP 443. Tường lửa biên chỉ ghi nhận thông tin 5-tuple gồm: nguồn, đích, cổng và số lượng byte truyền tải. Chỉ có thế. Chúng tôi hoàn toàn không thể biết được tên miền SNI nào được yêu cầu, bộ mã hóa (cipher) TLS nào đã thỏa thuận, hay các header trong payload trao đổi ra sao.

Để điều tra, chúng tôi đã cấu hình mirror cổng uplink 1 Gbps và chạy tcpdump. Kết quả là cả một mớ hỗn độn về khâu vận hành. Chỉ trong vòng 48 giờ, sensor thu thập dữ liệu đã tích lũy tới 620 GB file .pcap thô, chia nhỏ trên ba mươi phân đoạn xoay vòng.

Mở một file PCAP dung lượng 4 GB mất tới tám phút và làm treo cứng Wireshark trên máy trạm có 32 GB RAM. Việc tìm kiếm một truy vấn DNS duy nhất trên nhiều file bị chia nhỏ đã tiêu tốn trọn một buổi chiều viết bash script. Khi một sự cố đang diễn ra, các chuyên viên phân tích cần câu trả lời ngay lập tức. Họ không thể lãng phí hàng giờ chỉ để giải nén các file PCAP nặng hàng chục gigabyte chỉ nhằm tìm ra một hostname đơn lẻ.

2. Phân tích nguyên nhân gốc rễ: Vì sao phương pháp phân tích gói tin truyền thống thất bại

Nút thắt cổ chai về khả năng quan sát xuất phát từ việc xem mọi dữ liệu lưu lượng đều như nhau. Các phương pháp giám sát truyền thống dựa trên những giả định sai lầm về lưu trữ gói tin, độ sâu phân tích giao thức và ngữ cảnh cảnh báo:

  • Lưu trữ payload bừa bãi: Việc bắt trọn gói tin thô sẽ thu thập tất cả mọi thứ—từ luồng video 4K đến các bản sao lưu file dung lượng lớn. Hơn 85% lưu lượng doanh nghiệp hiện đại ngày nay đều được mã hóa bằng TLS 1.3. Lưu trữ những byte ứng dụng đã mã hóa đó mà không có session key vừa làm nghẽn I/O ổ đĩa, vừa đẩy chi phí lưu trữ SAN lên cao chót vót mà không mang lại bất kỳ giá trị điều tra nào.
  • Mù mờ về trạng thái ứng dụng: Tường lửa stateful theo dõi các quá trình bắt tay TCP và số thứ tự sequence number, nhưng lại bỏ qua ngữ nghĩa của giao thức sau khi tái tạo (reassembly). Nếu kẻ tấn công chạy beacon Cobalt Strike tùy biến qua cổng 443, hệ thống giám sát ở Layer 4 vẫn sẽ gắn nhãn đó là HTTPS thông thường chỉ vì trùng số cổng.
  • Cảnh báo thiếu ngữ cảnh: Các engine NIDS truyền thống so khớp gói tin với các biểu thức chính quy (regex) tĩnh và phát ra các chuỗi cảnh báo cô lập. Khi cảnh báo kích hoạt, bạn vẫn phải trích xuất ngữ cảnh xung quanh một cách thủ công. Bạn cần truy vấn DNS trước đó, chuỗi chứng chỉ TLS và thời lượng kết nối để phân biệt giữa một cuộc xâm nhập thực sự và một trình quét vô hại.

3. So sánh các giải pháp: Full PCAP vs. Signature IDS vs. Zeek

Để cân bằng giữa chi phí vận hành và độ chính xác trong điều tra, chúng tôi đã thử nghiệm đánh giá ba kiến trúc quan sát mạng thụ động trên đường uplink core 1 Gbps:

Phương pháp giám sát Dung lượng lưu trữ (Đường truyền 1 Gbps, TB ~350 Mbps) Tốc độ truy vấn Ngữ cảnh giao thức Gánh nặng bảo trì
Full PCAP (tcpdump / daemonlogger) Cực lớn (~3,5 TB / ngày) Vài phút đến hàng giờ (quét BPF trên nhiều file chia nhỏ) Byte thô; cần tái tạo lại luồng (reassembly) Cao; cần script xoay vòng và dọn dẹp liên tục
Signature NIDS (Snort / Suricata) Thấp (~500 MB / ngày cho cảnh báo) Nhanh (được đánh chỉ mục trong SIEM) Rời rạc; metadata chỉ được lưu khi khớp rule Cao; liên tục tinh chỉnh rule để giảm cảnh báo giả
Trích xuất metadata (Zeek) Nhỏ gọn (15–30 GB / ngày) Dưới một giây với công cụ CLI (zeek-cut, ripgrep) Phân tích chuyên sâu theo trạng thái (HTTP, DNS, TLS, SSH, SMB) Thấp; tự động xoay vòng log và dự đoán được thời gian lưu trữ

Bắt toàn bộ gói tin (Full PCAP) vẫn có vai trò nhất định khi cần debug các giao thức chuyên biệt. Các engine dựa trên chữ ký (signature) sẽ báo cho bạn biết khi phát hiện một mẫu độc hại đã biết. Zeek tiếp cận theo một góc nhìn khác: nó vận hành như một kiểm toán viên giao thức tự động. Nó loại bỏ phần thân payload cồng kềnh, đồng thời phân tích và ghi lại mọi sự kiện giao thức thành các file log văn bản có cấu trúc, gọn nhẹ. Bạn có thể cắt giảm tới khoảng 95% dung lượng lưu trữ mà không làm giảm độ sâu điều tra.

4. Giải pháp tối ưu: Triển khai Zeek trên Linux để trích xuất metadata theo thời gian thực

Mô hình triển khai chuẩn xác nhất là đặt Zeek trên một node sensor chuyên dụng chạy Debian 12 hoặc Ubuntu 22.04 LTS. Máy chủ này nhận lưu lượng trực tiếp từ cổng SPAN của switch hoặc qua thiết bị TAP thụ động. Với môi trường có lưu lượng duy trì ổn định từ 500 Mbps đến 1 Gbps, một máy chủ cấu hình vừa phải gồm CPU 4 nhân, 16 GB RAM và bộ nhớ đệm log dùng ổ NVMe hoàn toàn có thể xử lý việc nạp dữ liệu mà không làm rớt gói tin nào.

Bước 1: Chuẩn bị hệ thống và cấu hình interface

Dành riêng một interface vật lý phụ (ví dụ: eth1 hoặc enp3s0) chỉ để thu thập lưu lượng. Xóa bỏ toàn bộ địa chỉ IP gán cho interface này để nó không thể định tuyến và hoàn toàn vô hình trên đường truyền. Tiếp theo, tắt các tính năng hardware offloading trên card mạng (NIC). Khi các tính năng như GRO (Generic Receive Offload) hoặc LRO được bật, driver NIC sẽ gộp các gói tin lại trước khi kernel kịp nhìn thấy. Điều này sẽ phá vỡ cơ chế tái tạo luồng TCP của Zeek.

# Bật interface ở chế độ promiscuous và không gán IP
sudo ip link set dev eth1 up
sudo ip link set dev eth1 promisc on

# Tắt hardware offloading TCP/UDP để giữ nguyên ranh giới gói tin thực tế
sudo ethtool -K eth1 rx off tx off gso off gro off tso off

Để duy trì các thiết lập NIC này sau mỗi lần reboot máy chủ, hãy tạo một script trong /etc/networkd-dispatcher/routable.d/50-sniffer.sh hoặc cấu hình một systemd service tùy chỉnh áp dụng riêng cho interface đó.

Bước 2: Cài đặt Zeek từ OpenSUSE Build Service

Kho package mặc định của các bản phân phối Linux thường đi kèm các bản Zeek đã lỗi thời. Hãy sử dụng repository chính thức từ OpenSUSE Build Service để cài đặt phiên bản Hỗ trợ dài hạn (LTS) mới nhất:

# Cài đặt các gói phụ thuộc phục vụ quản lý khóa
sudo apt-get update && sudo apt-get install -y curl gnupg2 lsb-release

# Import signing key của OpenSUSE
curl -fsSL https://download.opensuse.org/repositories/security:/zeek/xUbuntu_22.04/Release.key | \
  gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/security_zeek.gpg > /dev/null

# Thêm nguồn repository chính thức
echo 'deb http://download.opensuse.org/repositories/security:/zeek/xUbuntu_22.04/ /' | \
  sudo tee /etc/apt/sources.list.d/security:zeek.list

# Cập nhật danh sách gói và cài đặt Zeek LTS
sudo apt-get update
sudo apt-get install -y zeek-lts

# Xuất đường dẫn binary của Zeek vào profile mặc định
echo 'export PATH="$PATH:/opt/zeek/bin"' >> ~/.bashrc
source ~/.bashrc

Bước 3: Cấu hình subnet nội bộ và interface thu thập dữ liệu

Truy cập vào /opt/zeek/etc/ để cấu hình các tham số phát hiện cốt lõi.

Chỉnh sửa file /opt/zeek/etc/networks.cfg để định nghĩa các subnet RFC 1918 và ranh giới DMZ của bạn. Zeek sẽ so sánh các định nghĩa này với IP nguồn và IP đích để gắn nhãn hướng kết nối một cách chính xác:

10.0.0.0/8          Corporate_LAN
172.16.10.0/24      Production_DMZ
192.168.50.0/24     Management_VLAN

Tiếp theo, gắn Zeek vào card mạng thu thập dữ liệu trong file /opt/zeek/etc/node.cfg. Với mô hình sensor trên một máy chủ đơn lẻ, hãy cập nhật khối cấu hình standalone:

[zeek]
type=standalone
host=localhost
interface=eth1

Bước 4: Quản lý engine với zeekctl

Zeek tích hợp sẵn công cụ quản lý chuyên dụng là zeekctl, dùng để kiểm tra cấu hình, điều khiển tiến trình và quản lý worker:

# Kiểm tra cú pháp cấu hình
sudo /opt/zeek/bin/zeekctl check

# Triển khai cấu hình và khởi chạy các worker capture chạy ngầm
sudo /opt/zeek/bin/zeekctl deploy

# Kiểm tra trạng thái hoạt động của instance standalone
sudo /opt/zeek/bin/zeekctl status

Nếu trạng thái trả về running, Zeek đang tích cực phân tích lưu lượng thu thập từ eth1.

Bước 5: Truy vấn metadata đã trích xuất bằng zeek-cut

Zeek ghi liên tục các log có cấu trúc vào thư mục /opt/zeek/logs/current/. Mặc định, các file log là bảng dữ liệu định dạng TSV phân tách bằng tab với các header trường rõ ràng, tuy nhiên bạn cũng có thể bật đầu ra JSON nếu muốn đẩy trực tiếp vào Elasticsearch hoặc OpenSearch.

Các luồng log chính cần theo dõi bao gồm:

  • conn.log: Bản ghi toàn diện về mọi luồng kết nối, theo dõi thời lượng phiên, địa chỉ IP, cổng, cờ giao thức và tổng số byte truyền tải.
  • dns.log: Bản ghi đầy đủ về các truy vấn và phản hồi DNS, bao gồm loại bản ghi, tên truy vấn, địa chỉ đã phân giải và mã RCODE của DNS server.
  • ssl.log: Các chỉ số chi tiết về quá trình đàm phán TLS, hiển thị chuỗi Server Name Indication (SNI), chủ thể chứng chỉ đã xác thực, CN của bên phát hành và bộ cipher được chọn.
  • http.log: Các yêu cầu HTTP không mã hóa, ghi lại URI được yêu cầu, phương thức HTTP, host header, mã trạng thái và chuỗi user-agent.

Thay vì dùng các công cụ giao diện đồ họa (GUI), bạn có thể truy vấn trực tiếp lưu lượng mạng ngay trên CLI bằng zeek-cut:

# Lọc top 10 domain ngoại vi được truy vấn nhiều nhất
zeek-cut query answers < /opt/zeek/logs/current/dns.log | \
  sort | uniq -c | sort -nr | head -n 10

# Săn lùng các domain SNI ngoại vi đáng ngờ và cipher cũ trong TLS handshake
zeek-cut id.orig_h id.resp_h server_name cipher < /opt/zeek/logs/current/ssl.log | \
  grep -v "yourdomain.com" | head -n 15

# Xác định các kết nối TCP kéo dài bất thường (sắp xếp theo thời lượng tính bằng giây)
zeek-cut id.orig_h id.resp_h duration proto service < /opt/zeek/logs/current/conn.log | \
  awk '$3 > 3600' | sort -k3 -nr | head -n 10

Bước 6: Viết script phát hiện tùy chỉnh dựa trên sự kiện

Zeek đồng thời là một ngôn ngữ phân tích mạng có thể lập trình được. Kiến trúc hướng sự kiện (event-driven) của nó cho phép bạn viết các khối logic chuyên biệt, được thực thi bất cứ khi nào state machine của giao thức thay đổi trạng thái. Ví dụ, nếu chính sách cấm sử dụng TLS 1.0 và 1.1, bạn có thể đánh dấu các phiên handshake không tuân thủ trực tiếp vào notice.log.

Tạo file /opt/zeek/share/zeek/site/detect-insecure-tls.zeek:

@load base/protocols/ssl
@load base/frameworks/notice

module SecurityMonitoring;

export {
    redef enum Notice::Type += {
        Insecure_TLS_Version
    };
}

event ssl_established(c: connection)
    {
    if ( ! c?$ssl )
        return;

    # Kích hoạt cảnh báo nếu handshake sử dụng các phiên bản TLS cũ
    if ( c$ssl?$version && (c$ssl$version == "TLSv10" || c$ssl$version == "TLSv11") )
        {
        NOTICE([$note=Insecure_TLS_Version,
                $msg=fmt("Phiên bản TLS không an toàn: %s từ %s đến %s (SNI: %s)", 
                         c$ssl$version, c$id$orig_h, c$id$resp_h, 
                         c$ssl?$server_name ? c$ssl$server_name : "<không có>"),
                $conn=c]);
        }
    }

Kích hoạt script bằng cách thêm dòng include vào file cấu hình site nội bộ của bạn:

echo '@load detect-insecure-tls.zeek' | sudo tee -a /opt/zeek/share/zeek/site/local.zeek
sudo /opt/zeek/bin/zeekctl deploy

Bất cứ khi nào có một client nội bộ thực hiện bắt tay bằng phiên bản giao thức cũ đã bị vô hiệu hóa, Zeek sẽ ghi một mục có cấu trúc vào /opt/zeek/logs/current/notice.log. Bản ghi này bao gồm IP client, server đích, phiên bản đã thỏa thuận và hostname SNI được yêu cầu.

Việc triển khai Zeek trên Linux cung cấp cho đội ngũ SOC khả năng kiểm tra giao thức với độ chính xác cao mà vẫn giữ dung lượng lưu trữ ở mức dự đoán được. Bằng cách tách biệt metadata vận hành hữu ích khỏi các byte payload thô, các chuyên viên phân tích có thể chuyển từ việc phải bơi trong hàng chục gigabyte PCAP sang truy vấn trạng thái giao dịch theo thời gian thực chỉ trong vài giây.

Share: