Bảo Mật Windows Server Từ Cơ Bản Đến Nâng Cao (Phần 2)
Giám sát & audit log, Sysmon, WDAC/AppLocker, Attack Surface Reduction, sao lưu chống ransomware — đầy đủ lệnh PowerShell cho IT Admin, đối chiếu Microsoft Learn/CISA. Phần 2/2 loạt Bảo Mật Windows Server Từ Cơ Bản Đến Nâng Cao.
Đội ngũ STEP Technology
Chuyên gia IT & Hạ tầng
Máy chủ đã cứng hơn — nhưng bạn có thấy được lúc nó bị chạm vào không?
Phần 1 đã đóng khá nhiều cửa: firewall mặc định chặn inbound, Administrator mặc định đã đổi tên/vô hiệu hoá, Script Block Logging bật, SMB/LDAP bắt buộc ký số. Nhưng đóng cửa không có nghĩa không ai vào được — nó chỉ có nghĩa là cửa chính khó hơn. Một ứng dụng web có lỗ hổng chưa vá, một tài khoản dịch vụ dùng mật khẩu cũ bị lộ trong một vụ rò rỉ dữ liệu khác, một file đính kèm email ai đó lỡ mở trên máy trạm rồi từ đó leo thang vào server — tất cả những đường này không đi qua RDP hay LDAP, và baseline ở Phần 1 không bắt được.
Vậy câu hỏi bây giờ là: nếu một trong những đường trên xảy ra, bạn biết trong bao lâu? Bạn có log nào ghi lại chính xác process nào vừa được tạo ra trên server ngay lúc này, hay chỉ biết khi có người báo dịch vụ ngừng chạy? Và nếu tệ nhất xảy ra — dữ liệu bị mã hoá hết bởi ransomware — bản backup bạn đang có có thật sự phục hồi được, hay đó là thứ bạn tin là phục hồi được vì chưa từng thử?
Bài này — Phần 2, khép lại loạt hai bài — đi vào bốn mảng còn lại: giám sát để phát hiện sớm khi những lớp phòng thủ ở Phần 1 bị vượt qua, kiểm soát ứng dụng và thu hẹp bề mặt tấn công ở tầng sâu hơn, chiến lược sao lưu chống được cả ransomware chứ không chỉ hỏng đĩa, và một đoạn ngắn nhắc lại các lớp mã hoá đã viết riêng ở bài trước. Đọc Phần 1 trước nếu chưa đọc — nhiều mục ở đây giả định bạn đã có nền baseline/danh tính/PowerShell/mạng từ đó, đặc biệt là Event ID và cơ chế log đã nói ở Mục 3.1.
Giống Phần 1, một số nội dung ở đây — đặc biệt là bật WDAC/AppLocker ở chế độ Enforce, bật Attack Surface Reduction rules ở chế độ Block, và thử phục hồi (restore test) — có thể chặn nhầm phần mềm nghiệp vụ đang chạy thật, hoặc nếu làm ẩu, ghi đè lên dữ liệu production. Đây là hai kiểu rủi ro khác nhau, khác cả rủi ro tự khoá mình ra khỏi RDP/WinRM đã nói ở Phần 1 — đọc kỹ Bước 0 ngay dưới trước khi chạy bất kỳ lệnh nào ở Mục 6 và Mục 7. Hãy thử trên môi trường không phải production trước, đảm bảo có bản sao lưu đã kiểm chứng, và thực hiện trong khung giờ bảo trì đã báo trước — đúng nguyên tắc đã nói ở Phần 1. Nội dung bài mang tính hướng dẫn kỹ thuật, không thay thế cho việc đánh giá rủi ro riêng của từng hệ thống — mỗi môi trường có ứng dụng, thiết bị và lịch sử cấu hình khác nhau. Người thực hiện chịu trách nhiệm kiểm thử và xác nhận trước khi áp dụng lên hệ thống đang chạy; STEP không chịu trách nhiệm cho thiệt hại hoặc gián đoạn phát sinh từ việc áp dụng trực tiếp các lệnh trong bài mà chưa qua bước kiểm thử này.
Bước 0 — Hai loại rủi ro riêng của bài này, và cách chuẩn bị
Rủi ro ở Phần 1 chủ yếu là "tự khoá mình ra khỏi máy" — có đường lùi bằng console/GPO restore. Rủi ro ở bài này khác về bản chất, nên đường lùi cũng khác:
Nhóm 1 — CHẶN NHẦM phần mềm đang chạy thật (Mục 6.2, 6.3, 6.4):
- WDAC/AppLocker ở chế độ Enforce (mục 6.2): nếu policy sinh ra thiếu (ví dụ chỉ quét được một phần phần mềm đang dùng), nó chặn cả ứng dụng nghiệp vụ hợp lệ — và tệ nhất, chặn luôn cả
powershell.exe/cmd.exenếu chưa được đưa vào rule, khiến bạn không gõ được lệnh gỡ chính sách vừa áp. - Attack Surface Reduction rules ở chế độ Block (mục 6.3): có thể chặn PSExec/WMI (chính công cụ agent backup/RMM/SCCM đang dùng), chặn Office macro nghiệp vụ hợp lệ, hoặc chặn cả các tiến trình đọc bộ nhớ LSASS một cách vô hại.
- Exploit Protection đặt sai mitigation cho một ứng dụng cụ thể (mục 6.4) có thể làm ứng dụng đó crash — và với mitigation mức hệ thống, sự cố có thể chỉ nổ ra ở lần khởi động lại kế tiếp, có khi vài tuần sau khi bạn đã quên mình từng đổi gì.
Đường lùi cho nhóm này luôn có — đều là cấu hình phần mềm, đảo ngược được bằng đúng lệnh nêu ở từng mục. Nhưng nếu policy khoá luôn cả công cụ bạn dùng để sửa lỗi (PowerShell, Registry Editor), đường lùi duy nhất còn lại là console/iDRAC/iLO khởi động vào Safe Mode hoặc gỡ policy từ xa qua một phiên quản trị khác chưa bị áp policy đó. Với thay đổi đẩy qua GPO (Mục 5.1, 5.2, 6.2 nhánh -Ldap, 6.3 qua GPO), console một máy KHÔNG cứu được — máy nhận lại đúng policy sai ở chu kỳ đồng bộ tiếp theo; đường lùi đúng là Restore-GPO từ bản backup (xem việc 1 dưới đây) hoặc gỡ link GPO khỏi OU trong Group Policy Management Console.
Nhóm 2 — MẤT DỮ LIỆU THẬT, không hoàn tác được (Mục 7.2, 7.3):
- Chọn ổ đĩa đích cho backup định kỳ (mục 7.2):
Add-WBBackupTargetFORMAT ổ đích và xoá vĩnh viễn dữ liệu đang có trên đó ngay khi lệnh chạy — không phải đợi tới lúc lưu lịch. Chọn nhầm ổ đang chứa dữ liệu thật là mất dữ liệu đó ngay lập tức. - Restore test (mục 7.3): phục hồi đè lên đúng vị trí đang chứa dữ liệu production (chọn nhầm
-recoveryTarget, nhầm ổ đĩa đích) thì dữ liệu mới hơn bị ghi đè bởi bản backup cũ.
Cả hai hành động này không có đường lùi nếu làm sai — khác hẳn nhóm 1 ở trên, nơi mọi thứ đều đảo ngược được bằng lệnh.
Việc cần làm trước khi bắt đầu Mục 5 trở đi:
1. Sao lưu toàn bộ GPO của domain — đường lùi THẬT cho các thay đổi cấp domain ở Mục 5.1, 5.2, 6.2 (-Ldap), 6.3 (qua GPO):
New-Item -ItemType Directory -Path "D:\Backup\GPO" -Force | Out-Null
Backup-GPO -All -Path "D:\Backup\GPO" -Comment "Truoc khi lam Phan 2"(Bỏ qua việc này nếu toàn bộ thay đổi bạn định làm chỉ áp cục bộ trên một máy, không qua GPO.)
2. Đã có một bản sao lưu toàn máy đã từng thử phục hồi thành công — giống Bước 0 của Phần 1. Nghịch lý nhỏ nhưng thật: Mục 7 của bài này mới dạy cách backup và test phục hồi, nhưng Mục 6 đã có thể làm hỏng máy trước khi bạn đọc tới đó — đừng để Mục 6 là lần đầu bạn cần dùng tới backup.
3. Xác nhận có đường vào ngoài băng thông (console/iDRAC/iLO/KVM) cho bất kỳ máy nào sẽ thử nghiệm AppLocker/WDAC/ASR/Exploit Protection ở Mục 6 — nếu policy khoá luôn cách bạn đang gõ lệnh (RDP, WinRM, cả PowerShell cục bộ), đây là đường duy nhất còn lại cho thay đổi cục bộ.
4. Ưu tiên máy KHÔNG phải production để thử lần đầu. Nếu bắt buộc làm trực tiếp trên máy đang chạy dịch vụ thật, luôn bắt đầu ở Audit mode cho Mục 6.2 và 6.3; riêng Mục 6.4 (Exploit Protection), ba mitigation cơ bản DEP/SEHOP/CFG không có chế độ Audit — bù lại bằng cách thử trên máy không production trước, và chủ động khởi động lại ngay trong khung giờ bảo trì để phát hiện sự cố tại chỗ, đừng để tới lần reboot ngoài kế hoạch mới biết.
5. Chuẩn bị một ổ đĩa hoặc máy ảo THAY THẾ, tách biệt hoàn toàn khỏi dữ liệu production, dành riêng cho việc chọn đích backup ở Mục 7.2 và thử phục hồi ở Mục 7.3 — quyết định trước nơi làm, đừng để tới lúc gõ lệnh mới chọn ngẫu nhiên.
6. Ghi lại cấu hình đang có trước khi đổi, ở dạng nhập lại được (không phải một file .txt chỉ để đọc) — để biết chính xác cái gì đã thay đổi, và để có gì phục hồi nếu cần:
$thuMuc = "D:\Backup\truoc-phan2" # đổi sang ổ khác nếu máy không có D:
New-Item -ItemType Directory -Path $thuMuc -Force | Out-Null
Get-MpPreference | Export-Clixml "$thuMuc\defender-preference.xml"
Get-AppLockerPolicy -Local -Xml | Set-Content "$thuMuc\applocker-truoc.xml" -Encoding UTF8
Get-ProcessMitigation -RegistryConfigFilePath "$thuMuc\exploit-protection-truoc.xml"
auditpol /backup /file:"$thuMuc\audit-policy-truoc.csv"
Get-Service -Name Sysmon* -ErrorAction SilentlyContinue |
Select-Object Name, Status, StartType | Export-Csv "$thuMuc\sysmon-truoc.csv" -NoTypeInformationBốn file đầu là bản nhập lại được: Set-AppLockerPolicy -XmlPolicy, Set-ProcessMitigation -PolicyFilePath, auditpol /restore /file: đều đọc đúng định dạng này để phục hồi lại cấu hình cũ — một file .txt in ra màn hình không phải bản backup.
7. Có người thứ hai biết bạn đang làm gì, có số điện thoại liên lạc được — giống Bước 0 của Phần 1.
Cách xác nhận trước khi sang Mục 5: trả lời "có" cho cả bảy câu, còn một câu "chưa" thì dừng lại:
- Đã xác định được đường vào ngoài băng thông cho máy sẽ test Mục 6 chưa?
- Có máy không phải production để thử trước không? (Nếu không — đã chấp nhận nguyên tắc "Audit trước, Enforce sau" ở 6.2/6.3, và "khởi động lại trong khung giờ bảo trì" ở 6.4 chưa?)
- Đã chọn sẵn ổ/máy thay thế cho việc chọn đích backup ở Mục 7.2 và phục hồi thử ở Mục 7.3, tách biệt khỏi dữ liệu thật chưa?
- Đã ghi lại cấu hình ASR/AppLocker/Exploit Protection/Sysmon hiện tại — ở định dạng nhập lại được — chưa?
- Có người thứ hai biết bạn đang làm gì chưa?
- Đã sao lưu toàn bộ GPO của domain chưa? (bỏ qua nếu mọi thay đổi chỉ làm cục bộ trên một máy)
- Đã có bản sao lưu toàn máy đã từng thử phục hồi thành công chưa?
5. Giám sát & phát hiện
5.1 Advanced Audit Policy Configuration — bật đúng log trước khi cần đến nó
Việc cần làm: Chuyển sang Advanced Audit Policy (59 subcategory nhỏ chia trong 10 category, thay cho 9 category thô kiểu cũ) và bật đúng tập subcategory tối thiểu Microsoft khuyến nghị.
Vì sao: Advanced Audit Policy Configuration nằm ở Computer Configuration\Windows Settings\Security Settings\Advanced Audit Policy Configuration\System Audit Policies trong Group Policy — theo đúng mô tả chính thức của Microsoft, các setting này "cho phép admin chọn chính xác hoạt động nào cần audit", thay vì phải bật nguyên một category thô kiểu cũ (kéo theo rất nhiều event không cần thiết). Đây cũng chính là tập subcategory mà Microsoft dùng làm điều kiện tối thiểu cho Windows Event Forwarding ở Mục 5.2 — bật đúng ở đây, Mục 5.2 mới có gì để chuyển tiếp.
Cách thực thi — theo đúng bảng "Minimum recommended audit policy" của Microsoft (không liệt kê toàn bộ subcategory, chỉ những cái Microsoft xác nhận cần cho baseline giám sát/phát hiện xâm nhập):
# Account Logon
auditpol /set /subcategory:"Credential Validation" /success:enable /failure:enable
# Account Management
auditpol /set /subcategory:"Security Group Management" /success:enable
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Computer Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Other Account Management Events" /success:enable /failure:enable
# Detailed Tracking - nền tảng cho Sysmon/EDR đọc process sau này ở Mục 5.3
auditpol /set /subcategory:"Process Creation" /success:enable
auditpol /set /subcategory:"Process Termination" /success:enable
# Logon/Logoff
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable
auditpol /set /subcategory:"Other Logon/Logoff Events" /success:enable /failure:enable
auditpol /set /subcategory:"Special Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Account Lockout" /success:enable
# Object Access - chỉ 2 subcategory này là "Success" trong bảng khuyến nghị tối thiểu,
# còn lại (File System, Registry...) Microsoft để "Not configured" ở mức tối thiểu
auditpol /set /subcategory:"File Share" /success:enable
auditpol /set /subcategory:"Removable Storage" /success:enable
# Policy Change - phát hiện ai vừa đổi chính sách bảo mật
auditpol /set /subcategory:"Audit Policy Change" /success:enable /failure:enable
auditpol /set /subcategory:"MPSSVC Rule-Level Policy Change" /success:enable /failure:enable
auditpol /set /subcategory:"Other Policy Change Events" /success:enable /failure:enable
auditpol /set /subcategory:"Authentication Policy Change" /success:enable /failure:enable
auditpol /set /subcategory:"Authorization Policy Change" /success:enable /failure:enable
# System
auditpol /set /subcategory:"Security State Change" /success:enable /failure:enable
auditpol /set /subcategory:"Security System Extension" /success:enable /failure:enable
auditpol /set /subcategory:"System Integrity" /success:enable /failure:enableTrên Domain Controller, hai subcategory Kerberos KHÔNG giống nhau về mặc định — chỗ này rất hay nhầm:
- Audit Kerberos Authentication Service (sinh Event ID 4768 TGT được yêu cầu, 4771 pre-auth thất bại, 4772 yêu cầu TGT thất bại): mặc định trên bản Server đã là Success — không cần bật thêm.
- Audit Kerberos Service Ticket Operations (sinh Event ID 4769 service ticket được yêu cầu, 4770 gia hạn): mặc định là Not configured — KHÔNG ghi gì cả nếu bạn không tự bật.
4769 là sự kiện chính để phát hiện Kerberoasting, nên trên DC nên bật thủ công:
auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable⚠️ Microsoft xếp khối lượng sự kiện của subcategory này là High trên DC đóng vai KDC — cân nhắc nới dung lượng Security log (xem cảnh báo cuối mục này) trước khi bật.
Nếu domain của bạn còn cấu hình audit policy kiểu cũ (9 category "thô", đặt qua GPO Local Policies → Audit Policy) song song với Advanced Audit Policy Configuration ở trên, hai bên có thể giành nhau ghi đè và kết quả không như mong đợi. Bật GPO Security Options → Audit: Force audit policy subcategory settings (Windows Vista or later) to override audit policy category settings (mặc định đã Enabled trên các baseline hiện đại, xem lại Mục 1.5 của Phần 1) để đảm bảo cấu hình subcategory ở trên luôn thắng. Nếu máy đã join domain: auditpol /set chỉ sửa cấu hình cục bộ. Khi domain có GPO cấu hình Advanced Audit Policy, GPO sẽ ghi đè lại toàn bộ ở chu kỳ refresh kế tiếp (mặc định khoảng 90 phút) — chạy xong 20 dòng auditpol ở trên, kiểm ngay thấy đúng, rồi vài tiếng sau giám sát âm thầm tắt mà không ai biết. Với môi trường nhiều máy chủ, đường bền vững là đưa đúng tập subcategory này vào một GPO rồi link vào OU chứa máy chủ; dùng auditpol để kiểm tra và để cấu hình máy đứng một mình. Nếu dùng GPO, nhớ chạy lại "Cách xác nhận" dưới đây sau khi gpupdate /force, không chỉ chạy ngay sau khi auditpol /set.
Bật chừng này subcategory làm khối lượng Security log tăng đáng kể trên máy chủ bận — log mặc định chỉ vài chục MB, ghi đè vòng tròn rất nhanh nếu không nới trước:
# Nâng Security log lên 1 GB (kiểm dung lượng đĩa còn trống trước khi chạy)
wevtutil sl Security /ms:1073741824
wevtutil gl Security | Select-String "maxSize"Cách xác nhận:
auditpol /get /category:* | Out-File "D:\Backup\audit-policy-hien-tai.txt"
auditpol /get /subcategory:"Logon"
auditpol /get /subcategory:"Process Creation"Cột Inclusion Setting phải khớp đúng những gì vừa bật (Success, Success and Failure, hoặc No Auditing).
5.2 Windows Event Forwarding (WEF) — dồn log về một chỗ trước khi kẻ tấn công xoá nó
Việc cần làm: Cấu hình một máy chủ làm Event Collector, các máy chủ còn lại tự đẩy (forward) log liên quan bảo mật về đó, dùng đúng cơ chế WEF có sẵn trong Windows — không cần license thêm.
Vì sao: Theo tài liệu chính thức của Microsoft về WEF, đây là cách "thu thập sự kiện từ các thiết bị trong tổ chức" phục vụ phát hiện xâm nhập. Điểm quan trọng nhất: log để trên chính máy bị tấn công có giá trị bằng chứng giảm mạnh — Event ID 1102 là sự kiện ghi lại việc Security log bị xoá sạch, chính là thứ kẻ tấn công tạo ra ngay trên máy đó khi dọn dấu vết. WEF giải quyết đúng vấn đề này: log đã forward đi rồi thì còn nguyên trên Collector, dù máy nguồn có bị xoá log sau đó.
Cách thực thi — kịch bản đơn giản nhất, phù hợp SME: các máy chủ cùng domain, dùng source-initiated subscription qua HTTP (không cần certificate riêng như kịch bản khác-domain):
(a) Trên máy Collector (máy tập trung nhận log):
winrm qc -q
wecutil qc /qwinrm qc dựng lại listener WinRM trên cổng 5985 (HTTP) và mở luật firewall cho cổng đó — nếu bạn đã làm Mục 3.4 của Phần 1 (xoá listener HTTP, chỉ giữ HTTPS), lệnh này đảo ngược một phần việc đó trên máy Collector. WEF source-initiated cần listener này để nhận log đẩy về nên không bỏ được; nhưng phải giới hạn nguồn ngay, đúng nguyên tắc "mọi cổng quản trị đều giới hạn nguồn" ở Phần 1:
# Chỉ cho dải mạng chứa máy chủ nguồn được gọi vào 5985 của Collector.
# ĐỔI dải IP cho đúng môi trường thật.
Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" -RemoteAddress 192.0.2.0/24
# Nếu profile Public đang active trên Collector, winrm qc còn bật thêm một luật riêng cho
# profile đó - siết luôn, đừng chỉ siết luật chính rồi bỏ sót luật này.
Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP-PUBLIC" -RemoteAddress 192.0.2.0/24 -ErrorAction SilentlyContinue
# Xác nhận lại - phải thấy đúng dải vừa đặt, không phải "Any", ở CẢ hai luật nếu luật Public tồn tại
Get-NetFirewallRule -Name "WINRM-HTTP-In-TCP" | Get-NetFirewallAddressFilter
Get-NetFirewallRule -Name "WINRM-HTTP-In-TCP-PUBLIC" -ErrorAction SilentlyContinue | Get-NetFirewallAddressFilterMáy nguồn không cần mở cổng inbound nào cho WEF — chúng chỉ gọi ra. Chỉ Collector cần 5985 inbound, và chỉ từ dải mạng máy chủ. "HTTP" ở đây không có nghĩa log truyền đi dạng rõ — với máy cùng domain, nội dung vẫn được mã hoá bằng Kerberos ở tầng WinRM. Nhưng máy ngoài domain thì bắt buộc dùng kịch bản HTTPS + certificate, không dùng được cách trong bài này.
Log ForwardedEvents là nơi giữ bằng chứng của cả hạ tầng — mặc định chỉ khoảng 20 MB, cuộn vòng trong vài giờ tới vài ngày nếu gom log từ nhiều máy. Nới dung lượng ngay khi vừa bật xong wecutil qc, tính theo số máy nguồn và số ngày muốn giữ:
# Nâng ForwardedEvents lên 4 GB (kiểm đĩa còn trống trước)
wevtutil sl ForwardedEvents /ms:4294967296
wevtutil gl ForwardedEvents | Select-String "maxSize"(b) Trên từng máy nguồn — cấp quyền đọc Security log để forward được:
Thêm tài khoản NETWORK SERVICE vào nhóm cục bộ Event Log Readers trên từng máy nguồn (không phải Collector) — bắt buộc nếu muốn forward được cả Security log, theo đúng lưu ý chính thức của Microsoft: "To be able to forward the Security log you need to add the NETWORK SERVICE account to the EventLog Readers group."
Add-LocalGroupMember -Group "Event Log Readers" -Member "NT AUTHORITY\NETWORK SERVICE"Lệnh này đúng và bắt buộc — không có cách khác để forward Security log. Nhưng nó không chỉ cấp quyền cho cơ chế WEF: nó cấp quyền đọc toàn bộ Security log cục bộ cho mọi dịch vụ đang chạy dưới tài khoản NETWORK SERVICE trên máy đó — không hiếm khi đó là một số application pool IIS, một số cấu hình SQL Server cũ, hoặc agent bên thứ ba (in ấn, sao lưu, phần mềm nội bộ). Một dịch vụ như vậy bị khai thác thì kẻ tấn công đọc được luôn tài khoản admin nào vừa đăng nhập, từ đâu (4624/4625), và tài khoản nào vừa được thêm vào nhóm quản trị (4720/4732) — một bản đồ trinh sát hoàn chỉnh, lấy chỉ bằng quyền đọc. Liệt kê trước khi chạy:
Get-CimInstance Win32_Service |
Where-Object { $_.StartName -match "NetworkService" } |
Select-Object Name, DisplayName, State, PathNameNếu danh sách có ứng dụng web hoặc dịch vụ bên thứ 3 tiếp xúc dữ liệu từ ngoài vào, cân nhắc chuyển dịch vụ đó sang tài khoản riêng trước. Và giữ Event ID 4732 trong danh sách forward (subscription mẫu ở dưới đã có sẵn) — event này ghi lại "có ai vừa được thêm vào một nhóm bảo mật cục bộ", nên chính thao tác này sẽ để lại dấu nếu sau này có người lặp lại nó với tài khoản khác.
(c) Trên từng máy nguồn — qua GPO (không có cmdlet PowerShell riêng cho setting này, đường chính thức của Microsoft là GPO):
Computer Configuration → Administrative Templates → Windows Components → Event Forwarding → Configure target Subscription Manager → Enabled, thêm chuỗi:
Server=http://TEN-MAY-COLLECTOR.congty.local:5985/wsman/SubscriptionManager/WEC,Refresh=60(đổi TEN-MAY-COLLECTOR.congty.local thành FQDN máy Collector thật; Refresh=60 là chu kỳ máy nguồn kiểm tra lại subscription, tính bằng giây — 60 giây phù hợp môi trường nhỏ, tăng lên nếu có nhiều máy để giảm tải)
gpupdate /force(d) Trên máy Collector — tạo subscription (không có cmdlet PowerShell riêng, dùng wecutil theo đúng công cụ chính thức của Microsoft cho tác vụ này):
Trước tiên, thu hẹp quyền gửi log về đúng nhóm máy chủ — mặc định trong tài liệu Microsoft cấp quyền cho nhóm Domain Computers, tức mọi máy trong domain, kể cả máy trạm, đều gửi được log vào Collector:
# 1. Tạo nhóm riêng chỉ chứa máy chủ được phép gửi log
New-ADGroup -Name "WEF-Nguon" -GroupScope Global -GroupCategory Security
Add-ADGroupMember -Identity "WEF-Nguon" -Members "MAYCHU01$","MAYCHU02$" # nhớ dấu $ cuối tên máy
# 2. Lấy SID của nhóm - dùng trực tiếp trong XML subscription bên dưới
$sidNhom = (Get-ADGroup "WEF-Nguon").SID.Value⚠️ Máy vừa được thêm vào nhóm (bước 1) phải khởi động lại (hoặc đăng xuất/đăng nhập lại phiên máy) thì Kerberos ticket mới nạp đúng nhóm mới — token của máy được cấp lúc khởi động, thêm vào nhóm AD sau đó không tự cập nhật ngay. Thiếu bước này, subscription vẫn từ chối máy nguồn dù đã đứng đúng trong nhóm, và người đọc dễ tưởng cấu hình sai chỗ khác.
@"
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
<SubscriptionId>SecurityBaseline</SubscriptionId>
<SubscriptionType>SourceInitiated</SubscriptionType>
<Description>Forward Security log tu may chu ve Collector</Description>
<Enabled>true</Enabled>
<Uri>http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog</Uri>
<ConfigurationMode>Custom</ConfigurationMode>
<Delivery Mode="Push">
<Batching>
<MaxItems>5</MaxItems>
<MaxLatencyTime>900000</MaxLatencyTime>
</Batching>
<PushSettings>
<Heartbeat Interval="900000"/>
</PushSettings>
</Delivery>
<Query>
<![CDATA[
<QueryList>
<Query Path="Security">
<Select>Event[System[(EventID=4624 or EventID=4625 or EventID=4672 or
EventID=4720 or EventID=4732 or EventID=4740 or EventID=1102)]]</Select>
</Query>
<Query Path="Microsoft-Windows-PowerShell/Operational">
<Select>Event[System[(EventID=4104)]]</Select>
</Query>
</QueryList>
]]>
</Query>
<ReadExistingEvents>false</ReadExistingEvents>
<TransportName>http</TransportName>
<ContentFormat>RenderedText</ContentFormat>
<LogFile>ForwardedEvents</LogFile>
<AllowedSourceDomainComputers>O:NSG:NSD:(A;;GA;;;$sidNhom)(A;;GA;;;NS)</AllowedSourceDomainComputers>
</Subscription>
"@ | Out-File "C:\WEF\subscription-security.xml" -Encoding UTF8
wecutil cs "C:\WEF\subscription-security.xml"ConfigurationMode phải là Custom, không phải Normal — theo tài liệu wecutil.exe, khối <Delivery> (MaxItems/MaxLatencyTime/Heartbeat tự đặt) chỉ hợp lệ khi ConfigurationMode là Custom; các giá trị đang dùng ở trên (gom 5 sự kiện, tối đa 15 phút) tái tạo đúng hành vi mặc định của Normal, chỉ là khai tường minh thay vì dùng mode dựng sẵn. AllowedSourceDomainComputers giờ chỉ cấp quyền cho nhóm WEF-Nguon vừa tạo — không còn mọi máy trong domain đều gửi log vào Collector được nữa.
Ví dụ trên chỉ forward vài Event ID mẫu (đăng nhập, tạo/khoá tài khoản, xoá log, script block PowerShell) để giữ khối lượng thấp cho môi trường nhỏ — trong đó 4740 (tài khoản bị khoá) và 4104 (script block PowerShell) đã nhắc ở Phần 1, còn 4624/4625/4672/4720/4732/1102 là giới thiệu lần đầu ở bài này. Mở rộng danh sách EventID=... trong <Query> theo đúng những gì Mục 5.1 vừa bật, hoặc dùng nguyên bộ Event ID Microsoft khuyến nghị cho "Baseline subscription" trong tài liệu WEF chính thức nếu cần bộ đầy đủ hơn.
WEF chỉ chuyển tiếp event ĐÃ có sẵn trong log nguồn — nó không tự bật audit policy, không tự mở log channel đang tắt, không tự nới dung lượng log. Nguyên văn Microsoft: "WEF is a passive system regarding the event log. It can't change the size of event log files, enable disabled event channels, change channel permissions, or adjust a security audit policy." Nếu Mục 5.1 chưa bật đúng subcategory, hoặc log PowerShell Operational vẫn ở mức 15 MB mặc định như cảnh báo ở Mục 3.1 Phần 1, WEF sẽ không có gì để forward — làm đúng thứ tự: 5.1 trước, 5.2 sau.
Cách xác nhận:
# Trên máy nguồn: xác nhận đã kết nối được tới Collector
Get-WinEvent -FilterHashtable @{ LogName="Microsoft-Windows-Eventlog-ForwardingPlugin/Operational"; Id=100 } `
-MaxEvents 5 -ErrorAction SilentlyContinue # "The subscription ... is created successfully"
# Trên máy Collector: xem trạng thái runtime của subscription
wecutil gr SecurityBaseline
# Trên máy Collector: xác nhận event đã thực sự chạy về
Get-WinEvent -LogName "ForwardedEvents" -MaxEvents 10wecutil gr phải hiện đúng số máy nguồn đang Active — nếu là 0, chờ hết chu kỳ Refresh đã khai ở GPO rồi kiểm lại, hoặc kiểm gpupdate /force đã chạy trên máy nguồn chưa. Với MaxItems=5/MaxLatencyTime=900000, phải có đủ 5 sự kiện khớp query, hoặc chờ hết 15 phút, mới thấy gì trong ForwardedEvents — đừng kết luận "hỏng" chỉ vì chưa đủ thời gian.
5.3 Sysmon — thấy được thứ Advanced Audit Policy không thấy
Việc cần làm: Cài Sysmon và áp một file cấu hình đã được cộng đồng bảo mật tinh chỉnh, thay vì cấu hình mặc định (gần như không ghi gì) hoặc tự viết từ đầu.
Vì sao: Theo tài liệu chính thức của Microsoft, Sysmon ghi lại chi tiết mà audit log chuẩn không có: command line đầy đủ của process vừa tạo (không chỉ tên file .exe), hash của file thực thi, network connection theo từng process, driver/DLL nạp vào kèm chữ ký số, named pipe, sự kiện WMI event subscription (kỹ thuật ẩn mình phổ biến). Nguyên văn Microsoft: "These capabilities give security teams better context than default audit logs alone and improve detection of suspicious behaviors such as living-off-the-land execution, lateral movement, and malicious activity."
Về file cấu hình: Cài mặc định không sai, nhưng gần như không dùng được — cấu hình mặc định (sysmon -i không kèm file) ghi hầu hết loại sự kiện nhưng không lọc gì cả, sinh lượng log khổng lồ mà tín hiệu thì loãng. Đồng thời nó tắt sẵn đúng hai thứ đáng giá nhất: Event ID 3 (network connection) và Event ID 7 (image loaded) — nguyên văn Sysinternals: "Install with default settings (process images hashed with SHA1 and no network monitoring)". Vì vậy Sysmon chỉ có giá trị thật khi đi kèm một file cấu hình đã tinh chỉnh. Trang hướng dẫn chính thức của Microsoft Learn về Sysmon liệt kê đích danh hai kho cấu hình cộng đồng phổ biến nhất để dùng ngay, nhưng ghi rõ đây là tài nguyên do cá nhân/cộng đồng duy trì, không phải sản phẩm chính thức của Microsoft:
- SwiftOnSecurity/sysmon-config — cấu hình đơn giản, một file XML, đã loại trừ sẵn nhiều noise phổ biến, phù hợp làm điểm khởi đầu.
- olafhartong/sysmon-modular (Olaf Hartong) — chi tiết và đồ sộ hơn, các module ánh xạ theo khung MITRE ATT&CK, phù hợp khi đã quen Sysmon và cần độ phủ sâu hơn.
Với môi trường mới bắt đầu, dùng SwiftOnSecurity trước — ít noise hơn, dễ đọc log hơn khi mới triển khai.
Cách thực thi — cách cài phụ thuộc phiên bản Windows Server:
| Phiên bản | Cách cài | Ghi chú |
|---|---|---|
| Windows Server 2025 | Built-in Sysmon (tính năng optional có sẵn trong Windows) | Tự cập nhật qua Windows Update, không cần tải/quản lý file .exe riêng |
| Windows Server 2019 / 2022 | Sysinternals Sysmon standalone (tải riêng) | Built-in Sysmon chưa hỗ trợ hai bản này — theo trang tải chính thức, Sysmon standalone hỗ trợ "Server: Windows Server 2019 and higher" |
Windows Server 2025 — built-in Sysmon:
# 1. Bật tính năng Sysmon có sẵn trong hệ điều hành
Enable-WindowsOptionalFeature -Online -FeatureName Sysmon
# 2. Tải file cấu hình cộng đồng về trước (ví dụ SwiftOnSecurity), lưu vào C:\Sysmon\sysmonconfig.xml
# 3. Cài và áp cấu hình cùng lúc
sysmon -i C:\Sysmon\sysmonconfig.xmlWindows Server 2019/2022 — Sysinternals Sysmon standalone:
# 1. Tải Sysmon.zip từ Sysinternals (download.sysinternals.com/files/Sysmon.zip), giải nén
# 2. Cài với file cấu hình cộng đồng, chấp nhận EULA không hỏi lại
& "C:\Sysmon\Sysmon64.exe" -accepteula -i C:\Sysmon\sysmonconfig.xmlCập nhật cấu hình sau này (cả hai nhánh, không cần khởi động lại — có hiệu lực ngay):
sysmon -c C:\Sysmon\sysmonconfig-moi.xmlBuilt-in Sysmon và Sysinternals Sysmon standalone KHÔNG chạy song song được trên cùng một máy — nguyên văn Microsoft: "Coexistence between built-in Sysmon and standalone Sysmon isn't supported." Nếu định nâng cấp một máy từ WS2019/2022 lên WS2025 và muốn chuyển sang built-in, gỡ bản standalone trước (Sysmon64.exe -u) rồi mới bật tính năng built-in.
Đừng tự bật hết mọi loại event Sysmon "cho chắc" — riêng Event ID 7 (Image loaded) Microsoft cảnh báo thẳng: "This event should be configured carefully, as monitoring all image load events will generate a significant amount of logging." Đây chính xác là lý do nên dùng file cấu hình cộng đồng đã tinh chỉnh (loại trừ sẵn các DLL hệ thống nạp liên tục) thay vì tự viết XML từ con số 0.
Cách xác nhận:
Get-Service -Name Sysmon* | Select-Object Name, Status, StartType
Get-WinEvent -FilterHashtable @{ LogName="Microsoft-Windows-Sysmon/Operational"; Id=1 } `
-MaxEvents 5 -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Message # Process Create (Event ID 1)Event ID 1 xuất hiện đều đặn nghĩa là Sysmon đang ghi log thật, không chỉ cài dịch vụ mà không sinh sự kiện. Muốn forward log Sysmon về Collector đã dựng ở Mục 5.2, thêm một <Query Path="Microsoft-Windows-Sysmon/Operational"> vào file subscription XML.
5.4 Log tập trung — Collector chính là "kho báu" cần bảo vệ riêng
Ba mục trên (Advanced Audit Policy sinh log đúng → WEF gom log về một chỗ → Sysmon làm log chi tiết hơn) đã tạo ra một hình thức "log tập trung" cơ bản, không cần license SIEM thêm. Nếu công ty có SIEM thương mại (Sentinel, Splunk, Elastic...), bước tiếp theo là cài agent SIEM trên chính máy Collector để đẩy tiếp ForwardedEvents sang đó — phần này phụ thuộc sản phẩm SIEM cụ thể, ngoài phạm vi bài viết chung cho Windows Server.
Máy Collector giờ giữ log của toàn bộ máy chủ khác — nếu nó bị chiếm, kẻ tấn công vừa có bức tranh toàn cảnh hạ tầng, vừa có thể xoá sạch bằng chứng ở một nơi duy nhất thay vì phải xoá từng máy. Áp dụng đúng tinh thần "log là kho bí mật" đã nói ở Mục 3.1 Phần 1: giới hạn quyền NTFS/đăng nhập vào máy Collector chỉ cho đúng người cần, và cân nhắc đặt nó vào lớp quản trị cao hơn (Tier 0/1) theo Enterprise Access Model đã nói ở Mục 2.1 Phần 1 — không dùng chung với máy chủ ứng dụng thông thường.
6. Nâng cao
6.1 Credential Guard / Device Guard — đã viết kỹ ở bài mã hoá, chỉ nhắc lại
Credential Guard (cách ly NTLM hash/vé Kerberos khỏi vùng nhớ thông thường, chặn kỹ thuật Pass-the-Hash/Pass-the-Ticket) và nền tảng Virtualization-based Security/Secure Boot/TPM đã được viết đầy đủ — cách bật qua GPO, qua registry, hai chế độ Enabled without lock / Enabled with UEFI lock và đánh đổi giữa chúng, cách xác nhận bằng Get-CimInstance -ClassName Win32_DeviceGuard — ở bài Mã hoá dữ liệu trên Windows Server 2022, Bước 4. Hai điểm quan trọng nhất cần nhớ khi đọc lại: bật Credential Guard trước khi máy join domain hoặc trước lần đăng nhập domain user đầu tiên (bật sau không bảo vệ được credential đã có nguy cơ lộ từ trước), và không bật trên Domain Controller (Microsoft không hỗ trợ). Lưu ý phiên bản: từ Windows Server 2025, Credential Guard đã bật mặc định trên máy đã join domain (không phải DC) đạt yêu cầu phần cứng — kiểm bằng Get-CimInstance -ClassName Win32_DeviceGuard trước khi định bật thủ công, và nhớ điều này khi đọc Mục 6.3 dưới đây (rule ASR liên quan LSASS có thể đã dư thừa sẵn trên máy WS2025). Attack Surface Reduction ở Mục 6.3 dưới đây có một rule liên quan trực tiếp tới Credential Guard — đọc chéo khi tới đó.
6.2 Windows Defender Application Control (WDAC) hay AppLocker — dùng cái nào
Việc cần làm: Chỉ cho phép đúng phần mềm đã được duyệt chạy trên máy chủ, chặn phần còn lại — bằng WDAC hoặc AppLocker tuỳ tình huống.
Vì sao: Malware muốn chạy được trước hết phải thực thi được — application control chặn đúng bước đó, độc lập với việc antivirus có nhận diện được mã độc cụ thể hay không.
So sánh khi nào dùng cái nào — theo đúng khuyến nghị chính thức của Microsoft:
| WDAC (App Control) | AppLocker | |
|---|---|---|
| Tầng chặn | Kernel — chặn cả driver, toàn hệ thống | User-mode — chặn tiến trình người dùng |
| Rule theo từng user/nhóm | Không — áp cho cả máy | Có — khác nhau theo user/nhóm trên cùng máy |
| Yêu cầu OS | Windows Server 2016 trở lên | Windows Server (rộng hơn, kể cả bản cũ) |
| Được Microsoft tiếp tục phát triển tính năng mới | Có | Chỉ vá lỗi bảo mật, không thêm tính năng mới |
Nguyên văn khuyến nghị: "Generally, customers who are able to implement application control using App Control, rather than AppLocker, should do so." Nhưng AppLocker vẫn là lựa chọn đúng khi: môi trường có máy Windows cũ cần áp cùng chính sách, hoặc cần rule khác nhau cho từng user/nhóm trên một máy chủ dùng chung (ví dụ máy Terminal Server nhiều người dùng RDP vào, mỗi nhóm phòng ban chỉ được chạy đúng phần mềm của phòng đó) — đây cũng là tình huống phổ biến hơn với máy chủ SME quy mô vừa, nên phần thực thi dưới đây tập trung vào AppLocker.
⚠️ Nói cho đủ: Microsoft phân loại App Control (WDAC) là tính năng bảo mật theo tiêu chí servicing của MSRC, còn AppLocker thì không — nguyên văn: "AppLocker … doesn't meet the servicing criteria for being a security feature." Nghĩa là một kỹ thuật vượt qua AppLocker sẽ không được Microsoft vá như một lỗ hổng bảo mật. AppLocker vẫn rất đáng dùng (nó chặn đứng phần lớn malware hàng loạt và mọi phần mềm ngoài luồng), nhưng hãy coi nó là lớp giảm rủi ro, không phải bức tường chống kẻ tấn công có chủ đích. Cần mức đó thì phải là WDAC.
Cách thực thi — AppLocker, quy trình Audit trước - Enforce sau:
1. Bật dịch vụ Application Identity — AppLocker chỉ hoạt động khi dịch vụ này chạy, theo đúng tài liệu chính thức: "Stopping this service prevents AppLocker policies from being enforced."
sc.exe config appidsvc start=auto
Start-Service -Name AppIDSvc
Get-Service AppIDSvc | Select-Object Name, Status, StartType # phải là Running / Automatic⚠️ Từ Windows 10/Windows Server 2016 trở đi, AppIDSvc là protected process: services.msc và Set-Service đều không đổi được Startup type (báo Access is denied) — phải dùng sc.exe như trên. Áp cho nhiều máy thì làm qua GPO: Computer Configuration\Windows Settings\Security Settings\System Services → Application Identity → Automatic. 🔴 Đây là thao tác khó lùi: nguyên văn Microsoft — "The Startup type of the Application Identity service cannot be set to Manual using sc.exe. Therefore, we recommend to perform a system backup before changing it."
2. Sinh rule tự động từ một máy tham chiếu (máy đã cài đủ phần mềm hợp lệ, sạch mã độc) — publisher rule ưu tiên trước (bám theo chữ ký số, không đổi khi phần mềm cập nhật phiên bản), hash rule dùng khi file không có chữ ký. Chỉ quét .exe ở lần đầu — bộ DLL là mức khó nhất của AppLocker (mọi module nạp vào mọi tiến trình đều bị kiểm), để lại tính sau khi EXE đã ổn định:
Get-ChildItem -Path "C:\Program Files","C:\Program Files (x86)" -Recurse `
-Include *.exe -ErrorAction SilentlyContinue |
Get-AppLockerFileInformation |
New-AppLockerPolicy -RuleType Publisher,Hash -User Everyone -Xml |
Out-File "C:\AppLocker\policy-audit.xml" -Encoding UTF8New-AppLockerPolicy sinh ra policy với EnforcementMode="NotConfigured" theo mặc định — và NotConfigured KHÔNG có nghĩa là "chưa bật"/"an toàn để thử". Theo đúng tài liệu chính thức của Microsoft về cách GPO merge AppLocker: "Any rule collection with the enforcement mode set as 'not configured' is enforced." Nghĩa là nếu bạn import thẳng file vừa sinh ra ở bước 2 mà không sửa gì, và không có GPO nào khác ghi đè xuống Audit only, policy đó CHẶN NGAY LẬP TỨC — đúng kiểu rủi ro giống JEA ở Mục 2.6 Phần 1 (một cấu hình tưởng là "trung tính" hoá ra lại là cấp quyền/chặn thật). Luôn mở file XML, tự tay sửa từng dòng EnforcementMode="NotConfigured" thành EnforcementMode="AuditOnly" trước khi import lần đầu:
$noiDungXml = Get-Content "C:\AppLocker\policy-audit.xml" -Raw
$noiDungXml = $noiDungXml -replace 'EnforcementMode="NotConfigured"', 'EnforcementMode="AuditOnly"'
Set-Content -Path "C:\AppLocker\policy-audit.xml" -Value $noiDungXmlÁp ngay policy vừa sửa làm nền, trước khi làm bất cứ gì khác — đây là điểm dễ làm sai nhất của cả mục: nếu bạn sinh thêm rule cho C:\Windows ở bước 2b/2c trước khi áp bước này, hoặc áp bước này sau bằng lệnh không kèm -Merge (Set-AppLockerPolicy không có -Merge sẽ GHI ĐÈ toàn bộ policy cục bộ, xoá sạch rule vừa gộp), bạn sẽ quay lại đúng tình trạng ban đầu — thiếu rule cho C:\Windows — mà tưởng mình đã sửa xong:
Set-AppLockerPolicy -XmlPolicy "C:\AppLocker\policy-audit.xml"(Muốn áp cho domain qua GPO thay vì máy cục bộ, dùng Set-AppLockerPolicy -Ldap "..." — nhớ đã Backup-GPO ở Bước 0, vì đường lùi cục bộ ở dưới không có tác dụng khi policy đến từ GPO, máy nhận lại đúng policy cũ ở lần đồng bộ sau.) Nguy hiểm hơn nữa: policy trên chỉ chứa rule cho C:\Program Files, KHÔNG có rule nào cho C:\Windows. Enforce một policy như vậy sẽ chặn luôn powershell.exe, cmd.exe, regedit.exe, mmc.exe, explorer.exe — tức chặn chính công cụ bạn cần để sửa lỗi. Không bao giờ chuyển Enabled khi policy chưa có rule cho C:\Windows và chưa có rule thoát hiểm cho Administrators. Đã tự kiểm chứng trên Windows Server 2022 thật (chính sách cục bộ, không qua GPO domain), KHÔNG có trong tài liệu Microsoft — rủi ro riêng của cách "quét hết rồi sinh rule cho từng file": quét đệ quy toàn bộ C:\Windows\System32 + SysWOW64 để sinh rule riêng cho từng file (~1000 rule Exe trở lên) làm chính sách cục bộ NGỪNG khớp đúng — Get-AppLockerPolicy -Local vẫn báo đủ số rule, nhưng Test-AppLockerPolicy (và nhiều khả năng cả AppIDSvc khi Enforce thật) trả về DeniedByDefault cho chính những file có rule hợp lệ, kể cả cmd.exe. Đã kiểm tra: ~570 rule vẫn khớp đúng, ~1000 rule thì hỏng — ngưỡng chính xác chưa rõ. Cảnh báo duy nhất bạn có là bước 4 dưới đây (Test-AppLockerPolicy) — đó chính là cách phát hiện ra vấn đề này, và là lý do đừng bao giờ bỏ qua bước đó dù tin chắc policy đã đúng. Vì lý do này, bài không dùng cách quét từng file cho C:\Windows — dùng cách dưới đây, vừa an toàn hơn vừa đúng tinh thần khuyến nghị chính thức của Microsoft. Cách an toàn hơn: MỘT rule Publisher phạm vi rộng, thay vì hàng nghìn rule từng file. Nguyên văn Microsoft về ưu điểm của publisher rule: "A single rule can be used to allow an entire product suite." Bỏ trống tên file và phiên bản (dùng *) trong điều kiện Publisher sẽ áp dụng rule đó cho mọi file thuộc đúng sản phẩm đó — theo đúng bảng chính thức: "Publisher and product name: All files for the specified product signed by the named publisher." Một rule như vậy phủ được gần như toàn bộ file lõi của Windows (đã tự kiểm chứng: cmd.exe, cả hai powershell.exe, explorer.exe, regedit.exe, mmc.exe, taskmgr.exe, notepad.exe, svchost.exe, winlogon.exe... đều khớp) — vì chúng dùng chung một chứng chỉ ký số của sản phẩm "Microsoft® Windows® Operating System". Đánh đổi cần biết — nguyên văn Microsoft: "Although a single rule can be used to allow an entire product suite, all files in the suite must be signed uniformly." Tức rule này chỉ phủ đúng một sản phẩm; sản phẩm Microsoft khác đóng gói riêng (xem cảnh báo OpenSSH bên dưới) vẫn nằm ngoài phạm vi:
# 2b. Sinh MOT rule tham chieu tu cmd.exe, roi mo rong pham vi bang wildcard "*" -
# thay vi liet ke hang nghin file rieng le (xem canh bao ve nguong so luong o tren).
$thamChieu = Get-AppLockerFileInformation -Path "C:\Windows\System32\cmd.exe"
$polTho = New-AppLockerPolicy -FileInformation $thamChieu -RuleType Publisher -User Everyone -Xml
[xml]$xmlWindows = $polTho
$dieuKien = $xmlWindows.SelectSingleNode("//FilePublisherCondition")
$dieuKien.BinaryName = "*" # tu 1 file cu the -> moi file cua san pham nay
$dieuKien.BinaryVersionRange.LowSection = "*" # tu 1 phien ban cu the -> moi phien ban
$dieuKien.BinaryVersionRange.HighSection = "*"
$xmlWindows.AppLockerPolicy.RuleCollection.EnforcementMode = "AuditOnly"
$xmlWindows.OuterXml | Out-File "C:\AppLocker\policy-windows.xml" -Encoding UTF8⚠️ PublisherName vẫn giữ nguyên, KHÔNG wildcard — rule chỉ mở rộng theo tên file/phiên bản, không mở rộng theo hãng phát hành, nên vẫn xác thực đúng chữ ký số, không cấp quyền cho phần mềm giả mạo publisher. Và rule này chỉ phủ đúng sản phẩm "Microsoft® Windows® Operating System" — các sản phẩm Microsoft khác đóng gói riêng (OpenSSH for Windows là một ví dụ đã tự kiểm chứng KHÔNG nằm trong phạm vi này dù cùng là Microsoft) vẫn cần rule riêng nếu máy chủ của bạn dùng tới; kiểm bằng Get-AppLockerFileInformation -Path <file> rồi xem trường Publisher trước khi giả định đã được phủ. Set-AppLockerPolicy -Merge chọn chế độ CHẶT HƠN giữa policy cục bộ và policy đang gộp vào — và NotConfigured được tính là chặt hơn AuditOnly. Nguyên văn Microsoft: "If you apply an AppLocker policy locally using the Set-AppLockerPolicy PowerShell cmdlet with the -merge option, the more restrictive enforcement mode is chosen between the existing local policy and the policy being merged." Đây chính xác là lý do bước 2b ở trên đã tự đặt EnforcementMode="AuditOnly" ngay khi sinh file — nếu để nguyên NotConfigured (giá trị mặc định của New-AppLockerPolicy) rồi mới merge, bộ Exe sẽ lật sang đang enforce ngay lập tức, bỏ qua toàn bộ giai đoạn Audit. Xác nhận lại trước khi merge nếu muốn chắc chắn:
(Get-Content "C:\AppLocker\policy-windows.xml" -Raw) -match 'EnforcementMode="(\w+)"' | Out-Null
"Enforcement mode cua policy-windows.xml: $($Matches[1])" # phải là AuditOnly, không phải NotConfigured
# 2c. Gộp THÊM vào policy ĐÃ ÁP ở bước trên - dùng đúng -Merge, không dùng lại lệnh không
# -Merge ở trên lần thứ hai (sẽ ghi đè, xoá mất rule Program Files vừa áp).
Set-AppLockerPolicy -XmlPolicy "C:\AppLocker\policy-windows.xml" -MergeVà giữ một rule cho phép nhóm BUILTIN\Administrators chạy mọi thứ trong suốt giai đoạn triển khai (đúng là default rule thứ 3 của AppLocker khi tạo qua GUI — tạo qua secpol.msc → phải chuột AppLocker → Create Default Rules, hoặc gộp default rules bằng Get-AppLockerPolicy -Local | Set-AppLockerPolicy -Merge sau khi tạo qua GUI trên một máy tham chiếu). Nói thẳng đánh đổi: rule này làm AppLocker không bảo vệ được tài khoản admin — nó là dây bảo hiểm lúc dựng, gỡ sau khi đã chạy ổn định, không phải cấu hình cuối. Một ngoại lệ riêng của rule collection "packaged apps" (Appx) đáng biết: khác với Exe/Script/Msi (rỗng thì cho chạy hết), theo nguyên văn Microsoft — "If any rules are enforced for the EXE rule collection, you must create rules in the packaged apps and packaged app installers rule collection. Otherwise, all packaged apps and packaged app installers are blocked." Nghĩa là ngay khi bộ Exe có rule đang enforce (đúng tình huống của mục này), bộ Appx trống sẽ tự động chặn hết ứng dụng đóng gói kiểu Microsoft Store — trên máy chủ ít gặp nhưng vẫn có thể có (ví dụ một vài công cụ quản trị đóng gói MSIX). Nếu máy chủ có dùng loại app này, tạo thêm rule cho bộ Appx trước khi Enforce.
3. Chạy Audit mode tối thiểu 1-2 tuần, theo dõi Event ID 8003 (sẽ bị chặn nếu Enforce) trong log Microsoft-Windows-AppLocker/EXE and DLL — bất kỳ phần mềm nghiệp vụ hợp lệ nào xuất hiện ở đây cần được thêm rule (publisher/hash, không dùng path rule rộng) trước khi chuyển Enforce:
Get-WinEvent -FilterHashtable @{ LogName="Microsoft-Windows-AppLocker/EXE and DLL"; Id=8003 } `
-MaxEvents 200 -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Message4. Kiểm bằng Test-AppLockerPolicy trước khi Enforce — đối chiếu đúng những file sống còn, đừng chỉ tin bằng mắt. Kiểm đúng policy ĐANG ÁP DỤNG THẬT (Get-AppLockerPolicy -Local), không kiểm lại file policy-audit.xml trên đĩa — file đó chỉ có rule Program Files, không chứa rule C:\Windows vừa gộp ở bước 2c, nên kiểm nhầm file sẽ luôn báo Denied dù policy thật đã đúng:
Get-AppLockerPolicy -Local |
Test-AppLockerPolicy -Path "C:\Windows\System32\cmd.exe",
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe",
"C:\Windows\regedit.exe",
"C:\Windows\explorer.exe" `
-User Everyone |
Format-Table FilePath, PolicyDecision, MatchingRuleCột PolicyDecision của cả bốn file phải là Allowed. Còn một dòng Denied/DeniedByDefault thì không được chuyển Enforce — quay lại bước 2b.
5. Chuyển Enforce — sau khi Audit sạch (không còn phần mềm hợp lệ bị đánh dấu) và Test-AppLockerPolicy toàn Allowed. Không sửa lại policy-audit.xml — file đó chỉ có rule Program Files, Set-AppLockerPolicy lên nó (không -Merge) sẽ ghi đè, xoá mất rule C:\Windows đã gộp ở 2c, đúng thảm hoạ N1 nhưng ở chế độ Enforce. Xuất chính policy đang áp dụng thật (đã có đủ cả hai bộ rule) ra file rồi mới đổi chế độ trên file đó:
Get-AppLockerPolicy -Local -Xml | Out-File "C:\AppLocker\policy-hienhanh.xml" -Encoding UTF8
(Get-Content "C:\AppLocker\policy-hienhanh.xml" -Raw) -replace 'EnforcementMode="AuditOnly"', 'EnforcementMode="Enabled"' |
Set-Content "C:\AppLocker\policy-hienhanh.xml"
Set-AppLockerPolicy -XmlPolicy "C:\AppLocker\policy-hienhanh.xml"Qua GUI thì an toàn hơn cách sửa XML ở trên (chỉ đổi chế độ, không đụng rule nào) — ưu tiên đường này nếu tiện: secpol.msc → phải chuột AppLocker → Properties → tab Enforcement → tick Configured → chọn Enforce rules.
Default rule của AppLocker (khi tạo qua GUI) cho phép mọi người chạy file trong toàn bộ thư mục C:\Windows — nhưng thư mục này có C:\Windows\Temp, nơi nhóm Users có quyền ghi. Nguyên văn cảnh báo chính thức của Microsoft: "because any user can create files in this location, allowing applications to be run from this location might conflict with your organization's security policy." Path rule kiểu này chỉ nên dùng làm starter policy khi mới test, không nên giữ nguyên khi đã Enforce production — ưu tiên publisher/hash rule như bước 2/2b ở trên thay vì path rule rộng. Lưu ý: quy trình bước 2/2b ở trên tự sinh rule bằng PowerShell, không dùng default rule của AppLocker Group Policy editor — nếu policy của bạn dựng theo cách này, đừng cho rằng C:\Windows đã được cho phép sẵn.
Cách xác nhận:
Get-AppLockerPolicy -Effective -Xml | Select-String "EnforcementMode"
Get-Service -Name AppIDSvc | Select-Object Name, Status, StartTypeSau khi Enforce, thử chạy một file KHÔNG nằm trong rule đã duyệt (ví dụ copy cmd.exe sang tên khác vào C:\Temp) — phải bị chặn kèm Event ID 8004.
Đường lùi nếu Enforce chặn nhầm phần mềm hợp lệ và cần gỡ khẩn cấp:
# Cach 1 - lùi về Audit-only (giữ lại rule đã sinh, chỉ ngừng chặn thật).
# Xuất từ chính policy ĐANG ÁP (đủ cả rule Program Files lẫn C:\Windows), KHÔNG sửa lại
# policy-audit.xml gốc - file đó chỉ có rule Program Files, ghi đè bằng nó sẽ xoá mất rule
# C:\Windows đã gộp, coi như tự khoá lại đúng lỗ hổng vừa vá.
Get-AppLockerPolicy -Local -Xml | Out-File "C:\AppLocker\policy-hienhanh.xml" -Encoding UTF8
(Get-Content "C:\AppLocker\policy-hienhanh.xml" -Raw) -replace 'EnforcementMode="Enabled"', 'EnforcementMode="AuditOnly"' |
Set-Content "C:\AppLocker\policy-hienhanh.xml"
Set-AppLockerPolicy -XmlPolicy "C:\AppLocker\policy-hienhanh.xml"
# Cách 2 (thay thế) - gỡ sạch rule AppLocker cục bộ: không còn RuleCollection nào nghĩa là
# không còn gì để enforce. KHÔNG thêm thuộc tính EnforcementMode vào đây dù ở dạng rỗng -
# chính bài này vừa cảnh báo NotConfigured = đang enforce, nên một RuleCollection rỗng mang
# thuộc tính đó có thể chặn HẾT thay vì mở HẾT. Giữ đúng dạng tối giản, không đoán thêm cấu trúc.
'<AppLockerPolicy Version="1" />' | Out-File "C:\AppLocker\policy-rong.xml" -Encoding UTF8
Set-AppLockerPolicy -XmlPolicy "C:\AppLocker\policy-rong.xml"
gpupdate /force(Cách 1 giữ nguyên toàn bộ rule đã dày công sinh ra, chỉ đổi về quan sát — ưu tiên dùng trước. Cách 2 áp một policy rỗng, không đụng tới dịch vụ Application Identity — dịch vụ này là protected process (xem bước 1) nên Stop-Service/Set-Service lên nó thường thất bại đúng lúc cần nhất; dùng Cách 2 khi Cách 1 không kịp thực hiện vì hệ thống đang gián đoạn nặng.)
Cách 3 — khi đã không gõ được lệnh nào nữa: nếu policy đến từ GPO, sửa cục bộ vô nghĩa (lần đồng bộ sau máy nhận lại đúng policy cũ) — phải gỡ link GPO khỏi OU từ một máy khác, hoặc Restore-GPO từ bản backup đã làm ở Bước 0. Nếu policy là cục bộ và không còn chạy được PowerShell, đường còn lại là console/iDRAC/iLO khởi động vào Safe Mode. ⚠️ Có tài liệu Microsoft (bản cũ, cho Windows 7/Server 2008 R2-2012 R2) mô tả Safe Mode là đường khôi phục khi bị AppLocker chặn hết tác vụ quản trị — khởi động Safe Mode, thêm lại default rule, xoá deny rule đang chặn, khởi động lại bình thường — và có ghi rằng "in Windows 7, administrators have the option of restricting standard users from bypassing AppLocker policies when logging into their local computers in safe mode", tức mặc định người dùng CÓ thể bỏ qua AppLocker trong Safe Mode trừ khi admin tự khoá thêm. Nhưng đây là tài liệu đã lưu trữ (archived), viết cho các bản Windows cũ — tôi chưa tìm được trang Microsoft Learn hiện hành nào khẳng định trực tiếp hành vi này còn đúng nguyên vẹn trên Windows Server 2019/2022/2025. Vì vậy: ưu tiên Cách 1 / Cách 2 / gỡ GPO trước, chỉ tính tới Safe Mode khi các đường trên đều không gõ được lệnh, và đừng coi Safe Mode là một đường lùi chắc chắn hoạt động.
WDAC — khi cần dùng: quy trình tương tự về mặt tư duy nhưng thao tác qua bộ cmdlet riêng New-CIPolicy (sinh policy từ máy tham chiếu, tương tự New-AppLockerPolicy) → Set-RuleOption (mặc định policy mới sinh ra ở Audit Mode — gỡ Option 3 bằng Set-RuleOption -FilePath <đường dẫn> -Option 3 -Delete để chuyển Enforce) → ConvertFrom-CIPolicy (đóng gói XML thành file nhị phân .cip để triển khai). Lưu ý chiều của bẫy ở hai công cụ là NGƯỢC NHAU: WDAC sinh policy ở Audit Mode (an toàn mặc định, phải chủ động gỡ Option 3 mới thành Enforce), còn AppLocker sinh policy ở NotConfigured, mà NotConfigured là đang enforce (xem lại khối cảnh báo đỏ ở bước 2). Đừng mang thói quen từ công cụ này sang công cụ kia. Quy trình đầy đủ của WDAC (bao gồm cách ký số policy, triển khai qua GPO/Intune, gộp nhiều policy) phức tạp hơn nhiều so với AppLocker và nằm ngoài phạm vi bài này; xem App Control for Business Design Guide của Microsoft nếu môi trường của bạn đủ lớn để cần WDAC thay vì AppLocker.
6.3 Attack Surface Reduction (ASR) rules — nhóm rule Microsoft nói thường bật Block được ngay, kèm một ngoại lệ
Việc cần làm: Bật đúng nhóm ASR rule Microsoft gọi là "Standard protection rules" — nhóm rule Microsoft nói thường có thể bật Block mà không cần test dài, kèm một ngoại lệ cần lưu ý.
Vì sao: ASR có gần 20 rule, mỗi rule chặn một kỹ thuật tấn công cụ thể (Office spawn child process, script bị obfuscate, PSExec/WMI...), nhưng không phải rule nào cũng an toàn để bật đại trà. Nguyên văn khuyến nghị triển khai chính thức của Microsoft: "Typically, you can enable the standard protection rules in Block or Warn mode without testing. You should test other ASR rules in Audit mode before you switch them to Block or Warn mode." — chữ "typically" ở đây quan trọng: trang tổng quan ASR còn nói thẳng "Typically, these rules have minimal or no noticeable effect on users, but there are exceptions", và một trong ba rule dưới đây chính là ngoại lệ đó. Ba rule dưới là toàn bộ nhóm "Standard protection rules":
| Rule | GUID | Tác dụng | Phiên bản Server hỗ trợ |
|---|---|---|---|
| Block abuse of exploited vulnerable signed drivers | 56a863a9-875e-4185-98a7-b882c64b5ce5 | Chặn app lưu driver đã ký nhưng có lỗ hổng đã biết vào máy — kỹ thuật "BYOVD" (bring your own vulnerable driver) dùng để tắt phần mềm bảo mật | WS2012 R2 trở lên (WS2016 cần bản 1803/SAC trở lên) |
| Block credential stealing from the Windows local security authority subsystem | 9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2 | Chặn đọc bộ nhớ LSASS — nơi mã độc kiểu Mimikatz đọc trộm mật khẩu/hash. Rule này không chặn tiến trình chạy, chỉ chặn việc đọc vùng nhớ đó | WS2012 R2 trở lên |
| Block persistence through WMI event subscription | e6db77e5-3df2-4cf1-b95a-636979351e5b | Chặn kỹ thuật ẩn mình dùng WMI event subscription để tự khởi động lại sau khi máy reboot | Windows Server 1903 (SAC) trở lên — KHÔNG hỗ trợ WS2016/2012 R2, và nằm ngoài phạm vi hỗ trợ của WS2019 LTSC (bản 1809, thấp hơn ngưỡng 1903 Microsoft yêu cầu) |
⚠️ Ngoại lệ của bảng trên: nếu hạ tầng đang dùng Microsoft Configuration Manager (SCCM), rule "Block persistence through WMI event subscription" phải chạy Audit mode và test kỹ trước — client SCCM phụ thuộc nặng vào WMI, nguyên văn Microsoft: "If you use Microsoft Configuration Manager, Microsoft recommends extensive testing of this ASR rule in Audit mode before you proceed to Block mode. The Configuration Manager client relies heavily on WMI." Máy không dùng SCCM mới bật Block ngay được. Trên máy không hỗ trợ (xem cột phiên bản), lệnh bật vẫn chạy thành công không báo lỗi — chỉ là không có tác dụng gì.
Nếu đã bật LSA Protection hoặc Credential Guard ở Mục 6.1 — rule "Block credential stealing..." ở trên không cần thiết nữa, theo đúng ghi chú chính thức: "If you enabled LSA protection (recommended, along with Credential Guard): This ASR rule isn't required. This ASR rule doesn't provide extra protection." Vẫn bật cả hai cũng không sai (không xung đột), chỉ là dư thừa. Nhớ lại Mục 6.1: từ Windows Server 2025, Credential Guard đã bật mặc định trên máy domain-joined không phải DC — trên máy đó, rule LSASS này rất có thể đã dư thừa sẵn.
Trước khi chạy bất kỳ lệnh nào ở mục này: ASR rules là tính năng của Microsoft Defender Antivirus và chỉ hoạt động khi Defender đang là phần mềm diệt virus chính, ở chế độ active. Nếu máy chủ đã cài AV của hãng khác (Kaspersky, ESET, Trend Micro, Bitdefender... rất phổ biến ở máy chủ SME), Defender tự lùi về passive mode và toàn bộ ASR rule không có tác dụng — nhưng Add-MpPreference vẫn chạy thành công, và Get-MpPreference vẫn hiện đủ rule, nên rất dễ tưởng đã xong. Kiểm chế độ thật trước:
# ĐIỀU KIỆN BẮT BUỘC - chạy TRƯỚC khi bật bất kỳ ASR rule nào
Get-MpComputerStatus | Select-Object AMRunningMode, RealTimeProtectionEnabled, AntivirusEnabledAMRunningMode phải là Normal và RealTimeProtectionEnabled phải là True. Nếu ra Passive, EDR Block Mode, SxS Passive Mode hay Off — nghĩa là máy đang dùng antivirus khác, ASR rules sẽ không hoạt động dù lệnh bật báo thành công. Dừng lại: hoặc chuyển hẳn sang Microsoft Defender làm AV chính, hoặc dùng tính năng tương đương của hãng AV đang có. Đừng bật ASR rồi coi như đã xong.
Cách thực thi:
# Hai rule chuẩn - bật Block ngay, môi trường nào cũng được (đã qua kiểm tra Defender Active ở trên)
Add-MpPreference -AttackSurfaceReductionRules_Ids `
"56a863a9-875e-4185-98a7-b882c64b5ce5", `
"9e6c4e1f-7d60-472f-ba1a-a39ef669e4b2" `
-AttackSurfaceReductionRules_Actions 1,1
# Rule WMI persistence: CÓ SCCM -> Audit (2) trước và test kỹ; KHÔNG có SCCM -> Block (1)
Add-MpPreference -AttackSurfaceReductionRules_Ids "e6db77e5-3df2-4cf1-b95a-636979351e5b" `
-AttackSurfaceReductionRules_Actions 2(giá trị 1 = Activated/Block theo đúng tài liệu Add-MpPreference — 0 = tắt, 2 = Audit mode, 6 = Warning)
Một rule khác rất đáng cân nhắc cho máy chủ nhưng KHÔNG nằm trong "Standard protection rules" — phải Audit trước: "Block process creations originating from PSExec and WMI commands" (d1e49aac-8f56-4280-b9ba-993a6d77406c) — PSExec/WMI là công cụ ransomware hay dùng để di chuyển ngang giữa các máy chủ, nhưng cũng là công cụ nhiều RMM/agent quản trị hợp pháp đang dùng. Microsoft cảnh báo thẳng: nếu dùng Microsoft Configuration Manager (SCCM), đừng bật rule này qua cách khác vì client SCCM "relies heavily on WMI" — cảnh báo này có ở cả hai rule liên quan WMI (rule này và rule WMI persistence ở bảng trên), không riêng rule nào. Bật Audit trước:
Add-MpPreference -AttackSurfaceReductionRules_Ids "d1e49aac-8f56-4280-b9ba-993a6d77406c" `
-AttackSurfaceReductionRules_Actions 2Cách xác nhận:
# Kiểm lại Defender vẫn ở Active mode - rule chỉ có tác dụng thật nếu điều kiện đầu mục vẫn đúng
Get-MpComputerStatus | Select-Object AMRunningMode, RealTimeProtectionEnabled
Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids
Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Actions
# Xem log: Event ID 1121 = rule vừa CHẶN thật (Block mode);
# Event ID 1122 = rule vừa GHI NHẬN nếu Block (Audit mode)
Get-WinEvent -FilterHashtable @{ LogName="Microsoft-Windows-Windows Defender/Operational"; Id=1121,1122 } `
-MaxEvents 20 -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, MessageSau khi chạy Audit mode đủ lâu (tối thiểu 1-2 tuần, theo dõi Event ID 1122) mà không thấy phần mềm hợp lệ nào bị đánh dấu, đổi Action từ 2 sang 1 để chuyển Block.
Đường lùi nếu một rule Block chặn nhầm phần mềm hợp lệ:
# Bước 1: mở khe hẹp cho ĐÚNG phần mềm bị chặn (loại trừ riêng cho ASR - rule LSASS và rule WMI
# persistence KHÔNG nhận loại trừ file/folder thông thường của Defender)
Add-MpPreference -AttackSurfaceReductionOnlyExclusions "C:\Program Files\PhanMemNghiepVu\agent.exe"
# Bước 2 (chỉ khi bước 1 không đủ): tắt riêng đúng rule đó, không cần tắt cả rule còn lại
Add-MpPreference -AttackSurfaceReductionRules_Ids "GUID-CUA-RULE-CAN-TAT" `
-AttackSurfaceReductionRules_Actions 0⚠️ -AttackSurfaceReductionOnlyExclusions áp cho tất cả ASR rule, không riêng rule đang gây phiền — đường loại trừ cho từng rule riêng chỉ có qua GPO/Intune/Defender portal, không qua PowerShell. Ghi lại mọi loại trừ đã thêm và rà lại định kỳ. Nếu vẫn cần tắt hẳn, ví dụ với rule PSExec/WMI ở trên:
Add-MpPreference -AttackSurfaceReductionRules_Ids "d1e49aac-8f56-4280-b9ba-993a6d77406c" `
-AttackSurfaceReductionRules_Actions 06.4 Exploit Protection — kế thừa EMET, thu hẹp lớp khai thác lỗ hổng phần mềm
Việc cần làm: Bật các mitigation chặn kỹ thuật khai thác lỗ hổng bộ nhớ (buffer overflow, ROP...) ở cấp hệ thống — độc lập với việc lỗ hổng đó đã có bản vá hay chưa.
Vì sao: Exploit Protection là phần kế thừa chính thức của EMET (Enhanced Mitigation Experience Toolkit) — công cụ đã hết hỗ trợ từ 31/07/2018. Theo Microsoft: "Many of the features in the Enhanced Mitigation Experience Toolkit (EMET) are included in exploit protection." Các mitigation này (DEP, ASLR, CFG, SEHOP...) không chặn một malware cụ thể — chúng chặn kỹ thuật mà exploit dùng để biến một lỗ hổng thành mã thực thi được, nên vẫn có giá trị ngay cả với lỗ hổng zero-day chưa có bản vá.
Cách thực thi — bật mitigation phổ biến nhất, rủi ro tương thích thấp nhất, ở mức hệ thống:
Set-ProcessMitigation -System -Enable DEP,SEHOP,CFG- DEP (Data Execution Prevention) — chặn thực thi mã ở vùng nhớ chỉ dành cho dữ liệu.
- SEHOP (Structured Exception Handler Overwrite Protection) — chặn kỹ thuật ghi đè chuỗi xử lý exception để chiếm luồng thực thi.
- CFG (Control Flow Guard) — kiểm tra tính hợp lệ của địa chỉ gọi hàm gián tiếp, chặn kỹ thuật ROP (Return-Oriented Programming).
Ba mitigation DEP/SEHOP/CFG ở trên không có chế độ Audit — khác với một số mitigation nâng cao hơn (ví dụ DisableWin32kSystemCalls, BlockDynamicCode) có bản Audit... riêng, hiệu quả cao nhưng dễ làm ứng dụng cũ hoặc ứng dụng dùng nhiều tương tác GUI crash nên Microsoft khuyến cáo test bằng bản Audit trước khi Enforce: "You should test exploit protection in all target use scenarios by using audit mode before deploying the configuration across a production environment or the rest of your network." Với DisableWin32kSystemCalls, Event ID 9 = audit, Event ID 10 = block tương ứng trong log Security-Mitigations (log này có hai kênh con Kernel Mode và User Mode; quy tắc "lẻ = audit, chẵn = block" chỉ áp dụng trong dải Event ID 1–24 của đúng provider này). Với DEP/SEHOP/CFG thì khác — đừng đi tìm log. DEP và SEHOP không sinh Event ID riêng nào trong Security-Mitigations. CFG khi block cũng không nằm ở Security-Mitigations mà ở một provider khác — WER-Diagnostics → Operational, Event ID 5. Cách xác nhận đúng cho ba mitigation này là Get-ProcessMitigation -System (xem "Cách xác nhận" cuối mục), không phải soi log. Đường lùi nếu mitigation ở mức hệ thống làm ứng dụng nào đó gặp lỗi — theo đúng ví dụ chính thức của Microsoft, phải dùng -Remove cùng -Disable để trả về đúng mặc định hệ thống (chỉ -Disable không kèm -Remove sẽ ghi đè thành "tắt cứng", không phải "trả về mặc định"):
Set-ProcessMitigation -System -Remove -Disable DEP,SEHOP,CFGMitigation mức hệ thống có hiệu lực đầy đủ sau khi khởi động lại. Nếu nó làm hỏng một ứng dụng cũ, sự cố có thể chỉ nổ ra ở lần reboot ngoài kế hoạch, có khi vài tuần sau — chủ động khởi động lại ngay trong khung giờ bảo trì sau khi bật, và xác nhận mọi dịch vụ chính lên đúng, đừng chờ tới lần reboot tình cờ mới biết.
Áp riêng cho một ứng dụng cụ thể (khi cần chặt hơn mức hệ thống cho một app nhạy cảm, ví dụ trình duyệt hoặc phần mềm xử lý file từ ngoài vào):
Set-ProcessMitigation -Name "app-nghiep-vu.exe" -Enable DEP,SEHOP -Disable ForceRelocateImagesXuất/nhập cấu hình dạng XML (để triển khai đồng loạt nhiều máy qua GPO, tương tự cách EMET cũ vẫn dùng file cấu hình XML):
Get-ProcessMitigation -RegistryConfigFilePath "C:\Backup\exploit-protection-hientai.xml"
# Triển khai lại ở máy khác:
Set-ProcessMitigation -PolicyFilePath "C:\Backup\exploit-protection-hientai.xml"(Không kèm -System — -RegistryConfigFilePath và -System thuộc hai parameter set khác nhau của Get-ProcessMitigation, không dùng chung được. Không kèm -System cũng lấy đủ: lệnh này đọc toàn bộ mitigation từ registry, gồm cả mức hệ thống lẫn từng app, đúng thứ cần để triển khai sang máy khác.)
Cách xác nhận:
Get-ProcessMitigation -SystemCột tương ứng DEP/SEHOP/CFG phải hiện ON — đây là cách xác nhận đúng cho ba mitigation này, không phải soi log Security-Mitigations (xem giải thích ở khối cảnh báo trên). Muốn xem log audit/block theo Event ID cho các mitigation khác có chế độ Audit (ví dụ DisableWin32kSystemCalls), tìm trong Applications and Services Logs → Microsoft → Windows → Security-Mitigations → Kernel Mode hoặc User Mode.
7. Sao lưu & phục hồi thảm hoạ
7.1 Nguyên tắc 3-2-1 — và vì sao ransomware buộc phải thêm số 1 và số 0
Việc cần làm: Giữ tối thiểu 3 bản sao dữ liệu, trên 2 loại phương tiện lưu trữ khác nhau, với 1 bản lưu ngoài vị trí vật lý của máy chủ gốc.
Vì sao: Đây là khung nguyên tắc sao lưu được CISA (Cybersecurity and Infrastructure Security Agency — cơ quan an ninh mạng của Mỹ) khuyến nghị trực tiếp cho doanh nghiệp nhỏ và vừa. Với ransomware hiện đại — thứ chủ động quét tìm và mã hoá/xoá cả các bản backup nó tìm thấy trên cùng mạng trước khi mã hoá dữ liệu chính — nguyên tắc 3-2-1 gốc (vốn thiết kế để chống hỏng đĩa/thiên tai) cần thêm hai điều kiện: ít nhất một bản offline — CISA khuyến nghị đúng chữ này (offline copies) — hoặc immutable/object-lock nếu nhà cung cấp cloud của bạn có (ransomware không với tới được dù có credential quản trị), và zero lỗi khi test phục hồi — chính là điều Mục 7.3 dưới đây nói tới.
Áp dụng cụ thể cho một máy chủ Windows: dữ liệu gốc trên máy chủ không tính là một trong ba bản; bản thứ 2 có thể là ổ đĩa ngoài/NAS nội bộ (loại phương tiện khác ổ đĩa hệ thống); bản thứ 3 — bản offsite — nên là nơi mà một tài khoản quản trị bị chiếm trên chính máy chủ đó không tự động có quyền xoá được (băng từ luân chuyển ra ngoài, cloud storage với immutability/object lock, hoặc ổ đĩa rời không cắm thường trực).
7.2 Windows Server Backup qua PowerShell
Việc cần làm: Cài tính năng Windows Server Backup, dựng một policy sao lưu định kỳ gồm cả bare-metal recovery, system state, và dữ liệu volume.
Vì sao: Windows Server Backup là công cụ có sẵn trong Windows (không cần license thêm), đủ cho backup bare-metal (phục hồi toàn bộ máy sau sự cố phần cứng) lẫn backup dữ liệu thông thường.
Cách thực thi:
# 1. Cài tính năng (bao gồm module PowerShell WindowsServerBackup)
Install-WindowsFeature -Name Windows-Server-Backup -IncludeManagementTools# 2. Dựng một policy backup đầy đủ: bare-metal recovery + system state + volume dữ liệu
$Policy = New-WBPolicy
Add-WBBareMetalRecovery -Policy $Policy
Add-WBSystemState -Policy $Policy
$Volume = Get-WBVolume -VolumePath "D:"
Add-WBVolume -Policy $Policy -Volume $VolumeNếu máy này là Domain Controller, Add-WBSystemState đưa cả cơ sở dữ liệu Active Directory vào bản backup — tức toàn bộ dấu vân tay mật khẩu của mọi tài khoản trong domain. Đối xử với ổ backup như tài sản mật ngang máy chủ: kiểm soát vật lý, không mang ra ngoài tuỳ tiện, huỷ đúng quy trình khi thanh lý. Muốn mã hoá ổ đích, kiểm tra tương thích BitLocker với Windows Server Backup trước, đừng bật rồi mới thử.
Add-WBBackupTarget FORMAT ổ đích và xoá vĩnh viễn mọi dữ liệu đang có trên đó — muộn nhất là khi lưu policy ở bước dưới, và có thể xảy ra ngay tại lệnh này khi bạn trả lời "Y" cho câu hỏi xác nhận. Nguyên văn Microsoft: "If you specify a disk as a storage location for backups, the server formats the disk before it uses the disk and permanently deletes any existing data on the disk." — tài liệu không nói rõ thời điểm chính xác trong hai bước, nên coi cả hai bước dưới đây đều có thể là điểm không quay lại được. Đây là hành động không hoàn tác được. Chọn ổ theo đúng số đĩa thật (DiskNumber), không chọn theo chỉ số mảng $Disks[1] — thứ tự mảng do hệ thống liệt kê, đổi theo máy và đổi cả khi cắm/rút ổ khác:
# B1. IN RA toàn bộ thuộc tính của từng ổ - đọc kỹ, không đoán
Get-WBDisk | Format-List *
# B2. Chọn ổ THEO SỐ ĐĨA thật (đổi số 2 cho đúng máy của bạn), không dùng chỉ số mảng
$oBackup = Get-WBDisk | Where-Object { $_.DiskNumber -eq 2 }
if (-not $oBackup) { throw "DỪNG LẠI: không tìm thấy đĩa số 2" }
if (@($oBackup).Count -ne 1) { throw "DỪNG LẠI: khớp nhiều hơn một đĩa" }
# B3. Chặn cứng: ổ đích KHÔNG được mang chữ ổ đang dùng cho hệ thống/dữ liệu
$oCamDung = @('C','D') # LIỆT KÊ đúng ổ production của máy này
$chuHienCo = (Get-Partition -DiskNumber $oBackup.DiskNumber -ErrorAction SilentlyContinue).DriveLetter |
Where-Object { $_ }
foreach ($chu in $chuHienCo) {
if ($oCamDung -contains "$chu") { throw "DỪNG LẠI: đĩa này đang chứa ổ $chu" }
}
# B4. Gán làm đích - KHÔNG thêm -Force, giữ lại câu hỏi xác nhận
$BackupLocation = New-WBBackupTarget -Disk $oBackup
Add-WBBackupTarget -Policy $Policy -Target $BackupLocation
# lệnh sẽ HỎI xác nhận - đọc kỹ tên ổ trong câu hỏi TRƯỚC khi gõ Y - TUYỆT ĐỐI không thêm -ForceỔ đích phải là ổ trống, dành riêng, đã xác nhận không còn dữ liệu cần giữ. Chưa có ổ như vậy thì DỪNG — đừng mượn tạm một ổ đang dùng. Remove-WBPolicy (ở cuối mục này) chỉ thả ổ ra khỏi policy, không phục hồi dữ liệu đã bị xoá — nó không phải đường lùi cho lệnh format, chỉ là cách dừng lịch backup định kỳ đang trỏ vào ổ đó.
# 5. Đặt lịch chạy hàng ngày, rồi lưu thành policy định kỳ chính thức
Set-WBSchedule -Policy $Policy -Schedule 01:00
Set-WBPolicy -Policy $Policy(Sau khi lưu, ổ đĩa vừa gán ở bước 4 bị Windows Server Backup ĐỘC QUYỀN quản lý: repartition, ẩn khỏi Explorer — hành vi này là chủ đích thiết kế của Microsoft, không phải lỗi. Muốn xem lại, dùng Disk Management (diskmgmt.msc), không tìm trong Explorer. Muốn ngừng hẳn và thả ổ ra khỏi quyền quản lý này — không phục hồi dữ liệu đã bị format, chỉ dừng lịch: Remove-WBPolicy -Policy (Get-WBPolicy) -Force.)
Cấu hình trên mới đáp ứng số 3 và số 2 của nguyên tắc 3-2-1 ở Mục 7.1. Số 1 — bản ngoài vị trí, không nằm trong tầm tay tài khoản quản trị của máy chủ này — phải làm thêm bằng một trong ba cách: luân chuyển ổ rời ra ngoài (rút hẳn khỏi máy sau mỗi lần sao chép), sao lên cloud storage có bật khoá chống xoá theo thời gian (object lock/immutability), hoặc sao sang một hệ lưu trữ dùng bộ credential khác hoàn toàn với credential của máy chủ này. Ransomware chạy với quyền quản trị trên chính máy chủ có thể xoá bản backup bằng công cụ của Windows (wbadmin delete catalog, vssadmin delete shadows) trước khi mã hoá dữ liệu — ổ backup dù bị ẩn khỏi Explorer vẫn nằm trong tầm với của mọi tiến trình chạy quyền hệ thống. Bỏ bước này, bạn có backup chống hỏng đĩa, không có backup chống ransomware.
Chạy một lần ngay (không chờ lịch), theo dõi tiến trình:
Start-WBBackup -Policy (Get-WBPolicy) -Async
Get-WBJobCách xác nhận:
Get-WBJob -Previous 1
wbadmin get versionsGet-WBJob -Previous 1 phải hiện JobState: Completed, không phải Failed. wbadmin get versions liệt kê từng bản backup theo mốc thời gian — dùng chính các mốc MM/DD/YYYY-HH:MM này khi cần phục hồi ở Mục 7.3.
7.3 Kiểm thử phục hồi — mục hay bị bỏ qua nhất, và là một trong hai hành động trong toàn bộ 2 bài này KHÔNG có đường lùi nếu làm sai
Việc cần làm: Định kỳ thực sự phục hồi dữ liệu từ bản backup — không chỉ tin rằng job backup "Completed" là đủ.
Vì sao: Một job backup báo thành công chỉ chứng minh được quá trình ghi dữ liệu ra đích không lỗi — nó không chứng minh được dữ liệu đó phục hồi lại và chạy được. Ví dụ kinh điển: backup file .bak của một database ra thành công, nhưng khi restore thật thì database không attach lên được vì thiếu log file đi kèm, hoặc lệch phiên bản engine. Theo khuyến nghị của CISA: "Test backup procedure to make sure your team can rapidly restore data both fully and partially, and to ensure you can roll back data at least seven days if needed."
Lý tưởng nhất: làm restore test trên một máy khác (máy ảo dựng riêng), không phải trên máy chủ đang chạy dịch vụ. Nếu buộc phải làm trên máy thật, ổ đích phải là ổ trống dành riêng cho việc thử, gắn vào trước khi thử và tháo ra sau khi xong — đừng để một ổ tên T: nằm thường trực cạnh dữ liệu production.
Đây là hành động thứ hai (cùng với việc chọn ổ đích ở Mục 7.2) trong toàn bộ hai bài viết này không có "đường lùi" nếu làm sai — phục hồi đè lên đúng vị trí đang chứa dữ liệu production sẽ GHI ĐÈ dữ liệu mới hơn bằng bản backup cũ, và không có lệnh nào hoàn tác được việc này. Luôn dùng tham số chỉ định đích phục hồi thay thế, không bao giờ để mặc định phục hồi về đúng vị trí gốc khi đây chỉ là một lần TEST. wbadmin start recovery sẽ HỎI lại và nêu đích danh ổ sắp bị ghi đè trước khi thực hiện — đọc kỹ tên ổ trong câu hỏi đó, đây là chốt chặn cuối cùng. Tuyệt đối không thêm -quiet (tham số này tắt luôn câu hỏi xác nhận):
# Kiểm trước: đích phục hồi KHÔNG được trùng ổ production, và phải là ổ còn trống
$dichPhucHoi = "T"
$oProduction = @("C","D") # LIỆT KÊ đúng ổ production của máy này
if ($oProduction -contains $dichPhucHoi) { throw "DỪNG LẠI: đích phục hồi trùng ổ production" }
$v = Get-Volume -DriveLetter $dichPhucHoi -ErrorAction Stop
$v | Format-List DriveLetter, FileSystemLabel, Size, SizeRemaining
if (($v.Size - $v.SizeRemaining) -gt 1GB) { throw "DỪNG LẠI: ổ $dichPhucHoi đang có dữ liệu" }
# Kiểm tra dữ liệu có thể phục hồi từ phiên bản nào - LẤY ĐÚNG mốc thời gian
# thật từ kết quả lệnh này, đừng gõ tay một giá trị "cho có"
wbadmin get versions
# Phục hồi THỬ một volume riêng - "-recoveryTarget" trỏ sang ổ đĩa KHÁC,
# KHÔNG phục hồi đè lên đúng ổ D: đang chạy dữ liệu thật.
# ĐỔI "09/15/2026-01:00" thành đúng mốc lấy được ở lệnh "wbadmin get versions" trên
wbadmin start recovery -version:09/15/2026-01:00 -itemType:Volume -items:D: -recoveryTarget:T:
# Phục hồi THỬ một file/thư mục cụ thể vào vị trí thay thế
# -overwrite:CreateCopy khai tường minh hành vi khi trùng tên - dừng dựa vào mặc định
wbadmin start recovery -version:09/15/2026-01:00 -itemType:File `
-items:D:\du-lieu-nghiep-vu -recoveryTarget:T:\phuc-hoi-thu -recursive -overwrite:CreateCopyChecklist restore test tối thiểu, làm định kỳ (không có con số cứng từ Microsoft — thực hành hợp lý là tối thiểu mỗi quý, hoặc ngay sau bất kỳ thay đổi hạ tầng lớn nào):
- Phục hồi một volume đầy đủ vào ổ thay thế — xác nhận dữ liệu đọc được, không lỗi checksum.
- Phục hồi một file/thư mục lẻ — mô phỏng đúng tình huống thực tế phổ biến nhất ("ai đó lỡ xoá nhầm một thư mục", không phải "mất cả máy chủ").
- Phục hồi bare-metal/system state trên phần cứng khác (hoặc máy ảo dựng riêng) — đây là bước hay bị bỏ qua nhất vì tốn thời gian nhất, nhưng cũng là bước duy nhất trả lời đúng câu hỏi "nếu máy chủ này chết hẳn, tôi dựng lại được trong bao lâu?". Xác nhận máy phục hồi boot lên được, đăng nhập được, dịch vụ chính khởi động đúng — không chỉ "file đã restore xong".
Cách xác nhận sau mỗi lần test: ghi lại thời gian thực tế từ lúc bắt đầu restore tới lúc dịch vụ chạy được (Recovery Time thực đo, so với mục tiêu RTO nếu công ty có đặt ra), và log lại kết quả — một lần restore test thành công 6 tháng trước không đảm bảo bản backup tuần này cũng phục hồi được nếu cấu hình hệ thống đã đổi khác.
8. Mã hoá dữ liệu — đã viết riêng, chỉ nhắc ngắn
Mã hoá là lớp phòng thủ cuối — dữ liệu dù bị đánh cắp cũng không đọc được nếu không có khoá. Toàn bộ phần này (BitLocker cho ổ đĩa, TLS 1.3 cho dữ liệu truyền qua mạng, SMB Encryption cho file share nội bộ, TDE/Always Encrypted cho SQL Server, EFS cho từng file theo người dùng, cùng Secure Boot/TPM/VBS/Credential Guard đã nhắc lại ở Mục 6.1) đã được viết đầy đủ kèm lệnh PowerShell xác nhận từng bước tại bài Mã hoá dữ liệu trên Windows Server 2022 — không nhắc lại chi tiết ở đây để tránh trùng lặp. Nếu máy chủ của bạn đã làm xong Mục 1-7 của hai bài này mà chưa đụng tới mã hoá, đó là bài nên đọc tiếp theo.
Kết loạt bài — tám mảng, và những gì hướng dẫn này không thay thế được
Hai bài viết đã đi qua tám mảng: baseline hệ điều hành, danh tính & truy cập, bảo vệ chính PowerShell, hạ tầng mạng (Phần 1) — giám sát & phát hiện, kiểm soát ứng dụng & thu hẹp bề mặt tấn công, sao lưu & phục hồi thảm hoạ, và mã hoá dữ liệu (Phần 2). Làm đúng, làm đủ cả tám mảng này giúp máy chủ Windows Server khó bị xâm nhập hơn nhiều so với cấu hình mặc định — nhưng nói cho đúng, giống câu đã kết ở Phần 1: đây là điều kiện cần, không phải điều kiện đủ.
Có những thứ không nằm trong khả năng của bất kỳ hướng dẫn cấu hình kỹ thuật nào, kể cả bài này:
- Đào tạo nhận thức người dùng — phần lớn sự cố thực tế bắt đầu từ một người dùng hợp lệ bấm vào đúng thứ không nên bấm, không phải từ một lỗ hổng zero-day. Không GPO nào ngăn được việc đó.
- Kiểm thử xâm nhập định kỳ (pentest) — hướng dẫn này giả định các cấu hình đã làm đúng theo mô tả; chỉ có việc thực sự thử tấn công hệ thống của chính mình mới phát hiện được những kẽ hở không nằm trong danh sách checklist nào, kể cả checklist dài như hai bài này.
- Quy trình phản ứng sự cố (incident response) — có log tốt (Mục 5) chỉ có giá trị nếu có người đọc log đó và biết phải làm gì tiếp theo khi thấy dấu hiệu bất thường.
- Vá lỗi liên tục — mọi lớp phòng thủ ở đây đều giả định hệ điều hành và ứng dụng được cập nhật đều đặn như đã nói ở Mục 1.1 Phần 1; một baseline hoàn hảo trên một hệ thống chưa vá suốt sáu tháng vẫn là hệ thống dễ bị khai thác.
Bài viết liên quan
STEP Có Thể Hỗ Trợ Gì
Dựng được Windows Event Collector, viết đúng ASR rule không chặn nhầm phần mềm nghiệp vụ, hay quan trọng hơn — thực sự bỏ thời gian mỗi quý để test phục hồi thay vì chỉ tin vào dòng chữ "Backup Completed" — đều là những việc cần người làm đều đặn, không phải làm một lần rồi quên. Dịch vụ CIO/quản trị hạ tầng thuê ngoài của STEP nhận vận hành trọn phần này cho khách hàng: dựng hệ thống giám sát và log tập trung, triển khai kiểm soát ứng dụng theo đúng quy trình Audit-trước-Enforce-sau để không làm gián đoạn nghiệp vụ đang chạy, và quan trọng nhất — lên lịch và tự thực hiện restore test định kỳ, báo cáo kết quả thật cho bạn thay vì để tới lúc sự cố mới biết bản backup có dùng được hay không.
Thường phản hồi trong vòng vài phút trong giờ làm việc.