Access Hub Scanner
Đang phát triểnĐồng bộ từ mã nguồn lúc 10:57, 03/10/2026
Skip to content

Kiểm kê và so khớp ​

10 phút đọcCập nhật 02/10/2026access-hub-scanner, docs/04-inventory-and-matching.md

1. Mô hình inventory ​

Một inventory là ảnh chụp các gói đã cài của một máy tại một thời điểm, cộng thông tin hệ điều hành và kernel. Từ giai đoạn P2 và P6 inventory có thêm dịch vụ, phần mềm ngoài gói, thống kê tệp và tệp đáng chú ý (mục 8). Scanner tạo, secmatch lưu bản mới nhất theo (company_id, server_id) (ADR 0008).

TrườngVí dụGhi chú
os.id, os.version_id, os.codename, os.id_likeubuntu, 22.04, jammy, debianTừ /etc/os-release
os.variantubuntu-pro, rhel-eusChỉ khi xác định được từ tệp cấu hình kho (Q15)
kernel.running6.8.0-142-genericuname (syscall, không gọi lệnh)
kernel.installed[]Danh sách gói kernel đã càiĐể phát hiện "cần khởi động lại"
packages[].managerdpkg, rpm, apk
packages[].name, archlibssl3, amd64Tên gói nhị phân
packages[].version3.0.2-0ubuntu1.15Chuỗi đầy đủ theo hệ (dpkg gồm epoch nếu có)
packages[].epoch, releaserpm: 1, 11.el9_4rpm tách EVR
packages[].source_name, source_versionopenssl, 3.0.2-0ubuntu1.15dpkg Source: (có thể kèm phiên bản trong ngoặc), rpm header SOURCERPM
packages[].vendorRed Hat, Inc.rpm header VENDOR, dùng để nhận gói bên thứ ba
packages[].modulenodejs:18:8090020240123:a75119d5rpm header MODULARITYLABEL (RHEL 8 module stream)
packages[].statusinstalleddpkg: chỉ lấy install ok installed; bỏ config-files, half-installed

Không thu: danh sách tệp của gói, script cài, nội dung tệp cấu hình, người cài, thời điểm cài theo người dùng.

Kích thước: một máy chủ thường có vài trăm đến vài nghìn gói (đo thực tế ở spike S5). Mỗi gói sau mã hóa protobuf khoảng 60 đến 120 byte, nén tốt vì chuỗi lặp. Đích SNFR-11: dưới 150 KB nén cho 3.000 gói.

2. Đọc DB gói trên máy ​

HệNguồnCách đọcRủi ro
dpkg/var/lib/dpkg/statusParser định dạng RFC 822 đơn giản, đọc tuần tự, đọc được không cần rootTệp lớn vài MB, đọc một lần
rpm 4.11 đến 4.14 (RHEL 7, 8)/var/lib/rpm/Packages (Berkeley DB)Thư viện Go thuần đọc BDB hash (ứng viên go-rpmdb)Đọc khi dnf đang ghi: mở chỉ đọc, thử lại, đánh dấu error nếu không nhất quán
rpm 4.16 trở lên (RHEL 9)/var/lib/rpm/rpmdb.sqliteCần SQLite thuần Go (ảnh hưởng kích thước binary, S1)Như trên
rpm NDB (SUSE)/var/lib/rpm/Packages.dbThư viện như trên nếu hỗ trợBest-effort
apk/lib/apk/db/installedParser văn bản (khóa một ký tự P:, V:, A:, o:)Thấp

Nguyên tắc: đọc tệp trực tiếp, không gọi lệnh. Nếu spike S1 cho thấy không đọc được một định dạng bằng Go thuần, phương án dự phòng duy nhất được phép là gọi binary hệ thống bằng đường dẫn tuyệt đối với đối số cố định trong mã (ví dụ /usr/bin/rpm -qa --qf <định dạng cố định>), không bao giờ nhận đối số từ cấu hình từ xa. Cần ghi lại bằng ADR nếu dùng.

Phát hiện thay đổi rẻ (SFR-07): lưu mtime, kích thước, inode của tệp DB gói ở lần quét trước trong /var/lib/accesshub-scanner/state.json; timer mỗi giờ chỉ stat các tệp này.

3. So sánh phiên bản ​

Lõi độ chính xác, tự viết và kiểm thử bằng bảng lấy từ công cụ gốc (dpkg --compare-versions, rpmdev-vercmp, apk version -t) chạy trong CI trên container distro (ADR 0007). Không dùng so sánh semver.

