v2.3
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
import re, json, sys, io
|
||||
from openpyxl import load_workbook
|
||||
from unidecode import unidecode
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
# Extract all checks from PowerShell script
|
||||
ps_content = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
checks = re.findall(r'Write-CheckResult\s+"(.+?)"\s+"(.+?)"', ps_content)
|
||||
print(f'PS script checks: {len(checks)}')
|
||||
|
||||
# Build criteria lookup: CheckId -> description
|
||||
ps_criteria = {}
|
||||
for cid, desc in checks:
|
||||
full = f"{cid}. {desc}"
|
||||
key = unidecode(full)
|
||||
ps_criteria[key] = (cid, full)
|
||||
|
||||
# Load Excel checklist
|
||||
wb = load_workbook(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\Windows_Checklist.xlsx')
|
||||
ws = wb.worksheets[0]
|
||||
|
||||
# Build row mapping: scan Excel for criteria IDs (like "1.1.1" in column A)
|
||||
# Compare unidecode'd criteria text to match PS output
|
||||
excel_rows = {}
|
||||
print(f'\nScanning Excel rows 1-{ws.max_row} for criteria IDs...')
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = ws.cell(row=row, column=1).value
|
||||
val_b = ws.cell(row=row, column=2).value
|
||||
|
||||
# Try to find criteria ID in column A (like "1.1.1")
|
||||
text_a = str(val_a).strip() if val_a else ""
|
||||
text_b = str(val_b).strip() if val_b else ""
|
||||
|
||||
# Check if this row has a criteria ID pattern (like "1.1.1" or "1.1.1.")
|
||||
# Also try matching the full text from column B
|
||||
combined = f"{text_a} {text_b}".strip()
|
||||
norm = unidecode(combined)
|
||||
|
||||
if norm in ps_criteria:
|
||||
cid, full_text = ps_criteria[norm]
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[norm] # Remove matched
|
||||
|
||||
# Now try matching by CheckId prefix in column A
|
||||
still_unmatched = dict(ps_criteria)
|
||||
for cid_key, (cid, full_text) in still_unmatched.items():
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
if val_a and cid in val_a:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
print(f'\nMatched via full text: {len(excel_rows)}')
|
||||
print(f'Matched via ID search: {194 - len(ps_criteria) - len(excel_rows)}')
|
||||
print(f'Still unmatched: {len(ps_criteria)}')
|
||||
|
||||
# For unmatched, find the closest row by ID pattern
|
||||
# Parse CheckId like "1.1.1" into section numbers
|
||||
for cid_key, (cid, full_text) in list(ps_criteria.items()):
|
||||
parts = cid.split('.')
|
||||
# Try to find a row where column A contains this ID prefix
|
||||
found = False
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
if val_a == cid or val_a == cid + '.':
|
||||
if row not in excel_rows:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
print(f' No Excel row for: [{cid}] {full_text[:60]}')
|
||||
|
||||
print(f'\nFinal matched rows: {len(excel_rows)}')
|
||||
print(f'Final unmatched: {len(ps_criteria)}')
|
||||
|
||||
# Build new config
|
||||
new_data = []
|
||||
for row in sorted(excel_rows.keys()):
|
||||
new_data.append({str(row): excel_rows[row]})
|
||||
|
||||
new_config = {"data": new_data}
|
||||
|
||||
# Write new config
|
||||
output_path = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\windows_config_new.json'
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(new_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f'\nNew config written to: {output_path}')
|
||||
print(f'Entries: {len(new_data)}')
|
||||
|
||||
# Print summary of row mapping
|
||||
print('\nSample row mapping:')
|
||||
for row in sorted(excel_rows.keys())[:10]:
|
||||
print(f' Row {row}: {excel_rows[row][:70]}')
|
||||
@@ -0,0 +1,24 @@
|
||||
import json
|
||||
from unidecode import unidecode
|
||||
|
||||
with open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\output\MEVAS-NTL-DATAN_2026_07_29-05_18_36.txt', 'r', encoding='utf-8', errors='replace') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
with open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\tools\debug_output.txt', 'w', encoding='utf-8') as out:
|
||||
for i, line in enumerate(lines):
|
||||
if any(x in line for x in ['2.1.2', '2.1.15', '2.1.17', '2.1.21', '2.1.22']):
|
||||
if 'Access' in line or 'Create' in line or 'Deny' in line or 'Enable' in line:
|
||||
out.write(f'Line {i+1}:\n')
|
||||
out.write(f' RAW: {repr(line.strip())}\n')
|
||||
out.write(f' NORM: {unidecode(line.strip())}\n')
|
||||
out.write('\n')
|
||||
|
||||
# Also show what's in the PS script for comparison
|
||||
out.write('=== PS Script variants ===\n')
|
||||
ps = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
import re
|
||||
for m in re.finditer(r'Write-CheckResult\s+"(2\.1\.\d+)"\s+"(.+?)"', ps):
|
||||
out.write(f' CheckId={m.group(1)} Desc={m.group(2)[:80]}\n')
|
||||
out.write(f' Normalized: {unidecode(m.group(2))}\n')
|
||||
|
||||
print('Debug output written to tools/debug_output.txt')
|
||||
@@ -0,0 +1,139 @@
|
||||
Line 22:
|
||||
RAW: '{"2.1.2. Cau hinh chinh sach \'Access this computer from the network\' [Ch��% MS]" : "FAILED"}'
|
||||
NORM: {"2.1.2. Cau hinh chinh sach 'Access this computer from the network' [Ch% MS]" : "FAILED"}
|
||||
|
||||
Line 34:
|
||||
RAW: '{"2.1.15. Cau hinh chinh sach \'Create symbolic links\' [Ch��% MS]" : "FAILED"}'
|
||||
NORM: {"2.1.15. Cau hinh chinh sach 'Create symbolic links' [Ch% MS]" : "FAILED"}
|
||||
|
||||
Line 36:
|
||||
RAW: '{"2.1.17. Cau hinh chinh sach \'Deny access to this computer from the network\' [Ch��% MS]" : "FAILED"}'
|
||||
NORM: {"2.1.17. Cau hinh chinh sach 'Deny access to this computer from the network' [Ch% MS]" : "FAILED"}
|
||||
|
||||
Line 39:
|
||||
RAW: '{"2.1.20. Cau hinh chinh sach \'Deny log on locally\'" : "FAILED"}'
|
||||
NORM: {"2.1.20. Cau hinh chinh sach 'Deny log on locally'" : "FAILED"}
|
||||
|
||||
Line 40:
|
||||
RAW: '{"2.1.21. Cau hinh chinh sach \'Deny log on through Remote Desktop Services\' [Ch��% MS]" : "FAILED"}'
|
||||
NORM: {"2.1.21. Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Ch% MS]" : "FAILED"}
|
||||
|
||||
Line 41:
|
||||
RAW: '{"2.1.22. Cau hinh chinh sach \'Enable computer and user accounts to be trusted for delegation\' [Ch��% MS]" : "PASSED"}'
|
||||
NORM: {"2.1.22. Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegation' [Ch% MS]" : "PASSED"}
|
||||
|
||||
Line 165:
|
||||
RAW: "[2.1.2] Cau hinh chinh sach 'Access this computer from the network' [Ch��% MS]"
|
||||
NORM: [2.1.2] Cau hinh chinh sach 'Access this computer from the network' [Ch% MS]
|
||||
|
||||
Line 174:
|
||||
RAW: "[2.1.15] Cau hinh chinh sach 'Create symbolic links' [Ch��% MS]"
|
||||
NORM: [2.1.15] Cau hinh chinh sach 'Create symbolic links' [Ch% MS]
|
||||
|
||||
Line 176:
|
||||
RAW: "[2.1.17] Cau hinh chinh sach 'Deny access to this computer from the network' [Ch��% MS]"
|
||||
NORM: [2.1.17] Cau hinh chinh sach 'Deny access to this computer from the network' [Ch% MS]
|
||||
|
||||
Line 179:
|
||||
RAW: "[2.1.20] Cau hinh chinh sach 'Deny log on locally'"
|
||||
NORM: [2.1.20] Cau hinh chinh sach 'Deny log on locally'
|
||||
|
||||
Line 180:
|
||||
RAW: "[2.1.21] Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Ch��% MS]"
|
||||
NORM: [2.1.21] Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Ch% MS]
|
||||
|
||||
=== PS Script variants ===
|
||||
CheckId=2.1.1 Desc=Cau hinh chinh sach 'Access Credential Manager as a trusted caller'
|
||||
Normalized: Cau hinh chinh sach 'Access Credential Manager as a trusted caller'
|
||||
CheckId=2.1.2 Desc=Cau hinh chinh sach 'Access this computer from the network' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Access this computer from the network' [Chi DC]
|
||||
CheckId=2.1.2 Desc=Cau hinh chinh sach 'Access this computer from the network' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Access this computer from the network' [Chi MS]
|
||||
CheckId=2.1.3 Desc=Cau hinh chinh sach 'Act as part of the operating system'
|
||||
Normalized: Cau hinh chinh sach 'Act as part of the operating system'
|
||||
CheckId=2.1.4 Desc=Cau hinh chinh sach 'Add workstations to domain' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Add workstations to domain' [Chi DC]
|
||||
CheckId=2.1.5 Desc=Cau hinh chinh sach 'Adjust memory quotas for a process'
|
||||
Normalized: Cau hinh chinh sach 'Adjust memory quotas for a process'
|
||||
CheckId=2.1.6 Desc=Cau hinh chinh sach 'Allow log on locally'
|
||||
Normalized: Cau hinh chinh sach 'Allow log on locally'
|
||||
CheckId=2.1.7 Desc=Cau hinh chinh sach 'Allow log on through Remote Desktop Services' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Allow log on through Remote Desktop Services' [Chi DC]
|
||||
CheckId=2.1.7 Desc=Cau hinh chinh sach 'Allow log on through Remote Desktop Services' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Allow log on through Remote Desktop Services' [Chi MS]
|
||||
CheckId=2.1.8 Desc=Cau hinh chinh sach 'Back up files and directories'
|
||||
Normalized: Cau hinh chinh sach 'Back up files and directories'
|
||||
CheckId=2.1.9 Desc=Cau hinh chinh sach 'Change the system time'
|
||||
Normalized: Cau hinh chinh sach 'Change the system time'
|
||||
CheckId=2.1.10 Desc=Cau hinh chinh sach 'Change the time zone'
|
||||
Normalized: Cau hinh chinh sach 'Change the time zone'
|
||||
CheckId=2.1.11 Desc=Cau hinh chinh sach 'Create a pagefile'
|
||||
Normalized: Cau hinh chinh sach 'Create a pagefile'
|
||||
CheckId=2.1.12 Desc=Cau hinh chinh sach 'Create a token object'
|
||||
Normalized: Cau hinh chinh sach 'Create a token object'
|
||||
CheckId=2.1.13 Desc=Cau hinh chinh sach 'Create global objects'
|
||||
Normalized: Cau hinh chinh sach 'Create global objects'
|
||||
CheckId=2.1.14 Desc=Cau hinh chinh sach 'Create permanent shared objects'
|
||||
Normalized: Cau hinh chinh sach 'Create permanent shared objects'
|
||||
CheckId=2.1.15 Desc=Cau hinh chinh sach 'Create symbolic links' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Create symbolic links' [Chi DC]
|
||||
CheckId=2.1.15 Desc=Cau hinh chinh sach 'Create symbolic links' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Create symbolic links' [Chi MS]
|
||||
CheckId=2.1.16 Desc=Cau hinh chinh sach 'Debug programs'
|
||||
Normalized: Cau hinh chinh sach 'Debug programs'
|
||||
CheckId=2.1.17 Desc=Cau hinh chinh sach 'Deny access to this computer from the network' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Deny access to this computer from the network' [Chi DC]
|
||||
CheckId=2.1.17 Desc=Cau hinh chinh sach 'Deny access to this computer from the network' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Deny access to this computer from the network' [Chi MS]
|
||||
CheckId=2.1.18 Desc=Cau hinh chinh sach 'Deny log on as a batch job'
|
||||
Normalized: Cau hinh chinh sach 'Deny log on as a batch job'
|
||||
CheckId=2.1.19 Desc=Cau hinh chinh sach 'Deny log on as a service'
|
||||
Normalized: Cau hinh chinh sach 'Deny log on as a service'
|
||||
CheckId=2.1.20 Desc=Cau hinh chinh sach 'Deny log on locally'
|
||||
Normalized: Cau hinh chinh sach 'Deny log on locally'
|
||||
CheckId=2.1.21 Desc=Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Chi DC]
|
||||
CheckId=2.1.21 Desc=Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Chi MS]
|
||||
CheckId=2.1.22 Desc=Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegat
|
||||
Normalized: Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegation' [Chi DC]
|
||||
CheckId=2.1.22 Desc=Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegat
|
||||
Normalized: Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegation' [Chi MS]
|
||||
CheckId=2.1.23 Desc=Cau hinh chinh sach 'Force shutdown from a remote system'
|
||||
Normalized: Cau hinh chinh sach 'Force shutdown from a remote system'
|
||||
CheckId=2.1.24 Desc=Cau hinh chinh sach 'Generate security audits'
|
||||
Normalized: Cau hinh chinh sach 'Generate security audits'
|
||||
CheckId=2.1.25 Desc=Cau hinh chinh sach 'Impersonate a client after authentication' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Impersonate a client after authentication' [Chi DC]
|
||||
CheckId=2.1.25 Desc=Cau hinh chinh sach 'Impersonate a client after authentication' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Impersonate a client after authentication' [Chi MS]
|
||||
CheckId=2.1.26 Desc=Cau hinh chinh sach 'Increase scheduling priority'
|
||||
Normalized: Cau hinh chinh sach 'Increase scheduling priority'
|
||||
CheckId=2.1.27 Desc=Cau hinh chinh sach 'Load and unload device drivers'
|
||||
Normalized: Cau hinh chinh sach 'Load and unload device drivers'
|
||||
CheckId=2.1.28 Desc=Cau hinh chinh sach 'Lock pages in memory'
|
||||
Normalized: Cau hinh chinh sach 'Lock pages in memory'
|
||||
CheckId=2.1.29 Desc=Cau hinh chinh sach 'Manage auditing and security log' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Manage auditing and security log' [Chi DC]
|
||||
CheckId=2.1.29 Desc=Cau hinh chinh sach 'Manage auditing and security log' [Chỉ MS]
|
||||
Normalized: Cau hinh chinh sach 'Manage auditing and security log' [Chi MS]
|
||||
CheckId=2.1.30 Desc=Cau hinh chinh sach 'Modify an object label'
|
||||
Normalized: Cau hinh chinh sach 'Modify an object label'
|
||||
CheckId=2.1.31 Desc=Cau hinh chinh sach 'Modify firmware environment values'
|
||||
Normalized: Cau hinh chinh sach 'Modify firmware environment values'
|
||||
CheckId=2.1.32 Desc=Cau hinh chinh sach 'Perform volume maintenance tasks'
|
||||
Normalized: Cau hinh chinh sach 'Perform volume maintenance tasks'
|
||||
CheckId=2.1.33 Desc=Cau hinh chinh sach 'Profile single process'
|
||||
Normalized: Cau hinh chinh sach 'Profile single process'
|
||||
CheckId=2.1.34 Desc=Cau hinh chinh sach 'Profile system performance'
|
||||
Normalized: Cau hinh chinh sach 'Profile system performance'
|
||||
CheckId=2.1.35 Desc=Cau hinh chinh sach 'Replace a process level token'
|
||||
Normalized: Cau hinh chinh sach 'Replace a process level token'
|
||||
CheckId=2.1.36 Desc=Cau hinh chinh sach 'Restore files and directories'
|
||||
Normalized: Cau hinh chinh sach 'Restore files and directories'
|
||||
CheckId=2.1.37 Desc=Cau hinh chinh sach 'Shut down the system'
|
||||
Normalized: Cau hinh chinh sach 'Shut down the system'
|
||||
CheckId=2.1.38 Desc=Cau hinh chinh sach 'Synchronize directory service data' [Chỉ DC]
|
||||
Normalized: Cau hinh chinh sach 'Synchronize directory service data' [Chi DC]
|
||||
CheckId=2.1.39 Desc=Cau hinh chinh sach 'Take ownership of files or other objects'
|
||||
Normalized: Cau hinh chinh sach 'Take ownership of files or other objects'
|
||||
@@ -0,0 +1,22 @@
|
||||
import re
|
||||
|
||||
ps = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
|
||||
# Find variable definitions for CheckIdPrefix, LabelPrefix, Label
|
||||
for m in re.finditer(r'\$(CheckIdPrefix|LabelPrefix|Label)\s*=\s*"(.+?)"', ps):
|
||||
print(f'{m.group(1)} = "{m.group(2)}"')
|
||||
|
||||
# Find Write-CheckResult calls with variable CheckIds
|
||||
print("\nWrite-CheckResult with variables:")
|
||||
for m in re.finditer(r'Write-CheckResult\s+"(\$.+?)"\s+"(.+?)"', ps):
|
||||
print(f' CheckId="{m.group(1)}" Desc="{m.group(2)[:80]}"')
|
||||
|
||||
# Also find the loop context around these calls
|
||||
print("\nContext for variable-based checks:")
|
||||
for m in re.finditer(r'(\$CheckIdPrefix\s*=\s*.+?)\n', ps):
|
||||
start = max(0, m.start() - 50)
|
||||
end = min(len(ps), m.end() + 300)
|
||||
context = ps[start:end]
|
||||
print(f' ---')
|
||||
for line in context.split('\n')[:10]:
|
||||
print(f' {line[:120]}')
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"ubuntu": {
|
||||
"icon": "🟠",
|
||||
"display_name": "Ubuntu",
|
||||
"versions": {
|
||||
"ubuntu_2204": {
|
||||
"name": "Ubuntu 22.04 Audit Check Script",
|
||||
"file": "Hardenning_Ubuntu2204_2.0.2.zip",
|
||||
"version": "v2.0.2",
|
||||
"updated": "08/04/2026",
|
||||
"os_version_label": "22.04",
|
||||
"source_path": "tools/Hardenning_Ubuntu2204_2.0.2.zip"
|
||||
},
|
||||
"ubuntu_2004": {
|
||||
"name": "Ubuntu 20.04 Audit Check Script",
|
||||
"file": "Hardenning_Ubuntu2004_2.0.2.zip",
|
||||
"version": "v2.0.2",
|
||||
"updated": "08/04/2026",
|
||||
"os_version_label": "20.04",
|
||||
"source_path": "tools/Hardenning_Ubuntu2004_2.0.2.zip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"centos": {
|
||||
"icon": "🔵",
|
||||
"display_name": "CentOS",
|
||||
"versions": {
|
||||
"centos_7": {
|
||||
"name": "Centos 7 Audit Check Script",
|
||||
"file": "hardening_centos_7_2.0.2.zip",
|
||||
"version": "v2.0.2",
|
||||
"updated": "15/04/2026",
|
||||
"os_version_label": "7",
|
||||
"source_path": "tools/hardening_centos_7_2.0.2.zip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rhel": {
|
||||
"icon": "🎩",
|
||||
"display_name": "RHEL",
|
||||
"versions": {
|
||||
"rhel_default": {
|
||||
"name": "RHEL Audit Script",
|
||||
"file": "audit_cis_rhel_v2.sh",
|
||||
"version": "v2.1.0",
|
||||
"updated": "03/02/2026",
|
||||
"os_version_label": "",
|
||||
"source_path": null
|
||||
},
|
||||
"rhel_8": {
|
||||
"name": "RHEL 8 Audit Script",
|
||||
"file": "Hardenning_RHEL8_2.0.2.zip",
|
||||
"version": "v2.0.2",
|
||||
"updated": "15/04/2026",
|
||||
"os_version_label": "8",
|
||||
"source_path": "tools/Hardenning_RHEL8_2.0.2.zip"
|
||||
}
|
||||
}
|
||||
},
|
||||
"oracle": {
|
||||
"icon": "🔸",
|
||||
"display_name": "Oracle Linux",
|
||||
"versions": {
|
||||
"oracle_default": {
|
||||
"name": "Oracle Linux Audit Script",
|
||||
"file": "oracle_linux_audit_v2.py",
|
||||
"version": "v2.0.0",
|
||||
"updated": "15/01/2026",
|
||||
"os_version_label": "",
|
||||
"source_path": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
"icon": "🪟",
|
||||
"display_name": "Windows Server",
|
||||
"versions": {
|
||||
"windows_default": {
|
||||
"name": "Windows Server Audit Script",
|
||||
"file": "windows_audit.ps1",
|
||||
"version": "v1.5.0",
|
||||
"updated": "20/12/2025",
|
||||
"os_version_label": "",
|
||||
"source_path": null
|
||||
},
|
||||
"windows_windows_server": {
|
||||
"name": "Windows Server Audit Script",
|
||||
"file": "hardening_windows.zip",
|
||||
"version": "v1",
|
||||
"updated": "08/04/2026",
|
||||
"os_version_label": "Windows Server",
|
||||
"source_path": "tools/hardening_windows.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import re, json, sys, io
|
||||
from openpyxl import load_workbook
|
||||
from unidecode import unidecode
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
ps = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
|
||||
# 1. Static checks
|
||||
static_checks = re.findall(r'Write-CheckResult\s+"([^$"].+?)"\s+"(.+?)"', ps)
|
||||
criteria = [(cid, desc) for cid, desc in static_checks]
|
||||
print(f'Static checks: {len(criteria)}')
|
||||
|
||||
# 2. Variable-based checks - expand from function calls
|
||||
# Test-FirewallProfile
|
||||
fw_calls = re.findall(r'Test-FirewallProfile\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for profile, prefix, label in fw_calls:
|
||||
criteria.append((f'{prefix}.1', f"Thiet lap trang thai 'Windows Firewall: {label} : Firewall state'"))
|
||||
criteria.append((f'{prefix}.2', f"Thiet lap trang thai 'Windows Firewall: {label} : Inbound connections'"))
|
||||
criteria.append((f'{prefix}.3', f"Thiet lap trang thai 'Windows Firewall: {label} : Outbound connections'"))
|
||||
|
||||
# Test-EventLogPolicy
|
||||
log_calls = re.findall(r'Test-EventLogPolicy\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for logname, prefix, label in log_calls:
|
||||
criteria.append((f'{prefix}.1', f"Thiet lap chinh sach '{label} : Control Event Log behavior when the log file reaches its maximum size'"))
|
||||
criteria.append((f'{prefix}.2', f"Thiet lap chinh sach '{label} : Specify the maximum log file size (KB)'"))
|
||||
|
||||
print(f'Total after expanding: {len(criteria)}')
|
||||
|
||||
# Build lookup: normalized_full_text -> full_text
|
||||
ps_criteria = {}
|
||||
for cid, desc in criteria:
|
||||
full = f"{cid}. {desc}"
|
||||
key = unidecode(full)
|
||||
ps_criteria[key] = full
|
||||
|
||||
# Load Excel
|
||||
wb = load_workbook(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\Windows_Checklist.xlsx')
|
||||
ws = wb.worksheets[0]
|
||||
|
||||
excel_rows = {}
|
||||
unmatched = {}
|
||||
|
||||
# Pass 1: match by full text (column B has the full criteria text)
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
combined = f"{val_a} {val_b}".strip()
|
||||
norm = unidecode(combined)
|
||||
if norm in ps_criteria:
|
||||
excel_rows[row] = ps_criteria[norm]
|
||||
del ps_criteria[norm]
|
||||
|
||||
# Pass 2: match just the CheckId in column A
|
||||
still_unmatched = dict(ps_criteria)
|
||||
for cid_key, full_text in still_unmatched.items():
|
||||
cid = full_text.split('. ')[0] if '. ' in full_text else full_text.split()[0]
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
if val_a and cid in val_a and row not in excel_rows:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
# Pass 3: try matching by normalized column B only
|
||||
still_unmatched2 = dict(ps_criteria)
|
||||
for cid_key, full_text in still_unmatched2.items():
|
||||
cid = full_text.split('. ')[0]
|
||||
norm_cid = unidecode(cid)
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
if val_b:
|
||||
norm_b = unidecode(val_b)
|
||||
if norm_cid in norm_b.split()[0] and row not in excel_rows:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
print(f'\nMatched rows: {len(excel_rows)}')
|
||||
print(f'Unmatched: {len(ps_criteria)}')
|
||||
|
||||
if ps_criteria:
|
||||
print('\nUnmatched criteria (first 10):')
|
||||
for i, (k, v) in enumerate(list(ps_criteria.items())[:10]):
|
||||
print(f' [{v[:70]}]')
|
||||
|
||||
# Build new config
|
||||
new_data = []
|
||||
for row in sorted(excel_rows.keys()):
|
||||
new_data.append({str(row): excel_rows[row]})
|
||||
|
||||
new_config = {"data": new_data}
|
||||
|
||||
output_path = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\windows_config.json'
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(new_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f'\nNew config written to: {output_path}')
|
||||
print(f'Total entries: {len(new_data)}')
|
||||
@@ -0,0 +1,150 @@
|
||||
import re, json, sys, io
|
||||
from openpyxl import load_workbook
|
||||
from unidecode import unidecode
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
ps = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
|
||||
# Strategy: find ALL lines with Write-CheckResult, regardless of conditional context
|
||||
# Also handle the case where IsDomain branches produce different descriptions
|
||||
|
||||
all_checks = []
|
||||
|
||||
# Find all Write-CheckResult calls - including those inside conditionals
|
||||
for m in re.finditer(r'Write-CheckResult\s+"([^"]+)"\s+"([^"]+)"', ps):
|
||||
check_id = m.group(1)
|
||||
desc = m.group(2)
|
||||
if not check_id.startswith('$'):
|
||||
all_checks.append((check_id, desc))
|
||||
|
||||
print(f'Direct calls (no variables): {len(all_checks)}')
|
||||
|
||||
# Now expand variable-based calls from Test-FirewallProfile and Test-EventLogPolicy
|
||||
fw_calls = re.findall(r'Test-FirewallProfile\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for profile, prefix, label in fw_calls:
|
||||
all_checks.append((f'{prefix}.1', f"Thiet lap trang thai 'Windows Firewall: {label} : Firewall state'"))
|
||||
all_checks.append((f'{prefix}.2', f"Thiet lap trang thai 'Windows Firewall: {label} : Inbound connections'"))
|
||||
all_checks.append((f'{prefix}.3', f"Thiet lap trang thai 'Windows Firewall: {label} : Outbound connections'"))
|
||||
|
||||
log_calls = re.findall(r'Test-EventLogPolicy\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for logname, prefix, label in log_calls:
|
||||
all_checks.append((f'{prefix}.1', f"Thiet lap chinh sach '{label} : Control Event Log behavior when the log file reaches its maximum size'"))
|
||||
all_checks.append((f'{prefix}.2', f"Thiet lap chinh sach '{label} : Specify the maximum log file size (KB)'"))
|
||||
|
||||
# Build criteria list, removing duplicates (same CheckId + same Description)
|
||||
seen = set()
|
||||
criteria_unique = []
|
||||
for cid, desc in all_checks:
|
||||
key = (cid, desc)
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
criteria_unique.append((cid, desc))
|
||||
|
||||
criteria = criteria_unique
|
||||
print(f'Total unique criteria: {len(criteria)}')
|
||||
|
||||
# Build ps_criteria lookup
|
||||
ps_criteria = {}
|
||||
for cid, desc in criteria:
|
||||
full = f"{cid}. {desc}"
|
||||
key = unidecode(full)
|
||||
ps_criteria[key] = full
|
||||
|
||||
# Load Excel
|
||||
wb = load_workbook(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\Windows_Checklist.xlsx')
|
||||
ws = wb.worksheets[0]
|
||||
|
||||
excel_rows = {}
|
||||
|
||||
# Pass 1: match by full unidecoded text
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
combined = f"{val_a} {val_b}".strip()
|
||||
norm = unidecode(combined)
|
||||
if norm in ps_criteria:
|
||||
excel_rows[row] = ps_criteria[norm]
|
||||
del ps_criteria[norm]
|
||||
|
||||
# Pass 2: match by CheckId prefix
|
||||
still = dict(ps_criteria)
|
||||
for cid_key, full_text in still.items():
|
||||
cid = full_text.split('. ')[0]
|
||||
for row in range(1, ws.max_row + 1):
|
||||
if row in excel_rows:
|
||||
continue
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
if val_a and cid in val_a:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
# Pass 3: match column B alone
|
||||
still2 = dict(ps_criteria)
|
||||
for cid_key, full_text in still2.items():
|
||||
cid = full_text.split('. ')[0]
|
||||
for row in range(1, ws.max_row + 1):
|
||||
if row in excel_rows:
|
||||
continue
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
if val_b:
|
||||
norm_b = unidecode(val_b)
|
||||
parts = norm_b.split()
|
||||
if parts and cid in parts[0]:
|
||||
excel_rows[row] = full_text
|
||||
del ps_criteria[cid_key]
|
||||
break
|
||||
|
||||
print(f'\nMatched rows: {len(excel_rows)}')
|
||||
print(f'Unmatched: {len(ps_criteria)}')
|
||||
|
||||
if ps_criteria:
|
||||
print('\nUnmatched check IDs:')
|
||||
for k in sorted(ps_criteria.keys()):
|
||||
cid = ps_criteria[k].split('. ')[0]
|
||||
print(f' {cid}: {ps_criteria[k][:80]}')
|
||||
|
||||
# Build new config
|
||||
new_data = []
|
||||
for row in sorted(excel_rows.keys()):
|
||||
new_data.append({str(row): excel_rows[row]})
|
||||
|
||||
new_config = {"data": new_data}
|
||||
|
||||
output_path = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\windows_config.json'
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(new_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f'\nNew config: {output_path}')
|
||||
print(f'Total entries: {len(new_data)}')
|
||||
|
||||
# Verify against actual output
|
||||
out_file = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\output\MEVAS-NTL-DATAN_2026_07_29-05_18_36.txt'
|
||||
with open(out_file, 'r', encoding='utf-8', errors='replace') as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
audit_results = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.startswith('{') and line.endswith('}'):
|
||||
try:
|
||||
parsed = json.loads(line)
|
||||
key = unidecode(str(list(parsed.keys())[0]))
|
||||
audit_results[key] = (str(list(parsed.values())[0]), line)
|
||||
except:
|
||||
pass
|
||||
|
||||
cfg_names = {unidecode(str(list(item.values())[0])) for item in new_config['data']}
|
||||
output_names = set(audit_results.keys())
|
||||
|
||||
matched = cfg_names & output_names
|
||||
output_only = output_names - cfg_names
|
||||
|
||||
print(f'Output lines: {len(output_names)}')
|
||||
print(f'Config matches output: {len(matched)}/{len(output_names)}')
|
||||
print(f'Output not in config: {len(output_only)}')
|
||||
if output_only:
|
||||
print('Missing from config:')
|
||||
for n in sorted(list(output_only))[:5]:
|
||||
print(f' {n[:80]}')
|
||||
@@ -0,0 +1,149 @@
|
||||
import re, json, sys, io
|
||||
from openpyxl import load_workbook
|
||||
from unidecode import unidecode
|
||||
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
ps = open(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\audit_check_script\audit_cis_windows.ps1', 'r', encoding='utf-8').read()
|
||||
|
||||
# Collect ALL criteria including DC/MS variants
|
||||
all_criteria = []
|
||||
|
||||
# Direct Write-CheckResult calls
|
||||
for m in re.finditer(r'Write-CheckResult\s+"([^"]+)"\s+"([^"]+)"', ps):
|
||||
check_id = m.group(1)
|
||||
desc = m.group(2)
|
||||
if not check_id.startswith('$'):
|
||||
all_criteria.append((check_id, desc))
|
||||
|
||||
# Expand variable-based calls
|
||||
fw_calls = re.findall(r'Test-FirewallProfile\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for profile, prefix, label in fw_calls:
|
||||
all_criteria.append((f'{prefix}.1', f"Thiet lap trang thai 'Windows Firewall: {label} : Firewall state'"))
|
||||
all_criteria.append((f'{prefix}.2', f"Thiet lap trang thai 'Windows Firewall: {label} : Inbound connections'"))
|
||||
all_criteria.append((f'{prefix}.3', f"Thiet lap trang thai 'Windows Firewall: {label} : Outbound connections'"))
|
||||
|
||||
log_calls = re.findall(r'Test-EventLogPolicy\s+"(\w+)"\s+"([\d.]+)"\s+"(\w+)"', ps)
|
||||
for logname, prefix, label in log_calls:
|
||||
all_criteria.append((f'{prefix}.1', f"Thiet lap chinh sach '{label} : Control Event Log behavior when the log file reaches its maximum size'"))
|
||||
all_criteria.append((f'{prefix}.2', f"Thiet lap chinh sach '{label} : Specify the maximum log file size (KB)'"))
|
||||
|
||||
# Build full criteria names, keep duplicates (DC vs MS variants)
|
||||
criteria_list = []
|
||||
seen = set()
|
||||
for cid, desc in all_criteria:
|
||||
full = f"{cid}. {desc}"
|
||||
key = (cid, unidecode(desc))
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
criteria_list.append((cid, desc, full))
|
||||
|
||||
print(f'Total criteria (with variants): {len(criteria_list)}')
|
||||
|
||||
# Load Excel
|
||||
wb = load_workbook(r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\Windows_Checklist.xlsx')
|
||||
ws = wb.worksheets[0]
|
||||
|
||||
# Build Excel row mapping: try to find the best row for each criteria
|
||||
# A row can have multiple criteria (DC + MS variants)
|
||||
row_to_criteria = {} # row -> list of criteria full text
|
||||
|
||||
unmatched = list(criteria_list)
|
||||
|
||||
# Pass 1: match by full text
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
combined = f"{val_a} {val_b}".strip()
|
||||
norm = unidecode(combined)
|
||||
|
||||
for cid, desc, full in list(unmatched):
|
||||
if unidecode(full) == norm:
|
||||
if row not in row_to_criteria:
|
||||
row_to_criteria[row] = []
|
||||
row_to_criteria[row].append(full)
|
||||
unmatched.remove((cid, desc, full))
|
||||
|
||||
# Pass 2: match by CheckId in column A
|
||||
for cid, desc, full in list(unmatched):
|
||||
for row in range(1, ws.max_row + 1):
|
||||
val_a = str(ws.cell(row=row, column=1).value or "").strip()
|
||||
if val_a and cid in val_a:
|
||||
if row not in row_to_criteria:
|
||||
row_to_criteria[row] = []
|
||||
if full not in row_to_criteria[row]:
|
||||
row_to_criteria[row].append(full)
|
||||
unmatched.remove((cid, desc, full))
|
||||
break
|
||||
|
||||
# Pass 3: match by CheckId in column B
|
||||
for cid, desc, full in list(unmatched):
|
||||
for row in range(1, ws.max_row + 1):
|
||||
if row in row_to_criteria:
|
||||
continue
|
||||
val_b = str(ws.cell(row=row, column=2).value or "").strip()
|
||||
if val_b:
|
||||
norm_b = unidecode(val_b)
|
||||
parts = norm_b.split()
|
||||
if parts and cid == parts[0].rstrip('.'):
|
||||
if row not in row_to_criteria:
|
||||
row_to_criteria[row] = []
|
||||
if full not in row_to_criteria[row]:
|
||||
row_to_criteria[row].append(full)
|
||||
unmatched.remove((cid, desc, full))
|
||||
break
|
||||
|
||||
print(f'\nMatched rows: {len(row_to_criteria)}')
|
||||
print(f'Unmatched criteria: {len(unmatched)}')
|
||||
|
||||
if unmatched:
|
||||
print('\nUnmatched:')
|
||||
for cid, desc, full in unmatched[:10]:
|
||||
print(f' {cid}: {full[:80]}')
|
||||
|
||||
# Build new config
|
||||
new_data = []
|
||||
for row in sorted(row_to_criteria.keys()):
|
||||
for full_text in row_to_criteria[row]:
|
||||
new_data.append({str(row): full_text})
|
||||
|
||||
new_config = {"data": new_data}
|
||||
|
||||
output_path = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\config\windows_config.json'
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(new_config, f, ensure_ascii=False, indent=4)
|
||||
|
||||
print(f'\nNew config: {output_path}')
|
||||
print(f'Total entries: {len(new_data)}')
|
||||
|
||||
# Verify against actual output
|
||||
out_file = r'D:\VNPT-M\Tool\audit_tool\NEW\Update\audit_lhdsin\output\MEVAS-NTL-DATAN_2026_07_29-05_18_36.txt'
|
||||
with open(out_file, 'r', encoding='utf-8', errors='replace') as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
audit_results = {}
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.startswith('{') and line.endswith('}'):
|
||||
try:
|
||||
parsed = json.loads(line)
|
||||
key = unidecode(str(list(parsed.keys())[0]))
|
||||
audit_results[key] = (str(list(parsed.values())[0]), line)
|
||||
except:
|
||||
pass
|
||||
|
||||
cfg_names = set()
|
||||
for item in new_config['data']:
|
||||
cfg_names.add(unidecode(str(list(item.values())[0])))
|
||||
|
||||
output_names = set(audit_results.keys())
|
||||
matched = cfg_names & output_names
|
||||
output_only = output_names - cfg_names
|
||||
|
||||
print(f'Output lines: {len(output_names)}')
|
||||
print(f'Matched: {len(matched)}/{len(output_names)}')
|
||||
print(f'Not in config: {len(output_only)}')
|
||||
if output_only:
|
||||
print('Still missing (first 5):')
|
||||
for n in sorted(list(output_only))[:5]:
|
||||
print(f' {n[:80]}')
|
||||
Reference in New Issue
Block a user