3.1 dpkg (Debian, Ubuntu) ​

  • Dạng [epoch:]upstream_version[-debian_revision]. Epoch vắng là 0.
  • So epoch theo số, rồi upstream, rồi revision bằng thuật toán verrevcmp: tách luân phiên phần không số và phần số; phần không số so từng ký tự, chữ cái xếp trước ký tự không phải chữ cái, ~ xếp trước mọi thứ kể cả chuỗi rỗng; phần số so theo giá trị.
  • Ví dụ cần có trong bộ kiểm thử: 1.0~rc1 < 1.0, 1:0.9 > 2.0, 3.0.2-0ubuntu1.15 > 3.0.2-0ubuntu1.9, hậu tố +esm1, +deb12u1.

3.2 rpm (họ RHEL, SUSE) ​

  • So EVR: epoch (vắng là 0), rồi version, rồi release bằng rpmvercmp: tách thành đoạn chữ hoặc số, bỏ ký tự phân cách; đoạn số mới hơn đoạn chữ; số so theo giá trị (bỏ số 0 đầu), chữ so theo thứ tự byte; ~ xếp trước (tiền phát hành); ^ xếp sau bản gốc nhưng trước bản kế tiếp (rpm 4.15 trở lên).
  • Phạm vi theo luồng: advisory Red Hat gắn với sản phẩm (BaseOS, AppStream, CodeReady, EUS). Gói có MODULARITYLABEL chỉ được so với advisory của đúng module stream đó, nếu không sẽ báo sai giữa các dòng phiên bản.
  • release chứa dấu hiệu bản phát hành (el9_4), giúp phát hiện gói lẫn từ phiên bản distro khác.

3.3 apk (Alpine) ​

  • Dạng số[.số]*[chữ][_hậu tố[số]]*[-rN]. Thứ tự hậu tố: _alpha < _beta < _pre < _rc < (không hậu tố) < _cvs < _svn < _git < _hg < _p. Revision -rN so cuối cùng.

4. Thuật toán so khớp (secmatch) ​

Với mỗi gói đã cài của máy thuộc hệ E (ví dụ ubuntu:22.04):

  1. Chọn khóa tra: Debian và Ubuntu dùng gói nguồn (source_name), họ RHEL và Alpine dùng tên gói nhị phân (cộng module stream nếu có).
  2. Lấy các mục affected của E với khóa đó.
  3. Với mỗi mục:
    • Có phiên bản sửa và phiên bản đã cài < phiên bản sửa: finding trạng thái open, fix_available = true, fixed_version.
    • Distro báo chưa sửa (needed, deferred, Debian open): finding open, fix_available = false, nhãn no_fix (Q8).
    • Distro báo không sửa (ignored, will not fix, Debian no-dsa có chú thích không sửa): finding nhãn wont_fix, mức ưu tiên hạ theo 06.
    • not-affected, DNE, phiên bản đã cài lớn hơn hoặc bằng bản sửa: không có finding.
  4. Gộp: một finding cho mỗi (máy, mã lỗ hổng chuẩn, khóa gói), liệt kê mọi gói nhị phân bị ảnh hưởng. Một lần nâng gói nguồn đóng một finding.
  5. Mã lỗ hổng chuẩn: CVE nếu có trong aliases, nếu không giữ mã advisory (USN, DSA, RHSA, GHSA). Advisory chứa nhiều CVE sinh nhiều finding, mỗi finding nhắc mã advisory để người dùng biết một bản cập nhật sửa nhiều CVE.
  6. Khóa ổn định: finding_key = SHA-256(company_id | server_id | vuln_id | ecosystem | package_key). Dùng làm khóa idempotent ở secmatch và Access Hub.
  7. So với tập finding đang mở của máy: sinh finding.opened, finding.resolved (biến mất khi quét lại, ghi resolved_reason = package_updated hoặc package_removed), finding.rescored.

So khớp lại khi DB đổi (5.2 của 02): chạy đúng thuật toán trên mọi inventory đã lưu, theo lô từng công ty, có giới hạn đồng thời, chỉ phát delta. resolved_reason = advisory_changed khi distro đổi dữ liệu (ví dụ sửa lại thành not-affected).

4.1 Bản phát hành hết hỗ trợ ​

Chính sách của chủ dự án (2026-10-02): lỗ hổng vẫn là lỗ hổng. Bản phát hành hết hỗ trợ (SUPPORT_EOL trong secdb, có eol_date) vẫn được so khớp như bản đang hỗ trợ, máy có trạng thái release_eol nhưng giữ mọi finding:

  1. Dữ liệu: Debian 10, 11 không còn trong tracker của Debian; secdb-build đọc Freexian ELTS tracker (cùng định dạng, --debian-elts-file, --no-elts) chỉ cho các bản hết hỗ trợ. Ubuntu LTS hết chuẩn chuyển sang ESM nên vẫn có dữ liệu.
  2. Distro sẽ không sửa: finding chưa sửa (no_fix, wont_fix, undetermined) mang no_distro_fix = true. Bản sửa mới hơn mọi phiên bản có trong kho công khai của Debian cho bản phát hành đó chỉ có qua ELTS trả phí: kênh elts, cũng no_distro_fix = true. Bản sửa đã nằm trong kho công khai (DSA, DLA trước khi hết LTS) giữ fixed, kênh standard: cài được ngay.
  3. Khuyến nghị nâng cấp: thêm một finding kind = release_eol, vuln_id = AHS-EOL-<DISTRO>-<VERSION>, fix_status = upgrade_release, mức high, eol_date, upgrade_to (các bản đang hỗ trợ của cùng distro trong secdb). Finding này đóng với release_upgraded khi máy chuyển bản phát hành.
  4. Finding không bị đóng out_of_scope khi bản phát hành chuyển sang hết hỗ trợ.

4.2 Nhiều nguồn ​

Từ SDB-5 (ADR 0007 đã sửa): secdb mang bản ghi theo từng nguồn; secmatch chọn bản ghi quyết định theo chính sách ưu tiên của distro, dùng ngay bản ghi mới của nguồn nhanh hơn với cờ unconfirmed, và gắn vào finding decided_by, confirmed_by, disputed_by, sources_agree. Thuật toán ở mục 4 không đổi: chỉ bước 2 chọn bản ghi theo chính sách thay vì đọc một bản ghi đã gộp. Bản P1 là trường hợp một nguồn mỗi distro.

5. Kernel ​

  • Finding kernel tính trên gói của kernel đang chạy (Ubuntu: linux-image-$(uname -r), gói nguồn như linux, linux-hwe-6.8, linux-aws; RHEL: kernel-<uname -r>).
  • Có gói kernel mới hơn đã cài và bản đó sửa CVE: finding giữ open với nhãn reboot_required, hướng dẫn khắc phục là khởi động lại, đồng thời kiểm tra AHS-UPD-003 không đạt.
  • Vá nóng (Canonical Livepatch, kpatch) có thể đã sửa CVE mà phiên bản gói không đổi: nguồn dương tính giả đã biết. P1 chỉ ghi nhận livepatch_active (đọc /sys/kernel/livepatch/) để hiển thị cảnh báo; ánh xạ bản vá nóng sang CVE là câu hỏi mở (Q15).

6. Dương tính giả: nguồn và cách xử lý ​

NguồnXử lý
So theo NVD CPE cho gói OS (không biết backport)Cấm theo ADR 0004. NVD chỉ làm giàu
Gói từ kho bên thứ ba (PPA, kho hãng như Docker, NGINX, PostgreSQL PGDG) cùng tên gói distrorpm: so VENDOR với danh sách nhà phát hành distro, khác thì gắn third_party và không so với dữ liệu distro. dpkg: tệp status không mang nguồn kho; giai đoạn P1 gắn origin_unknown khi phiên bản không mang dấu hiệu distro (ví dụ thiếu ubuntu, deb12u), giai đoạn P3 xem xét đọc /var/lib/apt/lists/*_Packages để xác định kho (tốn IO, cần đo)
Gói ở trạng thái config-files hoặc đã gỡKhông đưa vào inventory
Distro derivative (ID_LIKE=ubuntu như Linux Mint)unsupported_os, không so khớp, hiển thị rõ. Có hỗ trợ hay không là quyết định sản phẩm
Kernel cài nhưng không chạyChỉ kernel đang chạy sinh finding
Vá nóng kernelMục 5
Lỗ hổng chỉ khai thác được khi bật tính năng không dùngKhông tự suy luận. Người dùng tạo ngoại lệ false_positive hoặc compensating_control (06 mục 6)
Dữ liệu distro saiNgoại lệ ở Access Hub; nền tảng nhận thống kê ẩn danh số ngoại lệ dương tính giả theo (vuln_id, ecosystem, package_key) khi ít nhất k công ty cùng đánh dấu, để báo ngược nhà phát hành distro (không kèm tên công ty)

Ngoại lệ không bao giờ xóa finding: finding vẫn tồn tại với trạng thái accepted hoặc false_positive, có hạn, tự mở lại khi hết hạn (06).

7. Mở rộng sau ​

7.1 Hệ sinh thái ngôn ngữ (giai đoạn P6) ​

Ở vị trí hệ thống (mục 8.2) mặc định; thêm tệp khóa phụ thuộc (package-lock.json, poetry.lock, composer.lock, go.sum) ở thư mục do quản trị viên chọn, có trần số tệp, vì tốn IO và dễ lộ đường dẫn dự án. Dữ liệu từ OSV và GitHub advisories, khóa gói dạng purl, so sánh phiên bản semver, PEP 440, Maven (SMT-7). Quyết định phạm vi ở Q19.

7.2 Container và image (giai đoạn P9) ​

Hai hướng (Q19): (1) scanner trên máy đọc image của container đang chạy qua socket của Docker hoặc containerd, việc này tương đương quyền root và phải xem lại ADR 0001; (2) quét image trong registry từ trung tâm, không chạm máy. Cùng thuật toán so khớp, hệ alpine:3.20, debian:12 lấy từ os-release trong image.

7.3 Windows (giai đoạn P8) ​

Inventory từ registry (khóa Uninstall), bản build hệ điều hành và KB đã cài. Microsoft công bố theo sản phẩm và KB, không theo gói, nên cần mô hình so khớp riêng (bản build tích lũy). Q18.

8. Kiểm kê mở rộng: dịch vụ, phần mềm, tệp ​

Mục tiêu: trả lời "trên máy có gì" ngoài danh sách gói, để tìm phần mềm chạy ngoài trình quản lý gói (thường là nơi lỗ hổng bị bỏ quên) và biết dịch vụ nào đang bật. Chỉ siêu dữ liệu, cùng nguyên tắc đọc tệp trực tiếp, không gọi lệnh.

8.1 Dịch vụ (giai đoạn P6, SFR-50) ​

TrườngNguồn
nameTệp unit trong /etc/systemd/system, /run/systemd/system, /usr/lib/systemd/system, /lib/systemd/system
unit_file_stateenabled (có liên kết trong *.wants/, *.requires/), disabled, static, masked (liên kết tới /dev/null)
active_stateactive, inactive, failed, unknown: qua phương thức chỉ đọc ListUnits của systemd trên D-Bus hệ thống nếu S10 và Q44 đồng ý, nếu không thì unknown
packageGói sở hữu tệp unit (so danh sách tệp của gói, cùng chi phí với AHS-FS-005)

Không gửi nội dung tệp unit, Environment=, ExecStart= (có thể chứa bí mật; bí mật trong tệp unit do detector AHK-* tìm trên máy).

8.2 Phần mềm ngoài gói (giai đoạn P6, SFR-51, SFR-52) ​

LoạiNguồnTrường
snap/snap/*/current/meta/snap.yamltên, phiên bản
flatpak/var/lib/flatpak/app/*/current/active/metadatatên, phiên bản
binaryELF trong /usr/local/bin, /usr/local/sbin, /opt/** không thuộc gói nàotên, đường dẫn, kích thước, SHA-256
goBuild info nhúng trong binary Go (module, phiên bản, phụ thuộc)purl pkg:golang/...
pypidist-info/METADATA dưới /usr/lib/python3*/, /usr/local/lib/python3*/ không thuộc góipurl pkg:pypi/...
npmpackage.json trong node_modules toàn cục (/usr/lib/node_modules, /usr/local/lib/node_modules)purl pkg:npm/...
mavenMETA-INF/MANIFEST.MF, META-INF/maven/**/pom.properties trong .jar dưới /opt, /usr/share/java không thuộc gói (đọc zip có giới hạn như ADR 0009 mục 3)purl pkg:maven/...

Trần: 20.000 mục mỗi báo cáo (07 mục 3.4), ngân sách nằm trong lượt siêu dữ liệu (SNFR-01 đến SNFR-05), thư mục lớn có điểm dừng.

8.3 Tệp (giai đoạn P2, P6, SFR-54) ​

Chỉ mục cục bộ của lượt nội dung (ADR 0009 mục 5) giữ danh sách đầy đủ tệp trong phạm vi, không rời máy. Báo cáo gửi thống kê theo gốc và tệp đáng chú ý (14 mục 6). Kiểm tra quyền tệp (AHS-FS-*) vẫn dùng lượt lstat của lượt siêu dữ liệu (05 mục 5).

Trang này có giúp được bạn không?
Sửa trang này

Nội dung đồng bộ từ kho mã access-hub-scanner lúc 10:57, 03/10/2026. Khi tài liệu và mã khác nhau, mã thắng.