This commit is contained in:
Luftmensch
2026-08-26 14:11:37 +07:00
commit e528419f9a
135 changed files with 413970 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
# Python cache
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
# Conda environment
.conda/
# Virtual Environment
.venv/
venv/
ENV/
env/
# IDE
.vscode/
.idea/
*.swp
*.swo
.gemini/
# Git
.git/
.gitignore
# Documentation (not needed in container)
Documentation/
*.md
FILES_LIST.txt
# Test and utility scripts (not needed in container)
test_*.py
check_*.py
quick_test.py
# GUI-only files (not needed for web deployment)
decrypt_file.py
web_app.py
ImaP.ui
*.exe
# Shell/Batch scripts (not needed in container, except entrypoint)
*.bat
*.ps1
!docker-entrypoint.sh
!docker-service.sh
# Caddy/Proxy configs (not using)
Caddyfile*
nginx.conf*
docker-compose.*.yml
# Logs
*.log
# OS files
.DS_Store
Thumbs.db
# Data files (mounted as volumes, not baked into image)
uploads/
output/
# Config files (mounted as volumes at runtime)
config/
keys/
users_config.json
radius_config.json
email_config.json
email_config_api.json
# Standalone scripts not imported by web app
api_client.py
send_mail.py
# Model diagram
audit_portal_model.png
+60
View File
@@ -0,0 +1,60 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual Environment
.venv/
venv/
ENV/
env/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Sensitive Configuration Files
radius_config.json
users_config.json
keys/private_key.pem
# Uploads and Outputs
uploads/*.enc
uploads/*.txt
output/*.xlsx
output/*.txt
# OS
.DS_Store
Thumbs.db
# Logs
*.log
# Docker
.docker/
# Backups
backups/
email_config.json
email_config_api.json
+3
View File
@@ -0,0 +1,3 @@
# DUNGLH-ANTT Key by Termius
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAJ7ycGKJZb08QexTGDM6wki0ZzWeSvWG2LEMUZPTFs+ Generated By Termius Dunglh-ANTT
+44
View File
@@ -0,0 +1,44 @@
# Dockerfile for Audit Hardening Tool - Web Deployment
# Optimized for offline deployment (export/load workflow)
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
TZ=Asia/Ho_Chi_Minh
# Install minimal system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# Copy requirements first for better Docker layer caching
COPY requirements.docker.txt ./requirements.txt
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Create necessary data directories (mount points)
RUN mkdir -p uploads output config keys tools docs
# Copy entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Expose port
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/', timeout=5)" || exit 1
# Set entrypoint
ENTRYPOINT ["docker-entrypoint.sh"]
# Run the application with proxy headers support
CMD ["uvicorn","web_app_fastapi:app","--host","0.0.0.0","--port","8000","--proxy-headers","--forwarded-allow-ips","*","--root-path","/audit"]
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+593
View File
@@ -0,0 +1,593 @@
import base64
import datetime
import json
import os
import time
from os import mkdir
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
from Crypto.Cipher import PKCS1_OAEP, AES
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import unpad
from colorama import Fore
from colorama import init
from openpyxl import load_workbook
from tqdm import tqdm
from unidecode import unidecode
init()
current = datetime.datetime.now()
try:
os.mkdir("output")
except FileExistsError:
pass
def extract_system_info(lines):
"""Extract system information from decrypted file content."""
system_info = {
'script_version': '',
'os_name': '',
'kernel_version': '',
'architecture': '',
'hostname': '',
'fqdn': '',
'ip_address': '',
'all_ips': '',
'audit_time': '',
'timezone': '',
'uptime': '',
'cpu_model': '',
'cpu_cores': '',
'total_memory': '',
'used_memory': '',
'free_memory': '',
'swap_total': '',
'primary_interface': '',
'mac_address': '',
'default_gateway': '',
'dns_servers': '',
'selinux_status': '',
'firewall_status': '',
'last_boot': '',
'current_users': '',
'load_average': '',
# Compliance statistics
'passed_count': 0,
'failed_count': 0,
'total_checks': 0,
'compliance_percentage': 0.0,
# Mandatory/Optional statistics
'mandatory_passed': 0,
'mandatory_failed': 0,
'mandatory_total': 0,
'mandatory_percentage': 0.0,
'optional_passed': 0,
'optional_failed': 0,
'optional_total': 0,
'optional_percentage': 0.0
}
passed_count = 0
failed_count = 0
for line in lines:
line_stripped = line.strip()
# Count PASSED and FAILED checks from JSON format lines
if line_stripped.startswith('{') and line_stripped.endswith('}'):
if '"PASSED"' in line_stripped:
passed_count += 1
elif '"FAILED"' in line_stripped:
failed_count += 1
# Parse system information
if line_stripped.startswith('Script Version:'):
system_info['script_version'] = line_stripped.replace('Script Version:', '').strip()
elif line_stripped.startswith('Operating System:'):
system_info['os_name'] = line_stripped.replace('Operating System:', '').strip()
elif line_stripped.startswith('Kernel Version:'):
system_info['kernel_version'] = line_stripped.replace('Kernel Version:', '').strip()
elif line_stripped.startswith('Architecture:'):
system_info['architecture'] = line_stripped.replace('Architecture:', '').strip()
elif line_stripped.startswith('Hostname:'):
system_info['hostname'] = line_stripped.replace('Hostname:', '').strip()
elif line_stripped.startswith('FQDN:'):
system_info['fqdn'] = line_stripped.replace('FQDN:', '').strip()
elif line_stripped.startswith('IP Address:'):
system_info['ip_address'] = line_stripped.replace('IP Address:', '').strip()
elif line_stripped.startswith('All IP Addresses:'):
system_info['all_ips'] = line_stripped.replace('All IP Addresses:', '').strip()
elif line_stripped.startswith('Audit Time:'):
system_info['audit_time'] = line_stripped.replace('Audit Time:', '').strip()
elif line_stripped.startswith('Timezone:'):
system_info['timezone'] = line_stripped.replace('Timezone:', '').strip()
elif line_stripped.startswith('Uptime:'):
system_info['uptime'] = line_stripped.replace('Uptime:', '').strip()
elif line_stripped.startswith('CPU Model:'):
system_info['cpu_model'] = line_stripped.replace('CPU Model:', '').strip()
elif line_stripped.startswith('CPU Cores:'):
system_info['cpu_cores'] = line_stripped.replace('CPU Cores:', '').strip()
elif line_stripped.startswith('Total Memory:'):
system_info['total_memory'] = line_stripped.replace('Total Memory:', '').strip()
elif line_stripped.startswith('Used Memory:'):
system_info['used_memory'] = line_stripped.replace('Used Memory:', '').strip()
elif line_stripped.startswith('Free Memory:'):
system_info['free_memory'] = line_stripped.replace('Free Memory:', '').strip()
elif line_stripped.startswith('Swap Total:'):
system_info['swap_total'] = line_stripped.replace('Swap Total:', '').strip()
elif line_stripped.startswith('Primary Interface:'):
system_info['primary_interface'] = line_stripped.replace('Primary Interface:', '').strip()
elif line_stripped.startswith('MAC Address:'):
system_info['mac_address'] = line_stripped.replace('MAC Address:', '').strip()
elif line_stripped.startswith('Default Gateway:'):
system_info['default_gateway'] = line_stripped.replace('Default Gateway:', '').strip()
elif line_stripped.startswith('DNS Servers:'):
system_info['dns_servers'] = line_stripped.replace('DNS Servers:', '').strip()
elif line_stripped.startswith('SELinux Status:'):
system_info['selinux_status'] = line_stripped.replace('SELinux Status:', '').strip()
elif line_stripped.startswith('Firewall:'):
system_info['firewall_status'] = line_stripped.replace('Firewall:', '').strip()
elif line_stripped.startswith('Last Boot:'):
system_info['last_boot'] = line_stripped.replace('Last Boot:', '').strip()
elif line_stripped.startswith('Current Users:'):
system_info['current_users'] = line_stripped.replace('Current Users:', '').strip()
elif line_stripped.startswith('Load Average:'):
system_info['load_average'] = line_stripped.replace('Load Average:', '').strip()
# Calculate compliance statistics
total_checks = passed_count + failed_count
system_info['passed_count'] = passed_count
system_info['failed_count'] = failed_count
system_info['total_checks'] = total_checks
if total_checks > 0:
system_info['compliance_percentage'] = round((passed_count / total_checks) * 100, 1)
else:
system_info['compliance_percentage'] = 0.0
return system_info
def detect_os_from_content(lines):
"""
Detect OS type from decrypted file content.
Reads the 'Operating System:' field and maps it to an OS key.
Returns the OS key (centos, ubuntu, rhel, oracle, windows) or None if not detected.
Example values:
'CentOS Linux 7 (Core)' -> 'centos'
'Red Hat Enterprise ...' -> 'rhel'
'Ubuntu 20.04.x LTS' -> 'ubuntu'
'Oracle Linux 8.x' -> 'oracle'
'Windows Server 2019' -> 'windows'
"""
os_name_raw = None
for line in lines:
stripped = line.strip()
if stripped.startswith('Operating System:'):
os_name_raw = stripped.replace('Operating System:', '').strip()
break
if not os_name_raw:
return None
os_lower = os_name_raw.lower()
# Order matters: more specific patterns first
if 'centos' in os_lower:
detected = 'centos'
elif 'red hat' in os_lower or 'redhat' in os_lower or 'rhel' in os_lower:
detected = 'rhel'
elif 'ubuntu' in os_lower:
detected = 'ubuntu'
elif 'oracle' in os_lower:
# Check if version is < 8
# Hỗ trợ cả 'Oracle Linux Server release 7.9' và 'Oracle Linux Server 7.9'
import re
version_match = re.search(r'(?:release\s+|server\s+|linux\s+)(\d+)', os_lower)
if not version_match:
# Fallback: tìm số version đầu tiên trong chuỗi (ví dụ 'oracle linux 7.9')
version_match = re.search(r'(\d+)\.', os_lower)
if version_match and int(version_match.group(1)) < 8:
print(Fore.YELLOW + f"[CONTENT-DETECT] Oracle Linux < 8 detected (version {version_match.group(1)}). Routing to CentOS config." + Fore.RESET)
detected = 'centos'
else:
detected = 'oracle'
elif 'windows' in os_lower:
detected = 'windows'
else:
detected = None
if detected:
print(Fore.CYAN + f"[CONTENT-DETECT] 'Operating System: {os_name_raw}' → OS key: '{detected}'" + Fore.RESET)
else:
print(Fore.YELLOW + f"[CONTENT-DETECT] Unknown OS from content: '{os_name_raw}'" + Fore.RESET)
return detected
_cached_private_key = None
def get_private_key():
"""Lấy hoặc nạp RSA private key từ cache trong RAM."""
global _cached_private_key
if _cached_private_key is not None:
return _cached_private_key
script_dir = os.path.dirname(os.path.abspath(__file__))
private_key_paths = [
'private_key.pem',
'../private_key.pem',
os.path.join(script_dir, 'private_key.pem'),
os.path.join(script_dir, 'keys', 'private_key.pem'),
'keys/private_key.pem'
]
for path in private_key_paths:
if os.path.exists(path):
with open(path, 'rb') as f:
_cached_private_key = RSA.import_key(f.read())
return _cached_private_key
raise FileNotFoundError("private_key.pem not found! Please ensure it exists in the script directory.")
def _decrypt_rsa_block_worker(block: bytes) -> bytes:
"""Hàm worker cấp module phục vụ cho ProcessPoolExecutor / ThreadPoolExecutor giải mã RSA."""
private_key = get_private_key()
cipher = PKCS1_OAEP.new(private_key)
return cipher.decrypt(block)
def is_hybrid_encrypted(raw_text: str) -> bool:
"""Kiểm tra xem nội dung file có thuộc chuẩn mã hóa lai MỚI (HYBRID AES-256 + RSA) hay không."""
s = raw_text.strip()
return s.startswith("HYBRID_V1:") or s.startswith("HYBRID_AES:") or s.startswith("HYBRID:")
def decrypt_hybrid(raw_text: str) -> bytes:
"""
Giải mã định dạng Mã hóa Lai (Hybrid AES-256 + RSA) siêu tốc (~0.005s).
Cấu trúc:
HYBRID_V1:<b64_enc_key>:<b64_iv>:<b64_ciphertext>
hoặc JSON:
HYBRID_V1:{"enc_key": "...", "iv": "...", "data": "..."}
"""
s = raw_text.strip()
# Loại bỏ tiền tố prefix
for prefix in ("HYBRID_V1:", "HYBRID_AES:", "HYBRID:"):
if s.startswith(prefix):
payload = s[len(prefix):].strip()
break
b64_enc_key = ""
b64_iv = ""
b64_ciphertext = ""
if payload.startswith("{"):
# Format JSON
data_json = json.loads(payload)
b64_enc_key = data_json.get("enc_key", "")
b64_iv = data_json.get("iv", "")
b64_ciphertext = data_json.get("data", "")
else:
# Format chuỗi phân cách bởi dấu hai chấm ':'
parts = payload.split(":")
if len(parts) >= 3:
b64_enc_key = parts[0]
b64_iv = parts[1]
b64_ciphertext = parts[2]
if not b64_enc_key or not b64_iv or not b64_ciphertext:
raise ValueError("Cấu trúc file Mã hóa Lai (Hybrid Encryption) không hợp lệ!")
enc_key = base64.b64decode(b64_enc_key)
iv = base64.b64decode(b64_iv)
ciphertext = base64.b64decode(b64_ciphertext)
# 1. Giải mã khóa AES bằng RSA Private Key (chỉ 1 block RSA duy nhất)
private_key = get_private_key()
cipher_rsa = PKCS1_OAEP.new(private_key)
aes_key = cipher_rsa.decrypt(enc_key)
# 2. Giải mã dữ liệu bằng khóa AES-256-CBC (siêu nhanh)
cipher_aes = AES.new(aes_key, AES.MODE_CBC, iv)
decrypted_padded = cipher_aes.decrypt(ciphertext)
# Thử gỡ padding PKCS7
try:
plaintext_bytes = unpad(decrypted_padded, AES.block_size)
except ValueError:
plaintext_bytes = decrypted_padded
return plaintext_bytes
def decryption_read_header(filename: str, max_blocks: int = 30) -> list[str]:
"""
Giải mã nhanh phần header của file .enc để đọc thông tin OS.
Tự động hỗ trợ cả chuẩn MỚI (Hybrid AES+RSA) và chuẩn CŨ (Pure RSA).
"""
with open(filename, "r", encoding="utf-8", errors="replace") as f:
raw_text = f.read()
if is_hybrid_encrypted(raw_text):
# Format MỚI: Giải mã siêu tốc bằng AES-256 + RSA (< 0.005s)
plaintext_bytes = decrypt_hybrid(raw_text)
lines = plaintext_bytes.decode("utf-8", errors="replace").splitlines()
return lines[:100]
# Format CŨ: Giải mã N block RSA đầu tiên (~5KB)
ciphertext = base64.b64decode(raw_text.encode('utf-8'))
private_key = get_private_key()
block_size = private_key.size_in_bytes()
cipher = PKCS1_OAEP.new(private_key)
total_blocks = (len(ciphertext) + block_size - 1) // block_size
num_blocks = min(max_blocks, total_blocks)
blocks = []
for i in range(num_blocks):
offset = i * block_size
block = ciphertext[offset:offset + block_size]
try:
blocks.append(cipher.decrypt(block))
except Exception:
break
header_text = b"".join(blocks).decode('utf-8', errors='replace')
return header_text.splitlines()
def decryption_write(filename):
"""
Giải mã toàn bộ file mã hóa.
Tự động chuyển đổi giữa chuẩn MỚI (Hybrid AES-256 + RSA) và chuẩn CŨ (Pure RSA Multi-processing).
"""
with open(filename, "r", encoding="utf-8", errors="replace") as f:
raw_text = f.read()
start_time = time.time()
if is_hybrid_encrypted(raw_text):
# ⚡ Chuẩn MỚI (Hybrid AES-256 + RSA): Tốc độ tức thì < 0.01 giây
plaintext_bytes = decrypt_hybrid(raw_text)
plaintext = plaintext_bytes.decode("utf-8", errors="replace")
print(Fore.GREEN + f" [HYBRID AES+RSA] Decryption done in {time.time() - start_time:.3f}s" + Fore.RESET)
else:
# 🐢 Chuẩn CŨ (Pure RSA): Giải mã đa luồng / đa tiến trình tối ưu CPU Multi-core
ciphertext = base64.b64decode(raw_text.encode('utf-8'))
private_key = get_private_key()
block_size = private_key.size_in_bytes()
total_blocks = (len(ciphertext) + block_size - 1) // block_size
block_list = [ciphertext[i * block_size:(i + 1) * block_size] for i in range(total_blocks)]
max_workers = min(16, (os.cpu_count() or 4) * 2)
try:
with ThreadPoolExecutor(max_workers=max_workers) as executor:
decrypted_blocks = list(executor.map(_decrypt_rsa_block_worker, block_list))
except Exception:
cipher = PKCS1_OAEP.new(private_key)
decrypted_blocks = [cipher.decrypt(b) for b in block_list]
plaintext = b"".join(decrypted_blocks).decode('utf-8', errors='replace')
print(Fore.GREEN + f" [LEGACY RSA] Decryption done in {time.time() - start_time:.1f}s ({total_blocks} blocks, {max_workers} workers)" + Fore.RESET)
output_path = os.path.basename(filename).replace(".enc", "")
with open(output_path, 'w', encoding="utf-8") as f:
f.write(plaintext)
def check_file_exist(filename):
isFile = os.path.isfile(filename)
if isFile:
return True
else:
return False
def string_normalization(string):
return unidecode(str(string))
def extract_failed_logs(lines):
"""Extract detailed log blocks for each FAILED criteria from decrypted log lines.
Returns a dict mapping normalized criteria name -> log detail text.
"""
failed_logs = {}
i = 0
separator = '######################################'
dash_separator = '-------------------'
stderr_begin = '########## STDERR BEGIN ##########'
stderr_end = '########## STDERR END ##########'
while i < len(lines):
line_stripped = lines[i].strip()
# Look for FAILED JSON lines
if line_stripped.startswith('{') and line_stripped.endswith('}') and '"FAILED"' in line_stripped:
try:
parsed = json.loads(line_stripped)
criteria_name = str(list(parsed.keys())[0])
normalized_name = string_normalization(criteria_name)
# Collect all lines after this FAILED line until the next JSON criteria line
log_lines = []
j = i + 1
while j < len(lines):
next_line = lines[j].strip()
# Stop when we hit the next JSON criteria line (PASSED or FAILED)
if next_line.startswith('{') and next_line.endswith('}'):
try:
next_parsed = json.loads(next_line)
next_val = str(list(next_parsed.values())[0])
if next_val in ('PASSED', 'FAILED'):
break
except (json.JSONDecodeError, IndexError):
pass
# Skip separator lines and STDERR markers
if next_line == separator or next_line == dash_separator:
j += 1
continue
if next_line == stderr_begin or next_line == stderr_end:
j += 1
continue
# Skip empty lines at the beginning
if not log_lines and not next_line:
j += 1
continue
log_lines.append(lines[j].rstrip())
j += 1
# Remove trailing empty lines
while log_lines and not log_lines[-1].strip():
log_lines.pop()
if log_lines:
log_text = '\n'.join(log_lines)
# Excel cell limit is 32767 characters
if len(log_text) > 32767:
log_text = log_text[:32764] + '...'
failed_logs[normalized_name] = log_text
i = j # Skip to where we stopped
continue
except (json.JSONDecodeError, IndexError):
pass
i += 1
return failed_logs
def run_report(checklist_file, config_file, file_input):
with open(file_input, "r", encoding="utf8") as file:
line = file.read().splitlines()
wb = load_workbook(filename=checklist_file)
ws = wb.worksheets[0]
with open(config_file, 'r', encoding="utf8") as j:
contents = json.loads(j.read())
index_audit = contents['data']
mandatory_rows = set()
for row_idx in range(1, ws.max_row + 1):
cell_val = ws.cell(row=row_idx, column=5).value
if cell_val and str(cell_val).strip().lower() == 'x':
mandatory_rows.add(row_idx)
mandatory_passed = 0
mandatory_failed = 0
optional_passed = 0
optional_failed = 0
failed_logs = extract_failed_logs(line)
audit_results = {}
for one_audit in line:
try:
parsed_data = json.loads(one_audit)
result = str(list(parsed_data.keys())[0])
value = str(list(parsed_data.values())[0])
normalized_key = string_normalization(result)
audit_results[normalized_key] = (value, one_audit)
except Exception:
continue
for audit_pattern in index_audit:
index_a = list(audit_pattern.keys())[0]
index_pattern = string_normalization(list(audit_pattern.values())[0])
entry = audit_results.get(index_pattern)
if entry is None:
continue
status, raw_line = entry
is_mandatory = int(index_a) in mandatory_rows if index_a.isdigit() else False
if "FAILED" in raw_line:
ws['D{}'.format(index_a)] = 'x'
if index_pattern in failed_logs:
ws['F{}'.format(index_a)] = failed_logs[index_pattern]
if is_mandatory:
mandatory_failed += 1
else:
optional_failed += 1
else:
ws['C{}'.format(index_a)] = 'x'
if is_mandatory:
mandatory_passed += 1
else:
optional_passed += 1
# Find hostname and time dynamically in the file
hostname = "unknown"
time_generate = "unknown"
for l in line:
if l.strip().startswith("Hostname:"):
hostname = l.replace("Hostname:", "").strip().split(" ")[0]
elif l.strip().startswith("Audit Time:"):
time_generate = l.replace("Audit Time:", "").strip().replace("-", "_").replace(":", "_").replace(" ", "-")
# Also support old format with "Time:"
elif l.strip().startswith("Time:") and time_generate == "unknown":
time_generate = l.replace("Time:", "").strip().replace("-", "_").replace(":", "_").replace(" ", "-")
# Create file name based strictly on hostname and time
file_name = f'{hostname}_{time_generate}.xlsx'
wb.save(filename=file_name)
if check_file_exist(file_name):
print(Fore.GREEN + "\nChecklist Done: {}".format(file_name) + Fore.RESET)
else:
print(Fore.RED + "Error creating Excel file!" + Fore.RESET)
# Extract and return system info
system_info = extract_system_info(line)
# Add mandatory/optional statistics
mandatory_total = mandatory_passed + mandatory_failed
optional_total = optional_passed + optional_failed
system_info['mandatory_passed'] = mandatory_passed
system_info['mandatory_failed'] = mandatory_failed
system_info['mandatory_total'] = mandatory_total
system_info['mandatory_percentage'] = round((mandatory_passed / mandatory_total) * 100, 1) if mandatory_total > 0 else 0.0
system_info['optional_passed'] = optional_passed
system_info['optional_failed'] = optional_failed
system_info['optional_total'] = optional_total
system_info['optional_percentage'] = round((optional_passed / optional_total) * 100, 1) if optional_total > 0 else 0.0
# Recalculate compliance stats based on config-matched criteria (consistent with Excel)
# extract_system_info counts ALL PASSED/FAILED lines in raw text (including criteria
# not in the checklist config), which can differ from the Excel result.
# Use the actual config-matched counts for accurate web display.
config_passed = mandatory_passed + optional_passed
config_failed = mandatory_failed + optional_failed
config_total = config_passed + config_failed
if config_total > 0:
system_info['passed_count'] = config_passed
system_info['failed_count'] = config_failed
system_info['total_checks'] = config_total
system_info['compliance_percentage'] = round((config_passed / config_total) * 100, 1)
return system_info
def run_generate_excel(checklist_file, config_file, filename):
global current
current = datetime.datetime.now()
file_decrypt = os.path.basename(filename).replace(".enc", "")
if check_file_exist(file_decrypt):
os.remove(file_decrypt)
decryption_write(filename)
else:
decryption_write(filename)
if check_file_exist(file_decrypt):
system_info = run_report(checklist_file, config_file, file_decrypt)
return system_info
return None
View File
+314
View File
@@ -0,0 +1,314 @@
"""Authentication router for login and JWT token management."""
from fastapi import APIRouter, Depends, HTTPException, status, Form
from sqlalchemy.orm import Session
from typing import Dict, Any
from .. import crud, schemas
from ..database import get_db
from ..utils import create_access_token, decode_access_token
from fastapi import Request, Query
from ..security import get_current_user, revoke_token_db, REVOKED_TOKENS, set_latest_jti
import os
from .radius_login import check_radius_login
from ..models import RevokedToken
import requests
import xml.etree.ElementTree as ET
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/login", response_model=schemas.LoginResponse)
async def login(login_req: schemas.LoginRequest, db: Session = Depends(get_db)):
# Convert env về boolean chuẩn
IS_PRODUCT = os.getenv("IS_PRODUCT", "False").lower() == "true"
# =============================
# 🚀 PRODUCT MODE (mock data)
# =============================
if IS_PRODUCT:
return {
"access_token": "test",
"token_type": "bearer",
"user": {
"id": 1,
"email": "test@gmail.com",
"fullname": "Test User",
"unit_id": 1,
"unit_name": "MEDIA",
"role_id": 1,
"role_name": "Administrator",
"status": 2,
"status_name": "active",
"created_at": "2025-12-02T14:32:10",
"updated_at": "2025-12-23T04:24:04"
}
}
# =============================
# 🧪 DEV MODE (login thật)
# =============================
user = crud.authenticate_user(db, login_req.email, login_req.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Bearer"},
)
if int(getattr(user, "status", 0) or 0) != 2:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User is not active",
headers={"WWW-Authenticate": "Bearer"},
)
user_details = crud.get_user_with_details(db, user)
token_data = {
"sub": str(user.id),
"email": user.email,
"fullname": user.fullname,
"unit_id": user.unit_id,
"status": user.status,
}
access_token = create_access_token(data=token_data)
try:
payload = decode_access_token(access_token)
jti = payload.get("jti")
if jti:
set_latest_jti(int(user.id), jti)
except Exception:
pass
return {
"access_token": access_token,
"token_type": "bearer",
"user": user_details
}
@router.post("/logout", response_model=schemas.APIResponse, dependencies=[Depends(get_current_user)])
async def logout(request: Request, db: Session = Depends(get_db)):
"""Logout endpoint: revoke current JWT token."""
auth_header = request.headers.get("Authorization")
if not auth_header:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
try:
scheme, token = auth_header.split()
if scheme.lower() != "bearer":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication scheme",
headers={"WWW-Authenticate": "Bearer"},
)
except ValueError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
revoke_token_db(db, token)
return {"message": "success", "data": {"revoked": True}}
@router.get("/validate-token", response_model=schemas.APIResponse)
async def validate_token(request: Request, db: Session = Depends(get_db)):
auth_header = request.headers.get("Authorization")
if not auth_header:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
try:
scheme, token = auth_header.split()
if scheme.lower() != "bearer":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication scheme",
headers={"WWW-Authenticate": "Bearer"},
)
except ValueError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
if token in REVOKED_TOKENS:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has been revoked",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = decode_access_token(token)
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
)
jti = payload.get("jti")
if jti and db.query(RevokedToken).filter(RevokedToken.jti == jti).first():
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has been revoked",
headers={"WWW-Authenticate": "Bearer"},
)
return {"message": "success", "data": payload}
@router.post("/login_sso", response_model=schemas.LoginResponse)
async def login_sso(
login_req: schemas.LoginSSORequest,
db: Session = Depends(get_db),
):
server = os.getenv("RADIUS_SERVER")
secret = os.getenv("RADIUS_SECRET")
port = int(os.getenv("RADIUS_PORT", 1812))
realm = os.getenv("RADIUS_REALM", "")
if not server or not secret:
raise HTTPException(status_code=500, detail="Configuration is missing")
try:
local_part = (login_req.email or "").split("@")[0]
except Exception:
local_part = login_req.email or ""
username = f"{local_part}{realm}"
radius_password = f"{login_req.password}{login_req.otp or ''}"
ok = check_radius_login(server, port, secret, username, radius_password)
if not ok:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid username or password or OTP")
user = crud.get_user_by_email(db, login_req.email)
if not user:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found. Please contact to Admin.")
if int(getattr(user, "status", 0) or 0) != 2:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User is not active",
headers={"WWW-Authenticate": "Bearer"},
)
user_details = crud.get_user_with_details(db, user)
token_data = {
"sub": str(user.id),
"email": user.email,
"fullname": user.fullname,
"unit_id": user.unit_id,
"status": user.status,
}
access_token = create_access_token(data=token_data)
try:
payload = decode_access_token(access_token)
jti = payload.get("jti")
if jti:
set_latest_jti(int(user.id), jti)
except Exception:
pass
return {
"access_token": access_token,
"token_type": "bearer",
"user": user_details,
}
@router.get("/login_sso_vnpt", response_model=schemas.LoginResponse)
async def login_sso_vnpt(
ticket: str = Query(..., description="CAS ticket"),
db: Session = Depends(get_db),
):
# ===== 1. CAS CONFIG =====
CAS_HOST = os.getenv("CAS_HOST") # vd: https://cas.vnpt.vn/cas
SERVICE_URL = os.getenv("CAS_SERVICE_URL")
if not CAS_HOST or not SERVICE_URL:
raise HTTPException(
status_code=500,
detail="CAS configuration missing",
)
# ===== 2. BUILD VALIDATE URL =====
validate_url = (
f"{CAS_HOST.rstrip('/')}/serviceValidate"
f"?ticket={ticket}&service={SERVICE_URL}"
)
print(validate_url)
# ===== 3. CALL CAS =====
try:
resp = requests.get(validate_url, timeout=5)
resp.raise_for_status()
except Exception:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="CAS validate service unavailable",
)
# ===== 4. PARSE XML =====
try:
root = ET.fromstring(resp.text)
except ET.ParseError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid CAS response",
)
namespace = {"cas": "http://www.yale.edu/tp/cas"}
user_node = root.find(".//cas:user", namespace)
if user_node is None or not user_node.text:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="CAS returned but refused to validate your identity",
)
# ===== 5. NETID → EMAIL =====
netid = user_node.text.strip()
email = f"{netid.lower()}@vnpt.vn"
# ===== 6. CHECK USER DB =====
user = crud.get_user_by_email(db, email)
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found. Please contact to Admin.",
)
if int(getattr(user, "status", 0) or 0) != 2:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User is not active",
headers={"WWW-Authenticate": "Bearer"},
)
# ===== 7. USER DETAILS =====
user_details = crud.get_user_with_details(db, user)
# ===== 8. TOKEN DATA (GIỮ NGUYÊN THEO YÊU CẦU) =====
token_data = {
"sub": str(user.id),
"email": user.email,
"fullname": user.fullname,
"unit_id": user.unit_id,
"status": user.status,
}
access_token = create_access_token(data=token_data)
try:
payload = decode_access_token(access_token)
jti = payload.get("jti")
if jti:
set_latest_jti(int(user.id), jti)
except Exception:
pass
# ===== 9. RESPONSE =====
return {
"access_token": access_token,
"token_type": "bearer",
"user": user_details,
}
File diff suppressed because it is too large Load Diff
+114
View File
@@ -0,0 +1,114 @@
import os
from urllib.parse import quote_plus
from sqlalchemy import create_engine, event
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from dotenv import load_dotenv
import datetime
from sqlalchemy import inspect as sa_inspect
from .utils import audit_log_path, get_current_user_ctx
load_dotenv()
# Prefer per-component DB config when provided; fallback to DATABASE_URL; finally to sqlite for dev
db_driver = os.getenv("DB_DRIVER")
db_user = os.getenv("DB_USER")
db_password = os.getenv("DB_PASSWORD")
db_host = os.getenv("DB_HOST")
db_port = os.getenv("DB_PORT")
db_name = os.getenv("DB_NAME")
database_url = None
if db_driver and db_user and db_host and db_port and db_name is not None:
# URL-encode username and password. If password is empty or None, omit the ':' portion
user_enc = quote_plus(db_user)
if db_password:
pwd_enc = quote_plus(db_password)
auth = f"{user_enc}:{pwd_enc}"
else:
auth = f"{user_enc}"
database_url = f"{db_driver}://{auth}@{db_host}:{db_port}/{db_name}"
if not database_url:
database_url = os.getenv("DATABASE_URL")
if not database_url:
# final fallback for local dev
database_url = "sqlite:///./test.db"
# Engine pool configuration to avoid QueuePool timeouts under concurrency
default_pool_size = int(os.getenv("DB_POOL_SIZE", "20"))
default_max_overflow = int(os.getenv("DB_POOL_MAX_OVERFLOW", "40"))
default_pool_timeout = int(os.getenv("DB_POOL_TIMEOUT", "60"))
default_pool_recycle = int(os.getenv("DB_POOL_RECYCLE", "1800")) # seconds
if database_url.startswith("sqlite"):
engine = create_engine(
database_url,
pool_pre_ping=True,
connect_args={"check_same_thread": False},
)
else:
engine = create_engine(
database_url,
pool_pre_ping=True,
pool_size=default_pool_size,
max_overflow=default_max_overflow,
pool_timeout=default_pool_timeout,
pool_recycle=default_pool_recycle,
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def _write_audit(line: str) -> None:
try:
with open(audit_log_path(), "a", encoding="utf-8") as f:
f.write(line)
except Exception:
pass
@event.listens_for(SessionLocal, "after_flush")
def _audit_after_flush(session, context):
user = get_current_user_ctx() or {}
uid = str((user.get("sub") or user.get("id") or "-"))
email = user.get("email") or "-"
now = datetime.datetime.utcnow().isoformat()
for obj in list(session.new):
ins = sa_inspect(obj)
mapper = ins.mapper
table = mapper.local_table.name if getattr(mapper, "local_table", None) is not None else getattr(obj, "__tablename__", obj.__class__.__name__)
pk = ins.identity
line = f"{now} | {uid} | {email} | INSERT {table} | pk={pk}\n"
_write_audit(line)
for obj in list(session.dirty):
if not session.is_modified(obj, include_collections=False):
continue
ins = sa_inspect(obj)
mapper = ins.mapper
table = mapper.local_table.name if getattr(mapper, "local_table", None) is not None else getattr(obj, "__tablename__", obj.__class__.__name__)
changes = []
for attr in ins.attrs:
hist = attr.history
if hist.has_changes():
old = hist.deleted[0] if hist.deleted else None
new = hist.added[0] if hist.added else getattr(obj, attr.key)
changes.append(f"{attr.key}={old}->{new}")
pk = ins.identity
chs = ", ".join(changes) if changes else "-"
line = f"{now} | {uid} | {email} | UPDATE {table} | pk={pk} | {chs}\n"
_write_audit(line)
for obj in list(session.deleted):
ins = sa_inspect(obj)
mapper = ins.mapper
table = mapper.local_table.name if getattr(mapper, "local_table", None) is not None else getattr(obj, "__tablename__", obj.__class__.__name__)
pk = ins.identity
line = f"{now} | {uid} | {email} | DELETE {table} | pk={pk}\n"
_write_audit(line)
+301
View File
@@ -0,0 +1,301 @@
import os
import time
import datetime
from pathlib import Path
from fastapi import FastAPI, Request, Depends, HTTPException, status
from sqlalchemy.orm import Session
from fastapi.middleware.cors import CORSMiddleware
from fastapi.openapi.utils import get_openapi
from dotenv import load_dotenv
from .utils import decode_access_token, set_current_user_ctx
from .database import get_db
from . import models
from typing import Dict, Any, List, Optional
load_dotenv()
from .database import engine, Base
from .routers import auth, users, roles, posts, month, security_index
from .routers import hardening
from .routers import files
from app.routers import system_groups as system_groups_router
from app.routers import systems as systems_router
app = FastAPI(
title="ANTT Portal API",
swagger_ui_parameters={"persistAuthorization": True},
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# @app.middleware("http")
# async def docs_ip_whitelist(request: Request, call_next):
# path = request.url.path
# if path.startswith("/docs") or path.startswith("/redoc") or path.startswith("/openapi.json"):
# wl = [x.strip() for x in (os.getenv("DOCS_WHITELIST_IPS") or "").split(",") if x.strip()]
# client_ip = request.client.host if request.client else ""
# if wl and client_ip not in wl:
# raise HTTPException(status_code=403, detail="IP not allowed")
# return await call_next(request)
def get_real_ip(request: Request) -> str:
xff = request.headers.get("x-forwarded-for")
if xff:
# Lấy IP đầu tiên (client thật)
return xff.split(",")[0].strip()
x_real_ip = request.headers.get("x-real-ip")
if x_real_ip:
return x_real_ip.strip()
if request.client:
return request.client.host
return ""
@app.middleware("http")
async def docs_ip_whitelist(request: Request, call_next):
path = request.url.path
if path.startswith(("/docs", "/redoc", "/openapi.json")):
wl = [
ip.strip()
for ip in (os.getenv("DOCS_WHITELIST_IPS") or "").split(",")
if ip.strip()
]
client_ip = get_real_ip(request)
if wl and client_ip not in wl:
raise HTTPException(
status_code=403,
detail=f"IP {client_ip} not allowed"
)
return await call_next(request)
def _activity_log_dir() -> Path:
base = os.getenv("ACTIVITY_LOG_DIR", "logs")
p = Path(base).resolve()
p.mkdir(parents=True, exist_ok=True)
return p
def _activity_log_path() -> Path:
now = datetime.datetime.utcnow()
month_dir = _activity_log_dir() / now.strftime("%Y%m")
month_dir.mkdir(parents=True, exist_ok=True)
return month_dir / f"{now.strftime('%Y-%m-%d')}.txt"
@app.middleware("http")
async def activity_logger(request: Request, call_next):
path = request.url.path
if path.startswith("/auth/login"):
return await call_next(request)
if path.startswith("/auth/login_sso"):
return await call_next(request)
method = request.method.upper()
qs = request.url.query or ""
ip = request.client.host if request.client else "-"
start = time.time()
status_code = 500
user_payload = None
auth_header = request.headers.get("Authorization") or ""
token = None
try:
scheme, token = auth_header.split()
if scheme.lower() != "bearer":
token = None
except Exception:
token = None
if token:
try:
user_payload = decode_access_token(token)
except Exception:
user_payload = None
try:
set_current_user_ctx(user_payload)
except Exception:
pass
try:
response = await call_next(request)
status_code = response.status_code
return response
finally:
try:
set_current_user_ctx(None)
except Exception:
pass
try:
user_id = "-"
user_email = "-"
if user_payload:
try:
user_id = str(user_payload.get("sub") or "-")
user_email = user_payload.get("email") or "-"
except Exception:
pass
duration_ms = int((time.time() - start) * 1000)
line = f"{datetime.datetime.utcnow().isoformat()} | {ip} | {user_id} | {user_email} | {method} {path}{('?' + qs) if qs else ''} | {status_code} | {duration_ms}ms\n"
with open(_activity_log_path(), "a", encoding="utf-8") as f:
f.write(line)
except Exception:
pass
@app.on_event("startup")
def on_startup():
# create tables if AUTO_CREATE_DB is enabled (convenience for dev only)
if os.getenv("AUTO_CREATE_DB", "0") == "1":
Base.metadata.create_all(bind=engine)
app.include_router(auth.router)
app.include_router(roles.router, prefix="/roles", tags=["roles"])
app.include_router(users.router, prefix="/users", tags=["users"])
app.include_router(posts.router, prefix="/posts", tags=["posts"])
app.include_router(month.router, prefix="/months", tags=["months"])
app.include_router(security_index.router)
app.include_router(hardening.router)
# Đăng ký categories
from .routers import categories
app.include_router(categories.router, prefix="/categories", tags=["categories"])
app.include_router(files.router, prefix="/files", tags=["files"])
from .routers import pentest
from .routers import pentest_service
from .routers import jira
from .routers import units
from .routers import overview
from .routers import scorecard
from .routers import email as email_router
from .routers import documents as documents_router
from .routers import soc_ticket
from .routers import logsource
app.include_router(pentest.router, prefix="/pentest", tags=["pentest"])
app.include_router(pentest_service.router)
app.include_router(soc_ticket.router)
app.include_router(logsource.router)
from .routers import mail_history
app.include_router(mail_history.router, prefix="/mail-history", tags=["mail-history"])
from .routers import import_history as import_history_router
app.include_router(import_history_router.router, prefix="/import-history", tags=["import-history"])
from .routers import manage_systems as manage_systems_router
app.include_router(manage_systems_router.router)
# app.include_router(system_groups_router.router)
app.include_router(systems_router.router)
app.include_router(jira.router, prefix="/jira", tags=["jira"])
app.include_router(units.router)
app.include_router(overview.router)
app.include_router(scorecard.router)
app.include_router(email_router.email_roles_router)
app.include_router(email_router.email_users_router)
app.include_router(documents_router.router)
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="ANTT Portal API",
version="1.0.0",
description="API Gateway for ANTT Portal",
routes=app.routes,
)
openapi_schema["components"]["securitySchemes"] = {
"Bearer": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"description": "Enter JWT token (no 'Bearer' prefix needed)",
}
}
# Áp dụng security toàn cục để UI biết cần Bearer
openapi_schema["security"] = [{"Bearer": []}]
# Add security requirement to all paths except /auth/login
if "paths" in openapi_schema:
for path, path_item in openapi_schema["paths"].items():
# Bỏ qua các endpoint auth
if "/auth/" in path:
continue
# Thêm security cho từng operation nếu chưa có
for method in ["get", "post", "put", "delete", "patch"]:
if method in path_item:
operation = path_item[method]
if "security" not in operation:
operation["security"] = [{"Bearer": []}]
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi
# Public API: system groups tree via ManageSystem (levels 0/1/2), API key + IP whitelist
@app.post("/sync/system-groups", tags=["system_groups"])
def system_groups_tree(
request: Request,
payload: Dict[str, Any],
db: Session = Depends(get_db),
):
cfg_key = os.getenv("SYSTEM_GROUPS_API_KEY")
if not cfg_key:
raise HTTPException(status_code=500, detail="SYSTEM_GROUPS_API_KEY is not configured")
use_key = str(payload.get("api_key") or "")
if (use_key or "").strip() != cfg_key.strip():
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid API key",
headers={"WWW-Authenticate": "ApiKey"},
)
wl = [x.strip() for x in (os.getenv("SYSTEM_GROUPS_WHITELIST_IPS") or "").split(",") if x.strip()]
client_ip = request.client.host if request.client else ""
if wl and client_ip not in wl:
raise HTTPException(status_code=403, detail="IP not allowed")
items: List[models.ManageSystem] = db.query(models.ManageSystem).order_by(models.ManageSystem.level.asc(), models.ManageSystem.id.asc()).all()
type_map = {
0: "Web quản trị",
1: "Web dịch vụ",
2: "API",
3: "Mobile app",
4: "Khác",
5: "CNTT",
6: "ATTT",
}
nodes: Dict[int, Dict[str, Any]] = {}
for it in items:
tval = int(it.type) if getattr(it, "type", None) is not None else None
nodes[int(it.id)] = {
"id": int(it.id),
"name": it.name,
"level": int(it.level),
"parent_id": int(it.parent_id) if getattr(it, "parent_id", None) is not None else None,
"url_ip": getattr(it, "url_ip", None),
"unit_id": int(it.unit_id) if getattr(it, "unit_id", None) is not None else None,
"type": tval,
"type_name": type_map.get(tval) if tval is not None else None,
"private": bool(it.private) if getattr(it, "private", None) is not None else None,
"priority_level": int(it.priority_level) if getattr(it, "priority_level", None) is not None else None,
"status": bool(it.status) if getattr(it, "status", None) is not None else None,
"children": [],
}
roots: List[Dict[str, Any]] = []
for it in items:
node = nodes[int(it.id)]
pid = getattr(it, "parent_id", None)
if pid is None:
roots.append(node)
else:
parent = nodes.get(int(pid))
if parent:
parent["children"].append(node)
else:
roots.append(node)
return {"message": "success", "data": roots}
+541
View File
@@ -0,0 +1,541 @@
from sqlalchemy import Column, BigInteger, Integer, String, DateTime, Text, Boolean, Float, Index, UniqueConstraint
from .database import Base
import datetime
class Role(Base):
__tablename__ = "role"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False, unique=True)
description = Column(String(255))
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships
# relationships are intentionally omitted; handle joins in SQL queries as needed
class Permission(Base):
__tablename__ = "permission"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False)
path = Column(String(255), nullable=False)
method = Column(String(20), nullable=False)
description = Column(String(255))
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class Unit(Base):
__tablename__ = "units"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False)
description = Column(Text)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
__table_args__ = (Index('ix_units_name', 'name'),)
class User(Base):
__tablename__ = "users"
id = Column(BigInteger, primary_key=True, autoincrement=True)
email = Column(String(255), nullable=False, unique=True)
fullname = Column(String(255), nullable=False)
unit_id = Column(BigInteger, nullable=True)
role_id = Column(BigInteger, nullable=True)
status = Column(Integer, default=1)
#status 1 is created, 2 is active, 3 is disabled
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
hashed_password = Column(String(255), nullable=True)
# relationships intentionally omitted
__table_args__ = (Index('ix_users_email', 'email'),)
class Category(Base):
__tablename__ = "category"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False, unique=True)
# relationships intentionally omitted
class Post(Base):
__tablename__ = "posts"
id = Column(BigInteger, primary_key=True, autoincrement=True)
content = Column(Text, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
title = Column(String(255), nullable=False)
created_by = Column(BigInteger)
category_id = Column(BigInteger)
status = Column(Boolean, default=True)
thumbnail = Column(String(255), nullable=True)
# relationships intentionally omitted
class Month(Base):
__tablename__ = "month"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
from_date = Column(DateTime, nullable=False)
end_date = Column(DateTime, nullable=False)
# relationships intentionally omitted
class NAC(Base):
__tablename__ = "nac"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=False)
total = Column(BigInteger, default=0)
installed = Column(BigInteger, default=0)
ignored = Column(BigInteger, default=0)
rate = Column(Float, default=0)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class SmartIR(Base):
__tablename__ = "smartir"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=False)
total = Column(BigInteger, default=0)
installed = Column(BigInteger, default=0)
new_install = Column(BigInteger, default=0)
ignored = Column(BigInteger, default=0)
rate = Column(Float, default=0)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class Compliance(Base):
__tablename__ = "compliance"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=False)
windows_key = Column(BigInteger, default=0)
office = Column(BigInteger, default=0)
ms17010 = Column(BigInteger, default=0)
firewall = Column(BigInteger, default=0)
uac = Column(BigInteger, default=0)
winrar = Column(BigInteger, default=0)
antivirus = Column(BigInteger, default=0)
update_win = Column(BigInteger, default=0)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class LogSource(Base):
__tablename__ = "logsource"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=False)
log_id = Column(BigInteger)
name = Column(String(255), nullable=False)
description = Column(Text)
is_enabled = Column(Boolean, default=True)
source_type_id = Column(BigInteger)
status = Column(Integer) # lưu mã 1=OK, 2=ERROR, 3=DISABLE, 4=NOT AVAILABLE
message = Column(String(255))
other = Column(String(255))
file_id = Column(BigInteger, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class LogSourceComment(Base):
__tablename__ = "logsource_comment"
id = Column(BigInteger, primary_key=True, autoincrement=True)
logsource_id = Column(BigInteger, nullable=False)
user_id = Column(BigInteger, nullable=False)
comment = Column(Text, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class SourceType(Base):
__tablename__ = "source_type"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False)
type = Column(String(100))
# relationships intentionally omitted
class Ticket(Base):
__tablename__ = "ticket"
id = Column(BigInteger, primary_key=True, autoincrement=True)
open_count = Column(BigInteger, default=0)
in_process = Column(BigInteger, default=0)
completed = Column(BigInteger, default=0)
unit_id = Column(BigInteger, nullable=False)
month_id = Column(BigInteger, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class RootAccess(Base):
__tablename__ = "root_access"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=False)
number = Column(BigInteger, default=0)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class AttackStatics(Base):
__tablename__ = "attack_statics"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
siem_fintech = Column(BigInteger, default=0)
siem_media = Column(BigInteger, default=0)
ticket = Column(BigInteger, default=0)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class SmartIRDetail(Base):
__tablename__ = "smartir_detail"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=True)
vnpt_ma_nhan_vien = Column(String(255), nullable=True)
name = Column(String(255), nullable=True)
email = Column(String(255), nullable=True)
phong_ban = Column(String(255), nullable=True)
ip = Column(String(255), nullable=True)
pc_name = Column(String(255), nullable=True)
mac = Column(String(255), nullable=True)
agent_version = Column(String(255), nullable=True)
last_online = Column(String(255), nullable=True)
status = Column(Integer, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class NACDetail(Base):
__tablename__ = "nac_detail"
id = Column(BigInteger, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=True)
name = Column(String(255), nullable=True)
email = Column(String(255), nullable=True)
status = Column(Integer, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class ComplianceDetail(Base):
__tablename__ = "compliance_detail"
id = Column(BigInteger, primary_key=True, autoincrement=True)
unit_id = Column(BigInteger, nullable=True)
month_id = Column(BigInteger, nullable=False)
vnpt_ma_nhan_vien = Column(String(255), nullable=True)
name = Column(String(255), nullable=True)
email = Column(String(255), nullable=True)
phong_ban = Column(String(255), nullable=True)
windows_key = Column(BigInteger, nullable=True)
office = Column(BigInteger, nullable=True)
ms17010 = Column(BigInteger, nullable=True)
firewall = Column(BigInteger, nullable=True)
uac = Column(BigInteger, nullable=True)
winrar = Column(BigInteger, nullable=True)
antivirus = Column(BigInteger, nullable=True)
update_win = Column(BigInteger, nullable=True)
status = Column(Integer, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class ComplianceSmartIR(Base):
__tablename__ = "compliance_smartir"
id = Column(Integer, primary_key=True, autoincrement=True)
month_id = Column(BigInteger, nullable=False)
unit_id = Column(BigInteger, nullable=True)
vnpt_ma_nhan_vien = Column(String(20), nullable=False)
name = Column(String(255), nullable=False)
email = Column(String(255), nullable=False)
phong_ban = Column(String(255), nullable=True)
ten_may_tinh = Column(String(255), nullable=True)
mac = Column(String(50), nullable=True)
active_windows = Column(Integer, nullable=True)
bat_windows_firewall = Column(Integer, nullable=True)
bat_uac = Column(Integer, nullable=True)
cai_winrar_ban_moi = Column(Integer, nullable=True)
bat_av_fullscan = Column(Integer, nullable=True)
update_windows = Column(Integer, nullable=True)
status = Column(Integer, nullable=False, default=0)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(DateTime, default=datetime.datetime.utcnow)
class MailHistory(Base):
__tablename__ = "mail_history"
id = Column(BigInteger, primary_key=True, autoincrement=True)
post_id = Column(BigInteger)
subject = Column(String(255), nullable=True)
role_id = Column(BigInteger, nullable=True)
content = Column(Text)
status = Column(Integer, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# relationships intentionally omitted
class FileUpload(Base):
__tablename__ = "file_upload"
id = Column(BigInteger, primary_key=True, autoincrement=True)
path = Column(String(255), nullable=False)
table_name = Column(String(255), nullable=False)
table_id = Column(BigInteger, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
__table_args__ = (Index('ix_fileupload_table', 'table_name', 'table_id'),)
class ImportHistory(Base):
__tablename__ = "import_history"
id = Column(BigInteger, primary_key=True, autoincrement=True)
type = Column(String(255), nullable=False)
file_path = Column(String(255), nullable=False)
month_id = Column(BigInteger, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
__table_args__ = (Index('ix_import_history_type_month', 'type', 'month_id'),)
class MMFintech(Base):
__tablename__ = "mm_fintech"
id = Column(BigInteger, primary_key=True, autoincrement=True, index=True)
month_id = Column(BigInteger, nullable=False, index=True)
unit_id = Column(BigInteger, nullable=True, index=True)
file_path = Column(String(255), nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class ConvertHardening(Base):
__tablename__ = "convert_hardening"
id = Column(BigInteger, primary_key=True, autoincrement=True, index=True)
filename = Column(String(255), nullable=False, index=True)
user_id = Column(BigInteger, nullable=False, index=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class SystemGroup(Base):
__tablename__ = "system_group"
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
name = Column(String(255), nullable=False, index=True)
description = Column(String(1000), nullable=True)
class System(Base):
__tablename__ = "system"
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
name = Column(String(255), nullable=False, index=True)
url_ip = Column(String(255), nullable=True, index=True)
unit_id = Column(BigInteger, nullable=True, index=True)
system_group_id = Column(BigInteger, nullable=True, index=True)
description = Column(String(1000), nullable=True)
status = Column(Integer, nullable=True, index=True)
class ManageSystem(Base):
__tablename__ = "manage_system"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False, unique=True)
level = Column(Integer, nullable=False)
url_ip = Column(String(255), nullable=True)
unit_id = Column(BigInteger, nullable=True)
parent_id = Column(BigInteger, nullable=True)
type = Column(Integer, nullable=True)
private = Column(Boolean, default=False)
priority_level = Column(Integer, nullable=True)
status = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
__table_args__ = (
Index('ix_manage_system_name', 'name'),
Index('ix_manage_system_level_parent', 'level', 'parent_id'),
Index('ix_manage_system_unit', 'unit_id'),
)
class PentestService(Base):
__tablename__ = "pentest_service"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(Text, nullable=True)
type = Column(Integer, nullable=False) # 1: Đánh giá ATTT, 2: Công việc phối hợp, 3: Phối hợp xử lý, 4: Khác
code = Column(String(50), nullable=False, unique=True)
file_path = Column(String(255), nullable=True)
description = Column(Text, nullable=True)
due_date = Column(DateTime, nullable=True)
unit_id = Column(BigInteger, nullable=True)
status = Column(Integer, default=0) # 0: nháp, 1: tạo mới, 2: tiếp nhận, 3: đã xử lý, 4: đóng, 5: hủy
user_id = Column(BigInteger, nullable=True)
target_id = Column(BigInteger, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class PentestServiceComment(Base):
__tablename__ = "pentest_service_comment"
id = Column(BigInteger, primary_key=True, autoincrement=True)
pentest_service_id = Column(BigInteger, nullable=False)
content = Column(Text, nullable=False)
user_id = Column(BigInteger, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class PentestServiceHistory(Base):
__tablename__ = "pentest_service_history"
id = Column(BigInteger, primary_key=True, autoincrement=True)
pentest_service_id = Column(BigInteger, nullable=False)
old_status = Column(Integer, nullable=True)
new_status = Column(Integer, nullable=False)
user_id = Column(BigInteger, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class PentestServiceAssign(Base):
__tablename__ = "pentest_service_assign"
id = Column(BigInteger, primary_key=True, autoincrement=True)
user_id = Column(BigInteger, nullable=True)
email = Column(String(255), nullable=True)
pentest_service_id = Column(BigInteger, nullable=False)
class RevokedToken(Base):
__tablename__ = "revoked_token"
id = Column(BigInteger, primary_key=True, autoincrement=True)
jti = Column(String(64), nullable=False, unique=True, index=True)
user_id = Column(BigInteger, nullable=True)
revoked_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
expires_at = Column(DateTime, nullable=True)
class EmailRole(Base):
__tablename__ = "email_role"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False)
description = Column(String(1000), nullable=True)
class EmailUser(Base):
__tablename__ = "email_user"
id = Column(BigInteger, primary_key=True, autoincrement=True)
email = Column(String(255), nullable=False)
name = Column(String(255), nullable=True)
role_id = Column(BigInteger, nullable=False)
type = Column(Integer, nullable=False)
__table_args__ = (Index('ix_email_user_role', 'role_id'),)
class Document(Base):
__tablename__ = "documents"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False)
number_doc = Column(String(255), nullable=False)
sign_date = Column(DateTime, nullable=True)
level = Column(Integer, nullable=False)
validate_date = Column(DateTime, nullable=True)
file_path = Column(String(255), nullable=True)
class SecurityIndex(Base):
__tablename__ = "security_index"
id = Column(BigInteger, primary_key=True, autoincrement=True, index=True)
soc = Column(Integer, default=0)
pentest = Column(Integer, default=0)
access_policy = Column(Integer, default=0)
two_fa_policy = Column(Integer, default=0) # Cannot start with digit in Python, mapped to 2fa_policy if needed
config_network = Column(Integer, default=0)
config_server = Column(Integer, default=0)
patch_security = Column(Integer, default=0)
month_id = Column(BigInteger, nullable=False, index=True)
unit_id = Column(BigInteger, nullable=False, index=True)
description = Column(Text, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class SocTarget(Base):
__tablename__ = "soc_target"
id = Column(BigInteger, primary_key=True, autoincrement=True)
unit_id = Column(BigInteger, nullable=False)
priority = Column(Integer, nullable=False) # 1=critical → 5=low
name = Column(String(255), nullable=False)
code = Column(String(100), unique=True)
status = Column(Integer, nullable=False, default=0) # 0:Open, 1:In Progress, 2:Resolved, 3:Closed
deadline = Column(DateTime)
description = Column(Text, nullable=False)
system_id = Column(BigInteger, nullable=True)
system_type = Column(Integer, nullable=True)
source_ip = Column(Text, nullable=True)
destination_ip = Column(Text, nullable=True)
soc_target_type_id = Column(BigInteger, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
created_by = Column(BigInteger, nullable=True)
class SocTargetType(Base):
__tablename__ = "soc_target_type"
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String(255), nullable=False)
class TicketRelated(Base):
__tablename__ = "ticket_related"
id = Column(BigInteger, primary_key=True, autoincrement=True)
soc_target_id = Column(BigInteger, nullable=False)
related_soc_target_id = Column(BigInteger, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class SocTargetAssign(Base):
__tablename__ = "soc_target_assign"
id = Column(BigInteger, primary_key=True, autoincrement=True)
target_id = Column(BigInteger, nullable=False)
user_id = Column(BigInteger, nullable=True)
email = Column(String(255), nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class SocTargetHistory(Base):
__tablename__ = "soc_target_history"
id = Column(BigInteger, primary_key=True, autoincrement=True)
target_id = Column(BigInteger, nullable=False)
field_name = Column(String(100), nullable=False)
old_value = Column(Text)
new_value = Column(Text)
changed_by = Column(BigInteger, nullable=True)
changed_at = Column(DateTime, default=datetime.datetime.utcnow)
class SocTargetComment(Base):
__tablename__ = "soc_target_comment"
id = Column(BigInteger, primary_key=True, autoincrement=True)
target_id = Column(BigInteger, nullable=False)
user_id = Column(BigInteger, nullable=True)
email = Column(String(255), nullable=True)
content = Column(Text, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
class SocTargetAttachment(Base):
__tablename__ = "soc_target_attachment"
id = Column(BigInteger, primary_key=True, autoincrement=True)
target_id = Column(BigInteger, nullable=False)
file_name = Column(String(255), nullable=False)
file_path = Column(String(500), nullable=False)
file_size = Column(BigInteger, nullable=True)
file_type = Column(String(100), nullable=True)
uploaded_by = Column(BigInteger, nullable=True)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
class PostComment(Base):
__tablename__ = "post_comment"
id = Column(BigInteger, primary_key=True, autoincrement=True)
post_id = Column(BigInteger, nullable=False)
user_id = Column(BigInteger, nullable=False)
content = Column(Text, nullable=False)
created_at = Column(DateTime, default=datetime.datetime.utcnow)
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
+142
View File
@@ -0,0 +1,142 @@
import socket
import struct
import hashlib
import random
# RADIUS Attribute Type names (RFC 2865 + common)
RADIUS_ATTR_NAMES = {
1: "User-Name",
6: "Service-Type",
8: "Framed-IP-Address",
11: "Filter-Id",
18: "Reply-Message",
25: "Class",
26: "Vendor-Specific",
27: "Session-Timeout",
}
def encrypt_password(password: str, secret: str, request_authenticator: bytes) -> bytes:
"""Mã hóa mật khẩu PAP theo chuẩn RADIUS RFC 2865."""
password_bytes = password.encode('utf-8')
if len(password_bytes) % 16 != 0:
password_bytes += b'\x00' * (16 - len(password_bytes) % 16)
encrypted = b''
last = secret.encode('utf-8') + request_authenticator
for i in range(0, len(password_bytes), 16):
block = password_bytes[i:i+16]
md5_hash = hashlib.md5(last).digest()
encrypted_block = bytes(a ^ b for a, b in zip(block, md5_hash))
encrypted += encrypted_block
last = secret.encode('utf-8') + encrypted_block
return encrypted
def build_access_request(username: str, password: str, secret: str,
identifier: int = None) -> bytes:
"""Tạo gói Access-Request PAP cho RADIUS server."""
if identifier is None:
identifier = random.randint(0, 255)
request_authenticator = bytes(random.getrandbits(8) for _ in range(16))
username_attr = b'\x01' + struct.pack('B', len(username) + 2) + username.encode('utf-8')
password_attr_bytes = encrypt_password(password, secret, request_authenticator)
password_attr = b'\x02' + struct.pack('B', len(password_attr_bytes) + 2) + password_attr_bytes
attrs = username_attr + password_attr
length = 20 + len(attrs)
header = struct.pack('!BBH', 1, identifier, length) + request_authenticator
return header + attrs
def parse_radius_attributes(attributes_raw: bytes) -> dict:
"""
Parse phần attributes của gói RADIUS response.
Trả về dict: {type_int: [value_bytes, ...]}
"""
result: dict[int, list] = {}
idx = 0
while idx < len(attributes_raw):
if idx + 2 > len(attributes_raw):
break
attr_type = attributes_raw[idx]
attr_len = attributes_raw[idx + 1]
if attr_len < 2 or idx + attr_len > len(attributes_raw):
break
attr_value = attributes_raw[idx + 2: idx + attr_len]
result.setdefault(attr_type, []).append(attr_value)
idx += attr_len
return result
def check_radius_login(server: str, port: int, secret: str, username: str,
password: str, timeout: int = 5) -> bool:
"""
Kiểm tra username/password với RADIUS server (PAP).
Trả về True nếu Access-Accept, False nếu thất bại.
(Giữ nguyên signature để không ảnh hưởng code cũ)
"""
ok, _ = check_radius_login_extended(server, port, secret, username, password, timeout)
return ok
def check_radius_login_extended(server: str, port: int, secret: str, username: str,
password: str, timeout: int = 5) -> tuple[bool, dict]:
"""
Kiểm tra username/password với RADIUS server (PAP).
Trả về (success: bool, attributes: dict)
attributes chứa các giá trị decode từ RADIUS response, ví dụ:
{
'filter_id': ['Trung tâm An ninh thông tin'],
'reply_message': ['privacyIDEA access granted'],
'raw': {11: [b'...'], 18: [b'...']},
}
"""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(timeout)
attrs_decoded: dict = {}
try:
req_packet = build_access_request(username, password, secret)
sock.sendto(req_packet, (server, port))
resp, _ = sock.recvfrom(4096)
code = resp[0]
length = struct.unpack('!H', resp[2:4])[0]
raw_attrs = parse_radius_attributes(resp[20:length])
# Decode các attributes thường gặp sang chuỗi
def _decode_list(raw_list: list) -> list[str]:
return [v.decode('utf-8', errors='replace') for v in raw_list]
attrs_decoded['raw'] = raw_attrs
# Filter-Id (Type 11) — thường chứa thông tin nhóm/đơn vị
if 11 in raw_attrs:
attrs_decoded['filter_id'] = _decode_list(raw_attrs[11])
# Reply-Message (Type 18)
if 18 in raw_attrs:
attrs_decoded['reply_message'] = _decode_list(raw_attrs[18])
# Class (Type 25)
if 25 in raw_attrs:
attrs_decoded['class'] = _decode_list(raw_attrs[25])
if code == 2: # Access-Accept
print(f"[RADIUS] ✅ Đăng nhập thành công: {username}")
if attrs_decoded.get('filter_id'):
print(f"[RADIUS] Filter-Id: {attrs_decoded['filter_id']}")
return True, attrs_decoded
else:
print(f"[RADIUS] ❌ Sai username hoặc password: {username}")
return False, attrs_decoded
except socket.timeout:
print("[RADIUS] ⏱ Timeout khi kết nối đến RADIUS server.")
return False, {}
except Exception as e:
print(f"[RADIUS] ⚠️ Lỗi: {e}")
return False, {}
finally:
sock.close()
File diff suppressed because it is too large Load Diff
+342
View File
@@ -0,0 +1,342 @@
"""JWT authentication dependencies for FastAPI."""
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer
from starlette.requests import Request
from app.utils import decode_access_token
import jwt
from sqlalchemy.orm import Session
from app.database import get_db
from app.models import RevokedToken, User
import re
import datetime
security = HTTPBearer()
# In-memory revoked token store (non-persistent). Use DB for production.
# In-memory fallback (không bền vững). Giữ lại để chặn ngay trong tiến trình hiện tại.
REVOKED_TOKENS: set[str] = set()
LATEST_JTI_PER_USER: dict[int, str] = {}
def revoke_token(token: str) -> None:
REVOKED_TOKENS.add(token)
def set_latest_jti(user_id: int, jti: str) -> None:
LATEST_JTI_PER_USER[user_id] = jti
def revoke_token_db(db: Session, token: str) -> None:
"""Decode token and persist its jti to DB for revocation."""
payload = decode_access_token(token)
jti = payload.get("jti")
sub = payload.get("sub")
exp = payload.get("exp")
expires_at = None
if isinstance(exp, (int, float)):
expires_at = datetime.datetime.utcfromtimestamp(exp)
elif isinstance(exp, datetime.datetime):
expires_at = exp
if not jti:
# không có jti thì vẫn dùng in-memory để tránh bỏ sót
REVOKED_TOKENS.add(token)
return
if not db.query(RevokedToken).filter(RevokedToken.jti == jti).first():
db.add(RevokedToken(
jti=jti,
user_id=int(sub) if sub is not None else None,
expires_at=expires_at
))
db.commit()
async def get_current_user(request: Request, db: Session = Depends(get_db)):
"""Dependency to extract and validate JWT token from request headers.
Returns the decoded token payload with user info.
Raises:
HTTPException: If token is invalid, expired, or missing
"""
auth_header = request.headers.get("Authorization")
if not auth_header:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
try:
scheme, token = auth_header.split()
if scheme.lower() != "bearer":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication scheme",
headers={"WWW-Authenticate": "Bearer"},
)
except ValueError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
# Reject revoked tokens (in-memory fallback)
if token in REVOKED_TOKENS:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has been revoked",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = decode_access_token(token)
# Check DB revocation via jti
jti = payload.get("jti")
if jti and db.query(RevokedToken).filter(RevokedToken.jti == jti).first():
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has been revoked",
headers={"WWW-Authenticate": "Bearer"},
)
user_id: str = payload.get("sub")
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
)
try:
uid_int = int(user_id)
latest = LATEST_JTI_PER_USER.get(uid_int)
if latest and jti and jti != latest:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token is not the latest",
headers={"WWW-Authenticate": "Bearer"},
)
u = db.query(User).filter(User.id == uid_int).first()
if u:
if payload.get("role_id") is None:
payload["role_id"] = getattr(u, "role_id", None)
if payload.get("unit_id") is None:
payload["unit_id"] = getattr(u, "unit_id", None)
if not payload.get("email"):
payload["email"] = getattr(u, "email", None)
if not payload.get("fullname"):
payload["fullname"] = getattr(u, "fullname", None)
if payload.get("status") is None:
payload["status"] = getattr(u, "status", None)
except HTTPException:
raise
except Exception:
pass
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has expired",
headers={"WWW-Authenticate": "Bearer"},
)
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
)
# ---- RBAC helpers ----
# Role IDs
ROLE_ADMIN = 1
ROLE_DIRECTOR = 2
ROLE_MANAGER = 3
ROLE_LEADER_PM = 4
ROLE_ADMIN_LIMITED = 9
def _role_id(user: dict) -> int | None:
try:
rid = user.get("role_id")
return int(rid) if rid is not None else None
except Exception:
return None
def is_admin(user: dict) -> bool:
return _role_id(user) in (ROLE_ADMIN, ROLE_ADMIN_LIMITED)
def is_director(user: dict) -> bool:
return _role_id(user) == ROLE_DIRECTOR
def is_manager(user: dict) -> bool:
return _role_id(user) == ROLE_MANAGER
def is_leader_pm(user: dict) -> bool:
return _role_id(user) == ROLE_LEADER_PM
def get_user_email(user: dict) -> str:
return (user.get("email") or "").strip()
def get_user_unit_id(user: dict) -> int | None:
try:
uid = user.get("unit_id")
return int(uid) if uid is not None else None
except Exception:
return None
# RBAC
ROLE_ADMIN = 1
ROLE_DIRECTOR = 2
ROLE_MANAGER = 3
ROLE_LEADER_PM = 4
ROLE_ADMIN_LIMITED = 9
def _role_id(user: dict) -> int | None:
try:
rid = user.get("role_id")
return int(rid) if rid is not None else None
except Exception:
return None
# def is_admin(user: dict) -> bool:
# return _role_id(user) in (ROLE_ADMIN, ROLE_ADMIN_LIMITED)
# def is_director(user: dict) -> bool:
# return _role_id(user) == ROLE_DIRECTOR
# def is_manager(user: dict) -> bool:
# return _role_id(user) == ROLE_MANAGER
# def is_leader_pm(user: dict) -> bool:
# return _role_id(user) == ROLE_LEADER_PM
# def get_user_email(user: dict) -> str:
# return (user.get("email") or "").strip()
def _method_path(request: Request) -> tuple[str, str]:
return request.method.upper(), request.url.path.lower()
def _path_match(path: str, patterns: list[str]) -> bool:
for p in patterns:
q = p.lower()
if "*" in q:
regex = "^" + re.escape(q).replace("\\*", ".*") + "$"
if re.match(regex, path):
return True
else:
if path == q or path.startswith(q + "/"):
return True
return False
DIRECTOR_GET = [
"/months",
"/units",
"/jira/tickets-overview",
"/scorecard*",
"/overview/nac",
"/overview/compliance",
"/months/*/compliance",
"/overview/smart-ir",
"/pentest/get-overview",
"/pentest/vuln-lastest-12month",
"/pentest/category",
"/pentest/category-vuln",
"/pentest/get-top-vulns",
"/pentest/get-target-detail",
"/pentest/download-target-checklist",
"/months/*/files",
"/files/download",
"/jira/tickets-week",
"/jira/tickets-12-month-lastest",
"/months/*/root-access",
"/months/*/attack-statics",
"/months/*/logsource",
"/months/*/nac-smartir",
"/months/*/compliance",
"/posts",
"/categories",
"/documents",
"/documents/download",
"/months/*/pam-tsc",
"/hardening/*",
"/pentest/log_history/*",
"/pentest-service*",
"/logsource/*/comments",
]
DIRECTOR_POST = [
"/auth/login",
"/auth/logout",
"/pentest-service*",
]
MANAGER_GET = DIRECTOR_GET + [
"/pentest/update-vuln-status",
]
MANAGER_POST = DIRECTOR_POST
LEADER_GET = MANAGER_GET
LEADER_POST = MANAGER_POST
def enforce_rbac(request: Request, user: dict = Depends(get_current_user)):
method, path = _method_path(request)
# Cho phép tất cả các nhóm người dùng đã đăng nhập truy cập vào /pentest-service
if "pentest-service" in path:
return
rid = _role_id(user)
if rid == ROLE_ADMIN:
return
if rid == ROLE_ADMIN_LIMITED:
deny_get = [
# "/pentest/category-vuln",
"/pentest/get-target-detail",
"/pentest/download-target-checklist",
]
deny_post = [
"/users",
"/roles",
]
deny_put = [
"/users/*",
"/roles/*",
]
deny_delete = [
"/users/*",
"/roles/*",
]
if method == "GET" and _path_match(path, deny_get):
raise HTTPException(status_code=403, detail="Forbidden")
if method == "POST" and _path_match(path, deny_post):
raise HTTPException(status_code=403, detail="Forbidden")
if method == "PUT" and _path_match(path, deny_put):
raise HTTPException(status_code=403, detail="Forbidden")
if method == "DELETE" and _path_match(path, deny_delete):
raise HTTPException(status_code=403, detail="Forbidden")
return
# Cho phép các method khác GET cho pentest-service
NONGET_ALLOWED_ALL_ROLES = [
"/systems/search-leak",
"/hardening/convert/upload",
"/pentest-service*",
"/posts/*/comments", # Cho phép tất cả người dùng đã đăng nhập thêm comment
"/logsource/*/comments", # Cho phép tất cả người dùng đã đăng nhập thêm bình luận LogSource
]
if method != "GET":
if _path_match(path, NONGET_ALLOWED_ALL_ROLES):
return
raise HTTPException(status_code=403, detail="Forbidden")
if is_director(user):
allowed = DIRECTOR_GET if method == "GET" else DIRECTOR_POST
elif is_manager(user):
allowed = MANAGER_GET if method == "GET" else MANAGER_POST
elif is_leader_pm(user):
allowed = LEADER_GET if method == "GET" else LEADER_POST
else:
# Nếu không thuộc các nhóm trên nhưng là /pentest-service thì đã return ở trên
raise HTTPException(status_code=403, detail="Forbidden")
if not _path_match(path, allowed):
raise HTTPException(status_code=403, detail="Forbidden")
return
+90
View File
@@ -0,0 +1,90 @@
from passlib.context import CryptContext
import hashlib
import jwt
from datetime import datetime, timedelta
from typing import Dict, Any
import os
import uuid
from pathlib import Path
import contextvars
# Password hashing
pwd_context = CryptContext(schemes=["pbkdf2_sha256"], deprecated="auto")
def hash_password(password: str) -> str:
"""Hash a plain-text password using PBKDF2-SHA256.
This supports arbitrary password lengths and avoids backend problems.
"""
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
# return True
# JWT configuration
JWT_SECRET = os.getenv("JWT_SECRET", "your-secret-key-change-this-in-production")
JWT_ALGORITHM = "HS256"
JWT_EXPIRATION_HOURS = int(os.getenv("JWT_EXPIRATION_HOURS", 24))
def create_access_token(data: Dict[str, Any], expires_delta: timedelta = None) -> str:
"""Create a JWT access token.
Args:
data: Dictionary of claims to encode
expires_delta: Optional timedelta for token expiration; defaults to JWT_EXPIRATION_HOURS
Returns:
JWT token string
"""
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(hours=JWT_EXPIRATION_HOURS)
to_encode.update({"exp": expire, "jti": uuid.uuid4().hex, "iat": datetime.utcnow()})
encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM)
return encoded_jwt
def decode_access_token(token: str) -> Dict[str, Any]:
"""Decode and verify a JWT access token.
Args:
token: JWT token string
Returns:
Decoded payload dictionary
Raises:
jwt.InvalidTokenError: If token is invalid or expired
"""
return jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
def audit_log_path() -> str:
base = os.getenv("AUDIT_LOG_DIR", "audit_logs")
p = Path(base).resolve()
p.mkdir(parents=True, exist_ok=True)
now = datetime.utcnow()
month_dir = p / now.strftime("%Y%m")
month_dir.mkdir(parents=True, exist_ok=True)
return str(month_dir / f"{now.strftime('%Y-%m-%d')}.txt")
# Per-request user context for audit logging
CURRENT_USER_CTX: contextvars.ContextVar = contextvars.ContextVar("CURRENT_USER_CTX", default=None)
def set_current_user_ctx(user: dict | None) -> None:
try:
CURRENT_USER_CTX.set(user)
except Exception:
pass
def get_current_user_ctx() -> dict | None:
try:
return CURRENT_USER_CTX.get()
except Exception:
return None
+22
View File
@@ -0,0 +1,22 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
import os
# Create SQLite database in the app directory (mapped volume in Docker)
DB_FILE = os.path.join(os.path.dirname(__file__), "audit_data.db")
SQLALCHEMY_DATABASE_URL = f"sqlite:///{DB_FILE}"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
+805
View File
@@ -0,0 +1,805 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Email Notification Module for Audit Hardening Tool
Gửi email thông báo khi xử lý file hoàn tất
Hỗ trợ 2 phương thức: SMTP trực tiếp hoặc HTTP API
"""
import smtplib
import imaplib
import ssl
import os
import json
import base64
import requests
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from email.utils import formatdate
from datetime import datetime
from typing import List, Optional
from pathlib import Path
from colorama import Fore
class EmailNotifier:
"""Class xử lý gửi email thông báo"""
def __init__(self, config_path: str = "email_config.json"):
"""
Khởi tạo EmailNotifier với cấu hình từ file JSON
Args:
config_path: Đường dẫn tới file cấu hình email
"""
self.config = self._load_config(config_path)
self.enabled = self.config.get("enabled", False)
self.email_method = self.config.get("email_method", "smtp") # "smtp" hoặc "api"
def _load_config(self, config_path: str) -> dict:
"""Load cấu hình email từ file JSON"""
try:
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
print(Fore.GREEN + f"[EMAIL] Configuration loaded. Enabled: {config.get('enabled', False)}" + Fore.RESET)
return config
except FileNotFoundError:
print(Fore.YELLOW + f"[EMAIL] {config_path} not found. Email notifications disabled." + Fore.RESET)
return {"enabled": False}
except Exception as e:
print(Fore.RED + f"[EMAIL] Error loading config: {e}" + Fore.RESET)
return {"enabled": False}
def _create_email(
self,
to_emails: List[str],
subject: str,
body_html: str,
body_text: str = None,
attachments: List[str] = None
) -> MIMEMultipart:
"""
Tạo đối tượng email
Args:
to_emails: Danh sách email nhận
subject: Tiêu đề email
body_html: Nội dung HTML
body_text: Nội dung text thuần (fallback)
attachments: Danh sách file đính kèm
Returns:
MIMEMultipart object
"""
msg = MIMEMultipart('alternative')
msg['From'] = self.config.get('sender_email', '')
msg['To'] = ', '.join(to_emails)
msg['Subject'] = subject
msg['Date'] = formatdate(localtime=True)
# Thêm phần text và HTML
if body_text:
msg.attach(MIMEText(body_text, 'plain', 'utf-8'))
msg.attach(MIMEText(body_html, 'html', 'utf-8'))
# Thêm file đính kèm nếu có
if attachments and self.config.get('send_attachment', False):
for file_path in attachments:
if os.path.exists(file_path):
try:
with open(file_path, 'rb') as f:
part = MIMEBase('application', 'octet-stream')
part.set_payload(f.read())
encoders.encode_base64(part)
part.add_header(
'Content-Disposition',
f'attachment; filename="{os.path.basename(file_path)}"'
)
msg.attach(part)
except Exception as e:
print(Fore.YELLOW + f"[EMAIL] Cannot attach file {file_path}: {e}" + Fore.RESET)
return msg
def _file_to_base64(self, file_path: str) -> dict:
"""
Convert file thành base64 để gửi qua API
Args:
file_path: Đường dẫn tới file
Returns:
Dict với filename và content_base64
"""
MAX_FILE_SIZE = 100 * 1024 * 1024 # 100MB
p = Path(file_path)
size = p.stat().st_size
if size > MAX_FILE_SIZE:
print(Fore.YELLOW + f"[EMAIL] File too large for API attachment: {p.name} ({size} bytes)" + Fore.RESET)
raise ValueError(f"{p.name} too large ({size} bytes > {MAX_FILE_SIZE} bytes)")
with p.open("rb") as f:
return {
"filename": p.name,
"content_base64": base64.b64encode(f.read()).decode()
}
def _send_via_api(
self,
to_emails: List[str],
subject: str,
html_content: str,
attachments: List[str] = None
) -> bool:
"""
Gửi email qua HTTP API (giống send_mail.py)
Args:
to_emails: Danh sách email nhận
subject: Tiêu đề email
html_content: Nội dung HTML
attachments: Danh sách đường dẫn file đính kèm
Returns:
True nếu gửi thành công
"""
api_url = self.config.get('email_api_url')
api_key = self.config.get('email_api_key')
if not api_url or not api_key:
print(Fore.RED + "[EMAIL] ✗ API URL or API Key not configured in email_config.json" + Fore.RESET)
return False
# Chuẩn bị attachments base64
att_list = []
if attachments and self.config.get('send_attachment', False):
for file_path in attachments:
if os.path.exists(file_path):
try:
att_list.append(self._file_to_base64(file_path))
except Exception as e:
print(Fore.YELLOW + f"[EMAIL] Cannot attach file {file_path}: {e}" + Fore.RESET)
payload = {
"api_key": api_key,
"to_emails": to_emails,
"cc_emails": [],
"subject": subject,
"html_content": html_content,
"attachments": att_list
}
try:
print(Fore.CYAN + f"[EMAIL] Sending via API: {api_url}" + Fore.RESET)
r = requests.post(
api_url,
json=payload,
timeout=120,
verify=False
)
if not r.ok:
print(Fore.RED + f"[EMAIL] ✗ API Error: {r.status_code} - {r.text}" + Fore.RESET)
return False
print(Fore.GREEN + f"[EMAIL] ✓ API Email sent successfully to: {', '.join(to_emails)}" + Fore.RESET)
return True
except Exception as e:
print(Fore.RED + f"[EMAIL] ✗ API Request failed: {e}" + Fore.RESET)
return False
def _save_to_sent_folder(self, msg: MIMEMultipart) -> bool:
"""Lưu email vào thư mục Sent qua IMAP"""
if not self.config.get('save_to_sent', False):
return True
try:
ssl_context = ssl.create_default_context()
imap = imaplib.IMAP4_SSL(
host=self.config.get('imap_server', 'email.vnpt.vn'),
port=self.config.get('imap_port', 993),
ssl_context=ssl_context
)
imap.login(
self.config.get('sender_email', ''),
self.config.get('sender_password', '')
)
# Thử các tên thư mục Sent phổ biến
sent_folders = ['Sent', 'INBOX.Sent', 'Sent Items', 'Sent Messages']
for folder in sent_folders:
try:
status, _ = imap.select(folder)
if status == 'OK':
imap.append(folder, '\\Seen', None, msg.as_bytes())
print(Fore.CYAN + f"[EMAIL] Saved to {folder} folder" + Fore.RESET)
imap.logout()
return True
except:
continue
imap.logout()
return False
except Exception as e:
print(Fore.YELLOW + f"[EMAIL] Could not save to Sent: {e}" + Fore.RESET)
return False
def send_processing_notification(
self,
output_files: List[str],
os_type: str,
processing_time: float = None,
recipients: List[str] = None,
base_url: str = "http://localhost:8000",
system_info_list: List[dict] = None,
attachments: List[str] = None,
is_admin: bool = False
) -> bool:
"""
Gửi email thông báo khi xử lý file hoàn tất
Args:
output_files: Danh sách tên file output đã tạo
os_type: Loại hệ điều hành đã xử lý
processing_time: Thời gian xử lý (giây)
recipients: Danh sách email nhận (mặc định từ config)
base_url: URL base của ứng dụng
system_info_list: Danh sách thông tin hệ thống từ các file đã xử lý
attachments: Danh sách file đính kèm (đầy đủ đường dẫn)
is_admin: True nếu admin đăng nhập, sẽ gửi kèm file
Returns:
True nếu gửi thành công, False nếu lỗi
"""
if not self.enabled:
print(Fore.YELLOW + "[EMAIL] Email notifications are disabled" + Fore.RESET)
return False
# Sử dụng recipients mặc định nếu không được chỉ định
to_emails = recipients or self.config.get('default_recipients', [])
if not to_emails:
print(Fore.YELLOW + "[EMAIL] No recipients specified" + Fore.RESET)
return False
try:
# Tạo tiêu đề
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
subject = f"[Audit Tool] Xử lý hoàn tất - {os_type.upper()} - {len(output_files)} file(s)"
# Tạo danh sách file với link download
files_html = ""
files_text = ""
for filename in output_files:
download_url = f"{base_url}/download/{filename}"
files_html += f'<li style="margin: 8px 0;"><a href="{download_url}" style="color: #1976d2; text-decoration: none;">📊 {filename}</a></li>\n'
files_text += f" - {filename}: {download_url}\n"
# Tạo nội dung thông tin hệ thống
system_info_html = ""
system_info_text = ""
if system_info_list:
for idx, system_info in enumerate(system_info_list):
if not system_info:
continue
# Tính màu compliance
compliance_pct = system_info.get('compliance_percentage', 0)
if compliance_pct >= 80:
compliance_color = "#4caf50"
elif compliance_pct >= 50:
compliance_color = "#ff9800"
else:
compliance_color = "#f44336"
# Script version badge
script_version_html = ''
if system_info.get('script_version'):
script_version_html = f'<span style="background: #e8f5e9; color: #2e7d32; padding: 4px 10px; border-radius: 15px; font-size: 11px; font-weight: 600; margin-left: 5px;">🏷️ Script v{system_info.get("script_version")}</span>'
# Mandatory/Optional stats
mandatory_passed = system_info.get('mandatory_passed', 0)
mandatory_total = system_info.get('mandatory_total', 0)
optional_passed = system_info.get('optional_passed', 0)
optional_total = system_info.get('optional_total', 0)
# Mandatory color
if mandatory_total > 0 and mandatory_passed == mandatory_total:
mandatory_color = "#4caf50"
elif mandatory_total > 0:
mandatory_color = "#ff9800"
else:
mandatory_color = "#666"
# Optional color
if optional_total > 0 and optional_passed == optional_total:
optional_color = "#4caf50"
elif optional_total > 0:
optional_color = "#ff9800"
else:
optional_color = "#666"
# Progress bar width
progress_width = int(compliance_pct * 2) # max 200px
system_info_html += f'''
<div style="background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%); border: 1px solid #e0e0e0; border-radius: 15px; padding: 25px; margin-bottom: 20px;">
<!-- Header with hostname and OS -->
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding-bottom: 15px; border-bottom: 2px solid #e3f2fd;">
<div>
<h3 style="color: #1565c0; margin: 0; font-size: 22px;">🖥️ {system_info.get('hostname', 'Unknown Host')}</h3>
<p style="color: #666; margin: 5px 0 0 0; font-size: 14px;">{system_info.get('os_name', 'Unknown OS')}</p>
</div>
<div style="text-align: right;">
<span style="background: #e3f2fd; color: #1565c0; padding: 5px 12px; border-radius: 20px; font-size: 12px; font-weight: 600;">
{system_info.get('audit_time', '')}
</span>
{script_version_html}
</div>
</div>
<!-- Info Grid - 2 columns -->
<table style="width: 100%; border-collapse: collapse;">
<tr>
<!-- Left Column: Basic Info + Hardware -->
<td style="vertical-align: top; width: 50%; padding-right: 10px;">
<!-- Basic Info -->
<div style="background: #fff; border-radius: 10px; padding: 15px; border: 1px solid #e8e8e8; margin-bottom: 10px;">
<h4 style="color: #1976d2; margin: 0 0 12px 0; font-size: 12px; text-transform: uppercase; letter-spacing: 1px;">📋 Thông tin cơ bản</h4>
<table style="width: 100%; font-size: 12px;">
{f'<tr><td style="color: #666; padding: 4px 0;">IP Address:</td><td style="text-align: right;"><strong>{system_info.get("ip_address", "N/A")}</strong></td></tr>' if system_info.get('ip_address') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Kernel:</td><td style="text-align: right; font-size: 10px;"><strong>{system_info.get("kernel_version", "N/A")}</strong></td></tr>' if system_info.get('kernel_version') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Architecture:</td><td style="text-align: right;"><strong>{system_info.get("architecture", "N/A")}</strong></td></tr>' if system_info.get('architecture') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Uptime:</td><td style="text-align: right;"><strong>{system_info.get("uptime", "N/A")}</strong></td></tr>' if system_info.get('uptime') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Timezone:</td><td style="text-align: right;"><strong>{system_info.get("timezone", "N/A")}</strong></td></tr>' if system_info.get('timezone') else ''}
</table>
</div>
<!-- Hardware Info -->
<div style="background: #fff; border-radius: 10px; padding: 15px; border: 1px solid #e8e8e8;">
<h4 style="color: #4caf50; margin: 0 0 12px 0; font-size: 12px; text-transform: uppercase; letter-spacing: 1px;">⚙️ Phần cứng</h4>
<table style="width: 100%; font-size: 12px;">
{f'<tr><td style="color: #666; padding: 4px 0;">CPU:</td><td style="text-align: right; font-size: 10px;"><strong>{system_info.get("cpu_model", "N/A")}</strong></td></tr>' if system_info.get('cpu_model') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">CPU Cores:</td><td style="text-align: right;"><strong>{system_info.get("cpu_cores", "N/A")}</strong></td></tr>' if system_info.get('cpu_cores') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Total Memory:</td><td style="text-align: right;"><strong>{system_info.get("total_memory", "N/A")}</strong></td></tr>' if system_info.get('total_memory') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Used Memory:</td><td style="text-align: right;"><strong>{system_info.get("used_memory", "N/A")}</strong></td></tr>' if system_info.get('used_memory') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Free Memory:</td><td style="text-align: right;"><strong>{system_info.get("free_memory", "N/A")}</strong></td></tr>' if system_info.get('free_memory') else ''}
</table>
</div>
</td>
<!-- Right Column: Compliance + Network -->
<td style="vertical-align: top; width: 50%; padding-left: 10px;">
<!-- Compliance Stats -->
<div style="background: #fff; border-radius: 10px; padding: 15px; border: 1px solid #e8e8e8; text-align: center;">
<h4 style="color: #e91e63; margin: 0 0 15px 0; font-size: 12px; text-transform: uppercase; letter-spacing: 1px;">📊 Tỉ lệ tuân thủ</h4>
<!-- Compliance Percentage with progress bar -->
<div style="font-size: 36px; font-weight: bold; color: {compliance_color}; margin: 10px 0;">
{compliance_pct}%
</div>
<div style="background: #e0e0e0; border-radius: 10px; height: 10px; width: 100%; margin: 8px 0 15px 0;">
<div style="background: {compliance_color}; border-radius: 10px; height: 10px; width: {compliance_pct}%;"></div>
</div>
<!-- Mandatory / Non-Mandatory Stats -->
<table style="width: 100%; margin-top: 10px;">
<tr>
<td style="text-align: center; padding: 10px 8px; background: #e3f2fd; border-radius: 8px; width: 45%; border-left: 3px solid #1565c0;">
<div style="font-size: 10px; color: #1565c0; font-weight: 600; text-transform: uppercase; margin-bottom: 5px;">🔒 Bắt buộc đạt</div>
<div style="font-size: 20px; font-weight: bold; color: {mandatory_color};">{mandatory_passed}/{mandatory_total}</div>
{f'<div style="font-size: 11px; color: #999; margin-top: 4px;">{round((mandatory_passed / mandatory_total) * 100, 1) if mandatory_total > 0 else 0}%</div>' if mandatory_total > 0 else ''}
</td>
<td style="width: 10%;"></td>
<td style="text-align: center; padding: 10px 8px; background: #f3e5f5; border-radius: 8px; width: 45%; border-left: 3px solid #7b1fa2;">
<div style="font-size: 10px; color: #7b1fa2; font-weight: 600; text-transform: uppercase; margin-bottom: 5px;">📋 Tuỳ chọn đạt</div>
<div style="font-size: 20px; font-weight: bold; color: {optional_color};">{optional_passed}/{optional_total}</div>
</td>
</tr>
</table>
<!-- Total checks -->
<div style="margin-top: 10px; color: #666; font-size: 12px;">
Tổng số: <strong>{system_info.get('total_checks', 0)}</strong> tiêu chí
</div>
</div>
<!-- Network Info -->
<div style="background: #fff; border-radius: 10px; padding: 15px; border: 1px solid #e8e8e8; margin-top: 10px;">
<h4 style="color: #ff9800; margin: 0 0 12px 0; font-size: 12px; text-transform: uppercase; letter-spacing: 1px;">🌐 Mạng</h4>
<table style="width: 100%; font-size: 12px;">
{f'<tr><td style="color: #666; padding: 4px 0;">Interface:</td><td style="text-align: right;"><strong>{system_info.get("primary_interface", "N/A")}</strong></td></tr>' if system_info.get('primary_interface') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">MAC:</td><td style="text-align: right; font-size: 10px;"><strong>{system_info.get("mac_address", "N/A")}</strong></td></tr>' if system_info.get('mac_address') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">Gateway:</td><td style="text-align: right;"><strong>{system_info.get("default_gateway", "N/A")}</strong></td></tr>' if system_info.get('default_gateway') else ''}
{f'<tr><td style="color: #666; padding: 4px 0;">DNS:</td><td style="text-align: right;"><strong>{system_info.get("dns_servers", "N/A")}</strong></td></tr>' if system_info.get('dns_servers') else ''}
</table>
</div>
</td>
</tr>
</table>
</div>
'''
# Text version
script_ver_text = f" (Script v{system_info.get('script_version')})" if system_info.get('script_version') else ''
mandatory_pct_text = round((mandatory_passed / mandatory_total) * 100, 1) if mandatory_total > 0 else 0
system_info_text += f'''
--- Hệ thống {idx + 1}: {system_info.get('hostname', 'Unknown')}{script_ver_text} ---
OS: {system_info.get('os_name', 'N/A')}
IP: {system_info.get('ip_address', 'N/A')}
Kernel: {system_info.get('kernel_version', 'N/A')}
Architecture: {system_info.get('architecture', 'N/A')}
Uptime: {system_info.get('uptime', 'N/A')}
Timezone: {system_info.get('timezone', 'N/A')}
CPU: {system_info.get('cpu_model', 'N/A')} ({system_info.get('cpu_cores', 'N/A')} cores)
Memory: {system_info.get('total_memory', 'N/A')} (Used: {system_info.get('used_memory', 'N/A')}, Free: {system_info.get('free_memory', 'N/A')})
Interface: {system_info.get('primary_interface', 'N/A')} | MAC: {system_info.get('mac_address', 'N/A')}
Gateway: {system_info.get('default_gateway', 'N/A')} | DNS: {system_info.get('dns_servers', 'N/A')}
📊 Tỉ lệ tuân thủ: {compliance_pct}%
- 🔒 Bắt buộc đạt: {mandatory_passed}/{mandatory_total} ({mandatory_pct_text}%)
- 📋 Tuỳ chọn đạt: {optional_passed}/{optional_total}
- Tổng số: {system_info.get('total_checks', 0)} tiêu chí
'''
# ===== Tạo BẢNG TỔNG HỢP KẾT QUẢ (giống web) =====
summary_table_html = ""
if system_info_list and len([s for s in system_info_list if s]) > 0:
valid_infos = [s for s in system_info_list if s]
# Build summary table rows
summary_rows = ""
for idx_s, si in enumerate(valid_infos):
s_compliance = si.get('compliance_percentage', 0)
s_mandatory_passed = si.get('mandatory_passed', 0)
s_mandatory_total = si.get('mandatory_total', 0)
s_mandatory_failed = si.get('mandatory_failed', 0)
s_mandatory_pct = round((s_mandatory_passed / s_mandatory_total) * 100, 1) if s_mandatory_total > 0 else 0
# Compliance color
if s_compliance >= 80:
s_pct_bg = "#e8f5e9"; s_pct_color = "#2e7d32"
elif s_compliance >= 50:
s_pct_bg = "#fff3e0"; s_pct_color = "#e65100"
else:
s_pct_bg = "#ffebee"; s_pct_color = "#c62828"
# Mandatory color
if s_mandatory_failed == 0 and s_mandatory_total > 0:
s_mand_bg = "#e8f5e9"; s_mand_color = "#2e7d32"
elif s_mandatory_total > 0:
s_mand_bg = "#ffebee"; s_mand_color = "#c62828"
else:
s_mand_bg = "#f5f5f5"; s_mand_color = "#999"
# Note
if s_mandatory_failed > 0 and s_compliance < 80:
note_html = f'''
<div style="padding: 6px 10px; background: #ffebee; border-left: 3px solid #c62828; border-radius: 4px; color: #c62828; font-size: 11px; margin-bottom: 4px;">
❌ Còn <strong>{s_mandatory_failed}</strong> tiêu chí bắt buộc chưa đạt
</div>
<div style="padding: 6px 10px; background: #fff8e1; border-left: 3px solid #ffa000; border-radius: 4px; color: #e65100; font-size: 11px;">
⚠️ Tỉ lệ đạt chỉ {s_compliance}% (yêu cầu ≥80%)
</div>'''
elif s_mandatory_failed > 0:
note_html = f'''
<div style="padding: 6px 10px; background: #fff8e1; border-left: 3px solid #ffa000; border-radius: 4px; color: #e65100; font-size: 11px;">
⚠️ Còn <strong style="color: #c62828;">{s_mandatory_failed}</strong> tiêu chí bắt buộc chưa đạt
</div>'''
elif s_compliance < 80:
note_html = f'''
<div style="padding: 6px 10px; background: #fff8e1; border-left: 3px solid #ffa000; border-radius: 4px; color: #e65100; font-size: 11px;">
⚠️ Tỉ lệ đạt chỉ {s_compliance}% (yêu cầu ≥80%)
</div>'''
elif s_mandatory_total > 0:
note_html = '''
<div style="padding: 6px 10px; background: #e8f5e9; border-left: 3px solid #4caf50; border-radius: 4px; color: #2e7d32; font-size: 11px;">
✅ Đạt yêu cầu
</div>'''
else:
note_html = '<span style="color: #bbb; font-style: italic; font-size: 11px;">Không có dữ liệu</span>'
row_bg = "#fafbfc" if idx_s % 2 == 0 else "#ffffff"
summary_rows += f'''
<tr style="background: {row_bg};">
<td style="padding: 12px 14px; text-align: center; color: #666; font-weight: 500; border-bottom: 1px solid #f0f0f0;">{idx_s + 1}</td>
<td style="padding: 12px 14px; border-bottom: 1px solid #f0f0f0;">
<div style="font-weight: 600; color: #1565c0;">{si.get('hostname', 'N/A')}</div>
<div style="font-size: 11px; color: #999; margin-top: 2px;">{si.get('os_name', '')}</div>
</td>
<td style="padding: 12px 14px; color: #333; font-family: Consolas, monospace; font-size: 13px; border-bottom: 1px solid #f0f0f0;">{si.get('ip_address', 'N/A')}</td>
<td style="padding: 12px 14px; text-align: center; border-bottom: 1px solid #f0f0f0;">
<span style="display: inline-block; padding: 4px 12px; border-radius: 15px; font-weight: 700; font-size: 13px; background: {s_pct_bg}; color: {s_pct_color};">{s_compliance}%</span>
<div style="font-size: 10px; color: #999; margin-top: 3px;">{si.get('passed_count', 0)}/{si.get('total_checks', 0)} tiêu chí</div>
</td>
<td style="padding: 12px 14px; text-align: center; border-bottom: 1px solid #f0f0f0;">
<span style="display: inline-block; padding: 4px 12px; border-radius: 15px; font-weight: 700; font-size: 13px; background: {s_mand_bg}; color: {s_mand_color};">{s_mandatory_passed}/{s_mandatory_total}</span>
{f'<div style="font-size: 10px; color: #999; margin-top: 3px;">{s_mandatory_pct}%</div>' if s_mandatory_total > 0 else ''}
</td>
<td style="padding: 12px 14px; border-bottom: 1px solid #f0f0f0;">{note_html}</td>
</tr>'''
# Summary footer row (if multiple servers)
summary_footer = ""
if len(valid_infos) > 1:
total_passed_all = sum(s.get('passed_count', 0) for s in valid_infos)
total_checks_all = sum(s.get('total_checks', 0) for s in valid_infos)
avg_pct = round((total_passed_all / total_checks_all) * 100, 1) if total_checks_all > 0 else 0
total_mp = sum(s.get('mandatory_passed', 0) for s in valid_infos)
total_mt = sum(s.get('mandatory_total', 0) for s in valid_infos)
total_mf = sum(s.get('mandatory_failed', 0) for s in valid_infos)
if avg_pct >= 80:
avg_bg = "#e8f5e9"; avg_color = "#2e7d32"
elif avg_pct >= 50:
avg_bg = "#fff3e0"; avg_color = "#e65100"
else:
avg_bg = "#ffebee"; avg_color = "#c62828"
footer_note = f'<span style="color: #c62828; font-weight: 600;">⚠️ Tổng {total_mf} tiêu chí bắt buộc chưa đạt</span>' if total_mf > 0 else '<span style="color: #2e7d32; font-weight: 600;">✅ Tất cả đạt</span>'
summary_footer = f'''
<tr style="background: linear-gradient(135deg, #f5f5f5, #eeeeee); font-weight: 600;">
<td colspan="3" style="padding: 14px 16px; text-align: right; color: #555; font-size: 13px; border-top: 2px solid #e0e0e0;">
📈 Tổng hợp ({len(valid_infos)} máy chủ):
</td>
<td style="padding: 14px 16px; text-align: center; border-top: 2px solid #e0e0e0;">
<span style="display: inline-block; padding: 4px 12px; border-radius: 15px; font-weight: 700; font-size: 13px; background: {avg_bg}; color: {avg_color};">{avg_pct}%</span>
</td>
<td style="padding: 14px 16px; text-align: center; border-top: 2px solid #e0e0e0;">
<span style="font-size: 13px; color: #333;">{total_mp}/{total_mt}</span>
</td>
<td style="padding: 14px 16px; border-top: 2px solid #e0e0e0;">{footer_note}</td>
</tr>'''
summary_table_html = f'''
<h3 style="color: #1976d2; margin: 25px 0 15px 0; font-size: 18px;">📋 Bảng tổng hợp kết quả</h3>
<div style="overflow-x: auto; border-radius: 10px; border: 1px solid #e0e0e0;">
<table style="width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; border-radius: 10px; overflow: hidden;">
<thead>
<tr style="background: linear-gradient(135deg, #1565c0 0%, #1976d2 100%);">
<th style="padding: 12px 14px; color: white; font-weight: 600; text-align: center; font-size: 12px; letter-spacing: 0.5px; white-space: nowrap;">STT</th>
<th style="padding: 12px 14px; color: white; font-weight: 600; text-align: left; font-size: 12px; letter-spacing: 0.5px; white-space: nowrap;">🖥️ Tên máy chủ</th>
<th style="padding: 12px 14px; color: white; font-weight: 600; text-align: left; font-size: 12px; letter-spacing: 0.5px; white-space: nowrap;">🌐 Địa chỉ IP</th>
<th style="padding: 12px 14px; color: white; font-weight: 600; text-align: center; font-size: 12px; letter-spacing: 0.5px; white-space: nowrap;">📊 Tỉ lệ đạt</th>
<th style="padding: 12px 14px; color: white; font-weight: 600; text-align: center; font-size: 12px; letter-spacing: 0.5px; white-space: nowrap;">🔒 Bắt buộc đạt</th>
<th style="padding: 12px 14px; color: white; font-weight: 600; text-align: left; font-size: 12px; letter-spacing: 0.5px; min-width: 180px;">📝 Ghi chú</th>
</tr>
</thead>
<tbody>
{summary_rows}
</tbody>
{f"<tfoot>{summary_footer}</tfoot>" if summary_footer else ""}
</table>
</div>'''
# Tạo nội dung HTML với màu tối hơn cho chế độ sáng
body_html = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {{ font-family: 'Segoe UI', Arial, sans-serif; line-height: 1.6; color: #333333; margin: 0; padding: 0; background: #f5f5f5; }}
.container {{ max-width: 800px; margin: 0 auto; padding: 20px; }}
.header {{ background-color: #1565c0; color: #ffffff; padding: 25px; border-radius: 12px 12px 0 0; text-align: center; }}
.content {{ background: #ffffff; padding: 25px; border: 1px solid #e0e0e0; color: #333333; }}
.footer {{ background: #f8f9fa; padding: 15px; text-align: center; font-size: 12px; color: #555555; border-radius: 0 0 12px 12px; border: 1px solid #e0e0e0; border-top: none; }}
.success {{ color: #1b5e20; background: #d4edda; padding: 15px; border-radius: 8px; border-left: 4px solid #28a745; margin-bottom: 20px; }}
.info-table {{ width: 100%; border-collapse: collapse; margin: 15px 0; }}
.info-table td {{ padding: 10px 12px; border-bottom: 1px solid #eee; color: #333333; }}
.info-table td:first-child {{ font-weight: bold; width: 40%; color: #444444; }}
ul {{ margin: 10px 0; padding-left: 20px; list-style: none; }}
a {{ color: #1565c0; text-decoration: none; }}
a:hover {{ text-decoration: underline; }}
.note {{ background: #e7f3ff; border-left: 4px solid #2196F3; padding: 12px 15px; margin: 20px 0; border-radius: 5px; font-size: 13px; color: #333333; }}
h3 {{ color: #1565c0; }}
p {{ color: #333333; }}
</style>
</head>
<body style="color: #333333;">
<div class="container">
<div class="header" style="background-color: #1565c0;">
<h2 style="margin: 0; font-size: 24px; color: #ffffff !important;">🔒 Audit Hardening Tool</h2>
<p style="margin: 8px 0 0 0; font-size: 14px; color: #ffffff !important;">Thông báo xử lý hoàn tất</p>
</div>
<div class="content">
<div class="success">
<strong>✅ Xử lý file audit đã hoàn tất thành công!</strong>
</div>
<table class="info-table">
<tr><td>Hệ điều hành:</td><td>{os_type.upper()}</td></tr>
<tr><td>Số file đã tạo:</td><td>{len(output_files)} file(s)</td></tr>
<tr><td>Thời gian xử lý:</td><td>{processing_time:.2f} giây</td></tr>
<tr><td>Thời điểm:</td><td>{timestamp}</td></tr>
</table>
{summary_table_html}
{'<h3 style="color: #1976d2; margin: 25px 0 15px 0; font-size: 18px;">🖥️ Thông tin chi tiết hệ thống</h3>' + system_info_html if system_info_html else ''}
<h3 style="color: #1976d2; margin: 25px 0 15px 0; font-size: 18px;">📄 Danh sách file kết quả</h3>
<ul>
{files_html}
</ul>
<p style="margin-top: 25px; text-align: center;">
<a href="{base_url}/my_files" style="background: linear-gradient(135deg, #1976d2 0%, #1565c0 100%); color: white; padding: 12px 25px; border-radius: 8px; display: inline-block; font-weight: 600; text-decoration: none;">
📁 Xem tất cả file của tôi
</a>
</p>
</div>
<div class="footer">
<p style="margin: 0;">Email này được gửi tự động từ Audit Hardening Tool</p>
<p style="margin: 5px 0 0 0;">VNPT-MEDIA - An Toàn Thông Tin</p>
</div>
</div>
</body>
</html>
"""
# Tạo nội dung text thuần
body_text = f"""
Audit Hardening Tool - Thông báo xử lý hoàn tất
===============================================
✅ Xử lý file audit đã hoàn tất thành công!
Thông tin:
- Hệ điều hành: {os_type.upper()}
- Số file đã tạo: {len(output_files)} file(s)
- Thời gian xử lý: {processing_time:.2f} giây
- Thời điểm: {timestamp}
{system_info_text if system_info_text else ''}
Danh sách file kết quả:
{files_text}
Truy cập {base_url}/my_files để xem tất cả file của bạn.
---
Email này được gửi tự động từ Audit Hardening Tool
VNPT-MEDIA - An Toàn Thông Tin
"""
# Tạo email với file đính kèm nếu là admin
email_attachments = None
if is_admin and attachments:
email_attachments = attachments
print(Fore.CYAN + f"[EMAIL] Admin user - attaching {len(attachments)} file(s)" + Fore.RESET)
# ========== Chọn phương thức gửi email ==========
if self.email_method == 'api':
# Gửi qua HTTP API
return self._send_via_api(
to_emails=to_emails,
subject=subject,
html_content=body_html,
attachments=email_attachments
)
else:
# Gửi qua SMTP (phương thức cũ)
msg = self._create_email(
to_emails=to_emails,
subject=subject,
body_html=body_html,
body_text=body_text,
attachments=email_attachments
)
print(Fore.CYAN + f"[EMAIL] Connecting to SMTP server: {self.config.get('smtp_server')}:{self.config.get('smtp_port')}..." + Fore.RESET)
smtp = smtplib.SMTP(
self.config.get('smtp_server', 'email.vnpt.vn'),
self.config.get('smtp_port', 587),
timeout=self.config.get('timeout', 30)
)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(
self.config.get('sender_email', ''),
self.config.get('sender_password', '')
)
smtp.sendmail(
self.config.get('sender_email', ''),
to_emails,
msg.as_string()
)
smtp.quit()
print(Fore.GREEN + f"[EMAIL] ✓ Notification sent to: {', '.join(to_emails)}" + Fore.RESET)
# Lưu vào thư mục Sent
self._save_to_sent_folder(msg)
return True
except smtplib.SMTPException as e:
print(Fore.RED + f"[EMAIL] ✗ SMTP Error: {e}" + Fore.RESET)
return False
except Exception as e:
print(Fore.RED + f"[EMAIL] ✗ Error sending email: {e}" + Fore.RESET)
return False
# Global instance
_email_notifier = None
def get_email_notifier() -> EmailNotifier:
"""Lấy instance EmailNotifier (singleton pattern)"""
global _email_notifier
if _email_notifier is None:
_email_notifier = EmailNotifier()
return _email_notifier
def send_processing_complete_email(
output_files: List[str],
os_type: str,
processing_time: float = 0,
recipients: List[str] = None,
base_url: str = "http://localhost:8000",
system_info_list: List[dict] = None,
attachments: List[str] = None,
is_admin: bool = False
) -> bool:
"""
Hàm tiện ích để gửi email thông báo xử lý hoàn tất
Args:
output_files: Danh sách tên file output
os_type: Loại OS đã xử lý
processing_time: Thời gian xử lý (giây)
recipients: Email nhận (None = dùng mặc định)
base_url: URL của ứng dụng
system_info_list: Danh sách thông tin hệ thống từ các file đã xử lý
attachments: Danh sách đường dẫn file đính kèm
is_admin: True nếu admin đăng nhập
Returns:
True nếu thành công
"""
notifier = get_email_notifier()
return notifier.send_processing_notification(
output_files=output_files,
os_type=os_type,
processing_time=processing_time,
recipients=recipients,
base_url=base_url,
system_info_list=system_info_list,
attachments=attachments,
is_admin=is_admin
)
if __name__ == "__main__":
# Test gửi email
print("=" * 50)
print(" Test Email Notification")
print("=" * 50)
success = send_processing_complete_email(
output_files=["Test_Result_2025-02-03.xlsx"],
os_type="centos",
processing_time=5.23,
base_url="http://localhost:8000"
)
if success:
print("\n✅ Email sent successfully!")
else:
print("\n❌ Failed to send email")
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+59
View File
@@ -0,0 +1,59 @@
from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime
from datetime import datetime
from database import Base
class AuditRecord(Base):
__tablename__ = "audit_records"
id = Column(Integer, primary_key=True, index=True)
filename = Column(String, index=True, unique=True)
file_size = Column(Integer)
file_date = Column(String) # Stored as formatted string for simplicity: '%d/%m/%Y %H:%M'
hostname = Column(String, index=True)
ip_address = Column(String, index=True)
os_name = Column(String, index=True)
compliance_percentage = Column(Float, default=0.0)
passed_count = Column(Integer, default=0)
failed_count = Column(Integer, default=0)
total_checks = Column(Integer, default=0)
mandatory_passed = Column(Integer, default=0)
mandatory_failed = Column(Integer, default=0)
mandatory_total = Column(Integer, default=0)
mandatory_percentage = Column(Float, default=0.0)
optional_passed = Column(Integer, default=0)
optional_failed = Column(Integer, default=0)
optional_total = Column(Integer, default=0)
has_txt = Column(Boolean, default=False)
txt_filename = Column(String, default="")
created_at = Column(DateTime, default=datetime.utcnow)
class UserEmailRecord(Base):
"""Lưu trữ email người dùng (@vnpt.vn) và thống kê số file đã upload."""
__tablename__ = "user_email_records"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, index=True, unique=True) # email @vnpt.vn (unique per user)
display_name = Column(String, default="") # phần trước @, dùng để hiển thị
total_uploads = Column(Integer, default=0) # tổng số lần upload (batch)
total_files = Column(Integer, default=0) # tổng số file đã xử lý
first_seen = Column(DateTime, default=datetime.utcnow)
last_seen = Column(DateTime, default=datetime.utcnow)
class UserFileRecord(Base):
"""Lưu vết các file thuộc quyền sở hữu của user (đã đăng nhập)."""
__tablename__ = "user_file_records"
id = Column(Integer, primary_key=True, index=True)
filename = Column(String, index=True)
username = Column(String, index=True)
unit_id = Column(String, index=True)
unit_name = Column(String, index=True)
created_at = Column(DateTime, default=datetime.utcnow)
+651
View File
@@ -0,0 +1,651 @@
<!DOCTYPE html>
<html lang="vi">
<head>
<script>
var savedTheme = localStorage.getItem('audit_theme');
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.setAttribute('data-theme', 'dark');
} else {
document.documentElement.setAttribute('data-theme', 'light');
}
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="{{ url_for('icon', path='/icon.png') }}">
<title>Quản lý Công cụ - Admin - VNPT-MEDIA</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: var(--bg-main);
min-height: 100vh;
padding: 20px;
color: var(--text-main);
}
.container {
max-width: 1000px;
margin: 0 auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding: 20px;
background: var(--card-bg);
border-radius: 15px;
backdrop-filter: blur(10px);
}
.header h1 {
color: var(--text-main);
font-size: 24px;
}
.header-actions {
display: flex;
gap: 10px;
}
.btn {
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
cursor: pointer;
border: none;
font-size: 14px;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1);
color: white;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.2);
}
.btn-danger {
background: #e74c3c;
color: white;
}
.btn-danger:hover {
background: #c0392b;
}
.card {
background: var(--card-bg);
border-radius: 15px;
padding: 25px;
margin-bottom: 20px;
backdrop-filter: blur(10px);
border: 1px solid var(--border-color);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border-color);
}
.card-title {
font-size: 18px;
color: var(--text-main);
}
.tools-table {
width: 100%;
border-collapse: collapse;
}
.tools-table th,
.tools-table td {
padding: 15px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.tools-table th {
color: var(--text-muted);
font-weight: 500;
font-size: 13px;
text-transform: uppercase;
}
.tools-table tr:hover {
background: var(--card-bg);
}
.status-badge {
display: inline-block;
padding: 5px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
.status-available {
background: rgba(46, 204, 113, 0.2);
color: #2ecc71;
}
.status-unavailable {
background: rgba(231, 76, 60, 0.2);
color: #e74c3c;
}
.os-icon {
font-size: 20px;
margin-right: 8px;
}
/* Upload Form */
.upload-form {
background: var(--table-row-hover);
border: 2px dashed var(--border-color);
border-radius: 15px;
padding: 30px;
text-align: center;
transition: all 0.3s ease;
}
.upload-form:hover {
border-color: #667eea;
background: var(--empty-state-bg);
}
.upload-form.dragover {
border-color: #667eea;
background: var(--hover-bg);
}
.form-group {
margin-bottom: 20px;
text-align: left;
}
.form-group label {
display: block;
margin-bottom: 8px;
color: var(--text-muted);
font-size: 13px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 12px 15px;
border-radius: 8px;
border: 1px solid var(--input-border);
background: var(--card-bg);
color: var(--text-main);
font-size: 14px;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: #667eea;
}
.form-group select option {
background: var(--input-bg);
color: var(--input-text);
padding: 10px;
}
.form-group input[type="file"] {
padding: 10px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.alert {
padding: 15px 20px;
border-radius: 10px;
margin-bottom: 20px;
}
.alert-success {
background: rgba(46, 204, 113, 0.2);
color: #2ecc71;
border: 1px solid rgba(46, 204, 113, 0.3);
}
.alert-error {
background: rgba(231, 76, 60, 0.2);
color: #e74c3c;
border: 1px solid rgba(231, 76, 60, 0.3);
}
.empty-state {
text-align: center;
padding: 40px;
color: var(--text-muted);
}
.empty-state-icon {
font-size: 48px;
margin-bottom: 15px;
}
@media (max-width: 768px) {
.form-row {
grid-template-columns: 1fr;
}
.header {
flex-direction: column;
gap: 15px;
}
.tools-table {
font-size: 13px;
}
.tools-table th,
.tools-table td {
padding: 10px;
}
}
</style>
</head>
<body>
{% include 'header.html' %}
<div class="container">
<!-- Top Navigation Tabs -->
<div class="top-nav-tabs"
style="display: flex; justify-content: center; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; background: rgba(25, 118, 210, 0.05); padding: 15px; border-radius: 12px; border: 1px solid rgba(25, 118, 210, 0.1);">
<a href="{{ url_for('index') }}" class="nav-tab"
style="padding: 10px 20px; background: var(--card-bg); color: var(--text-main); text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 14px; transition: all 0.3s ease; border: 1px solid var(--border-color); box-shadow: 0 2px 5px rgba(0,0,0,0.05);">🏠 Trang chủ</a>
<a href="{{ url_for('my_files') }}" class="nav-tab"
style="padding: 10px 20px; background: var(--card-bg); color: var(--text-main); text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 14px; transition: all 0.3s ease; border: 1px solid var(--border-color); box-shadow: 0 2px 5px rgba(0,0,0,0.05);">📁 File của tôi</a>
{% if user_info and user_info.role == 'admin' %}
<a href="{{ url_for('admin_tools') }}" class="nav-tab"
style="padding: 10px 20px; background: linear-gradient(135deg, #1976d2 0%, #1565c0 100%); color: white; text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 14px; transition: all 0.3s ease; box-shadow: 0 4px 10px rgba(25, 118, 210, 0.3);">⚙️ Quản trị</a>
{% endif %}
</div>
{% if user_info and user_info.role == 'admin' %}
<!-- Admin Sub Navigation Tabs (Dark mode style) -->
<div class="admin-sub-tabs"
style="display: flex; justify-content: center; gap: 8px; margin-bottom: 25px; flex-wrap: wrap;">
<a href="{{ url_for('admin_tools') }}" class="sub-tab"
style="padding: 8px 16px; background: #667eea; color: white; text-decoration: none; border-radius: 20px; font-weight: 600; font-size: 13px; transition: all 0.3s ease; box-shadow: 0 2px 5px rgba(102, 126, 234, 0.3);">🔧 Cài đặt chung</a>
<a href="{{ url_for('admin_users_page') }}" class="sub-tab"
style="padding: 8px 16px; background: rgba(255, 255, 255, 0.1); color: var(--text-main); text-decoration: none; border-radius: 20px; font-weight: 600; font-size: 13px; transition: all 0.3s ease; border: 1px solid var(--input-border);">👥 Người dùng & Đơn vị</a>
<a href="{{ url_for('list_outputs') }}" class="sub-tab"
style="padding: 8px 16px; background: rgba(255, 255, 255, 0.1); color: var(--text-main); text-decoration: none; border-radius: 20px; font-weight: 600; font-size: 13px; transition: all 0.3s ease; border: 1px solid var(--input-border);">📂 Tất cả File</a>
<a href="{{ url_for('server_stats_page') }}" class="sub-tab"
style="padding: 8px 16px; background: rgba(255, 255, 255, 0.1); color: var(--text-main); text-decoration: none; border-radius: 20px; font-weight: 600; font-size: 13px; transition: all 0.3s ease; border: 1px solid var(--input-border);">📊 Thống kê</a>
</div>
{% endif %}
<div class="header">
<h1>🔧 Quản lý Công cụ Đánh giá</h1>
<div class="header-actions">
<a href="{{ url_for('index') }}" class="btn btn-secondary">← Về trang chủ</a>
</div>
</div>
{% if message %}
<div class="alert alert-{{ message.type }}">
{{ message.text }}
</div>
{% endif %}
<!-- Upload New Tool -->
<div class="card">
<div class="card-header">
<h2 class="card-title">📤 Tải lên Công cụ mới</h2>
</div>
<form action="tools/upload" method="post" enctype="multipart/form-data" class="upload-form" id="uploadForm">
<div class="form-row">
<div class="form-group">
<label>Hệ điều hành *</label>
<select name="os_type" required>
<option value="">-- Chọn OS --</option>
{% for os_key, meta in os_metadata.items() %}
<option value="{{ os_key }}">{{ meta.icon }} {{ meta.display_name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>Phiên bản OS (vd: 22.04, 24.04, 2019) *</label>
<input type="text" name="os_version_label" placeholder="22.04" required>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Tên công cụ *</label>
<input type="text" name="tool_name" placeholder="Ubuntu 22.04 Hardening" required>
</div>
<div class="form-group">
<label>Phiên bản script (vd: v2.0.0) *</label>
<input type="text" name="version" placeholder="v2.0.0" required>
</div>
</div>
<div class="form-row">
<div class="form-group" style="grid-column: 1 / -1;">
<label>File công cụ (.sh, .py, .ps1, .zip) *</label>
<input type="file" name="tool_file" accept=".sh,.py,.ps1,.zip,.tar.gz" required>
</div>
</div>
<button type="submit" class="btn btn-primary">⬆️ Tải lên</button>
</form>
</div>
<!-- Current Tools -->
<div class="card">
<div class="card-header">
<h2 class="card-title">📦 Công cụ hiện có</h2>
</div>
{% if tools_list %}
<table class="tools-table">
<thead>
<tr>
<th>Hệ điều hành</th>
<th>Phiên bản OS</th>
<th>Tên công cụ</th>
<th>Script ver.</th>
<th>Cập nhật</th>
<th>Trạng thái</th>
<th>Thao tác</th>
</tr>
</thead>
<tbody>
{% for tool in tools_list %}
<tr>
<td><span class="os-icon">{{ tool.icon }}</span>{{ tool.display_name }}</td>
<td>{{ tool.os_version_label or '-' }}</td>
<td>{{ tool.name }}</td>
<td><code>{{ tool.version }}</code></td>
<td>{{ tool.updated }}</td>
<td>
{% if tool.available %}
<span class="status-badge status-available">✓ Có sẵn</span>
{% else %}
<span class="status-badge status-unavailable">✗ Chưa có</span>
{% endif %}
</td>
<td style="white-space: nowrap;">
{% if tool.available %}
<div style="display: inline-flex; gap: 6px; align-items: center;">
<a href="{{ url_for('download_tool', version_key=tool.version_key) }}"
class="btn btn-secondary" style="padding: 5px 10px; font-size: 12px; white-space: nowrap;">⬇️ Tải</a>
<form action="tools/delete/{{ tool.version_key }}" method="post" style="display: inline; margin: 0;"
onsubmit="return confirm('Bạn có chắc muốn xóa công cụ này?')">
<button type="submit" class="btn btn-danger"
style="padding: 5px 10px; font-size: 12px; white-space: nowrap;">🗑️ Xóa</button>
</form>
</div>
{% else %}
<span style="color: var(--text-muted);">-</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="empty-state">
<div class="empty-state-icon">📭</div>
<p>Chưa có công cụ nào được tải lên.</p>
</div>
{% endif %}
</div>
<!-- Upload Documentation Form -->
<div class="card">
<div class="card-header">
<h2 class="card-title">⬆️ Tải lên Tài liệu Cấu hình mới</h2>
</div>
<form action="{{ url_for('admin_docs_upload') }}" method="post" enctype="multipart/form-data">
<div class="form-row">
<div class="form-group">
<label>Tên tài liệu *</label>
<input type="text" name="doc_name" placeholder="VD: Hướng dẫn Hardening OS" required>
</div>
<div class="form-group">
<label>Phiên bản tài liệu (vd: v1.0) *</label>
<input type="text" name="doc_version" placeholder="v1.0" value="v1.0" required>
</div>
</div>
<div class="form-row">
<div class="form-group" style="grid-column: 1 / -1;">
<label>File tài liệu (.pdf, .docx, .xlsx, .zip) *</label>
<input type="file" name="doc_file" required>
</div>
</div>
<button type="submit" class="btn btn-primary">⬆️ Tải lên Tài liệu</button>
</form>
</div>
<!-- Current Documentation -->
<div class="card">
<div class="card-header">
<h2 class="card-title">📚 Quản lý Tài liệu Cấu hình hiện có</h2>
</div>
{% if docs_list %}
<table class="tools-table">
<thead>
<tr>
<th>Tên tài liệu</th>
<th>Tên file</th>
<th>Phiên bản</th>
<th>Kích thước</th>
<th>Cập nhật</th>
<th>Trạng thái</th>
<th>Thao tác</th>
</tr>
</thead>
<tbody>
{% for doc in docs_list %}
<tr>
<td><strong>📄 {{ doc.name }}</strong></td>
<td><code>{{ doc.file }}</code></td>
<td><code>{{ doc.version }}</code></td>
<td>{{ doc.size }}</td>
<td>{{ doc.updated }}</td>
<td>
{% if doc.available %}
<span class="status-badge status-available">✓ Có sẵn</span>
{% else %}
<span class="status-badge status-unavailable">✗ Lỗi file</span>
{% endif %}
</td>
<td style="white-space: nowrap;">
{% if doc.available %}
<div style="display: inline-flex; gap: 6px; align-items: center;">
<a href="{{ url_for('download_doc', doc_key=doc.doc_key) }}"
class="btn btn-secondary" style="padding: 5px 10px; font-size: 12px; white-space: nowrap;">⬇️ Tải</a>
<form action="{{ url_for('admin_docs_delete', doc_key=doc.doc_key) }}" method="post" style="display: inline; margin: 0;"
onsubmit="return confirm('Bạn có chắc muốn xóa tài liệu này?')">
<button type="submit" class="btn btn-danger"
style="padding: 5px 10px; font-size: 12px; white-space: nowrap;">🗑️ Xóa</button>
</form>
</div>
{% else %}
<form action="{{ url_for('admin_docs_delete', doc_key=doc.doc_key) }}" method="post" style="display: inline; margin: 0;"
onsubmit="return confirm('Bạn có chắc muốn xóa bản ghi này?')">
<button type="submit" class="btn btn-danger"
style="padding: 5px 10px; font-size: 12px; white-space: nowrap;">🗑️ Xóa</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="empty-state">
<div class="empty-state-icon">📭</div>
<p>Chưa có tài liệu cấu hình nào được tải lên.</p>
</div>
{% endif %}
</div>
<!-- Email Notification Settings -->
<div class="card">
<div class="card-header">
<h2 class="card-title">⚙️ Cài đặt Hệ thống</h2>
</div>
<div style="display: flex; align-items: flex-start; gap: 30px; flex-wrap: wrap;">
<!-- Email Toggle Block -->
<div style="flex: 1; min-width: 280px;">
<p style="color: var(--text-muted); font-size: 13px; margin-bottom: 15px;">
Bật / Tắt chức năng gửi email thông báo khi xử lý file hoàn tất.
</p>
{% if not email_module_available %}
<!-- Module không có sẵn -->
<div style="display: flex; align-items: center; gap: 15px; padding: 18px 20px; background: rgba(231,76,60,0.12); border: 1px solid rgba(231,76,60,0.3); border-radius: 12px;">
<span style="font-size: 32px;">📧</span>
<div>
<div style="font-weight: 600; font-size: 15px; color: #e74c3c;">Không khả dụng</div>
<div style="font-size: 12px; color: var(--text-muted); margin-top: 4px;">
Module <code style="background: rgba(255,255,255,0.1); padding: 1px 6px; border-radius: 4px;">email_notifier</code> chưa được cài đặt trên server này.
</div>
</div>
</div>
{% elif email_enabled %}
<!-- Module có, đang BẬT -->
<div style="display: flex; align-items: center; gap: 15px; padding: 18px 20px; background: rgba(46,204,113,0.12); border: 1px solid rgba(46,204,113,0.3); border-radius: 12px; margin-bottom: 15px;">
<span style="font-size: 32px;"></span>
<div>
<div style="font-weight: 600; font-size: 15px; color: #2ecc71;">Đang BẬT</div>
<div style="font-size: 12px; color: var(--text-muted); margin-top: 4px;">
Hệ thống sẽ gửi email thông báo sau mỗi lần xử lý file thành công.
</div>
</div>
</div>
<form action="email/disable" method="post">
<button type="submit" class="btn btn-danger" style="width: 100%;">
🔕 Tắt gửi Email
</button>
</form>
{% else %}
<!-- Module có, đang TẮT -->
<div style="display: flex; align-items: center; gap: 15px; padding: 18px 20px; background: var(--card-bg); border: 1px solid rgba(255,255,255,0.15); border-radius: 12px; margin-bottom: 15px;">
<span style="font-size: 32px;">🔕</span>
<div>
<div style="font-weight: 600; font-size: 15px; color: var(--text-muted);">Đang TẮT</div>
<div style="font-size: 12px; color: var(--text-muted); margin-top: 4px;">
Không gửi email sau khi xử lý. Nhấn bên dưới để bật.
</div>
</div>
</div>
<form action="email/enable" method="post">
<button type="submit" class="btn btn-primary" style="width: 100%;">
📧 Bật gửi Email
</button>
</form>
{% endif %}
<p style="margin-top: 12px; font-size: 11px; color: #666; font-style: italic;">
⚠️ Lưu ý: cài đặt này chỉ giữ trong phiên chạy hiện tại. Khi khởi động lại server, email sẽ trở về trạng thái <strong>TẮT</strong>.
</p>
</div>
</div>
</div>
<!-- User Email Stats -->
<div class="card">
<div class="card-header">
<h2 class="card-title">👥 Thống kê Người dùng (VNPT Email)</h2>
</div>
{% if email_stats and email_stats|length > 0 %}
<div style="overflow-x: auto;">
<table class="tools-table">
<thead>
<tr>
<th>Người dùng</th>
<th>Email</th>
<th>Số lần Upload</th>
<th>Tổng File</th>
<th>Lần đầu</th>
<th>Gần nhất</th>
</tr>
</thead>
<tbody>
{% for stat in email_stats %}
<tr>
<td style="font-weight: 600; color: var(--text-main);">{{ stat.display_name }}</td>
<td style="color: #90caf9;">{{ stat.email }}</td>
<td><span class="status-badge" style="background: rgba(102,126,234,0.2); color: #8ba4f9;">{{ stat.total_uploads }}</span></td>
<td><span class="status-badge status-available">{{ stat.total_files }}</span></td>
<td style="font-size: 13px; color: var(--text-muted);">{{ stat.first_seen }}</td>
<td style="font-size: 13px; color: var(--text-muted);">{{ stat.last_seen }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
<div class="empty-state-icon">📭</div>
<p>Chưa có dữ liệu thống kê từ người dùng.</p>
</div>
{% endif %}
</div>
</div>
<script>
// Drag and drop support
const uploadForm = document.getElementById('uploadForm');
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
uploadForm.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
uploadForm.addEventListener(eventName, () => uploadForm.classList.add('dragover'), false);
});
['dragleave', 'drop'].forEach(eventName => {
uploadForm.addEventListener(eventName, () => uploadForm.classList.remove('dragover'), false);
});
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
+225
View File
@@ -0,0 +1,225 @@
<script>
// Theme initialization (Anti-FOUC)
(function() {
var savedTheme = localStorage.getItem('audit_theme');
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.setAttribute('data-theme', 'dark');
} else {
document.documentElement.setAttribute('data-theme', 'light');
}
})();
</script>
<style>
:root {
--bg-main: #f4f6f9;
--card-bg: #ffffff;
--text-main: #2b3445;
--text-muted: #7d879c;
--border-color: #e3e9ef;
--border-color-light: #f1f5f9;
--primary-color: #1976d2;
--hover-bg: #f8f9fa;
--input-bg: #ffffff;
--input-text: #2b3445;
--input-border: #ced4da;
--sub-tab-bg: #e3f2fd;
--sub-tab-text: #1565c0;
--sub-tab-border: #bbdefb;
--sub-tab-active-bg: #1565c0;
--sub-tab-active-text: #ffffff;
--empty-state-bg: #f8f9fa;
--table-header-bg: #f1f5f9;
--table-header-text: #475569;
--table-row-hover: #f8fafc;
--table-border: #e2e8f0;
--modal-bg: #ffffff;
--shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
--success-color: #2e7d32;
--success-bg: #e8f5e9;
--danger-color: #c62828;
--danger-bg: #ffebee;
--warning-color: #e65100;
--warning-bg: #fff3e0;
--info-color: #0277bd;
--info-bg: #e1f5fe;
}
[data-theme="dark"] {
--bg-main: #0f172a;
--card-bg: #1e293b;
--text-main: #f1f5f9;
--text-muted: #94a3b8;
--border-color: #334155;
--border-color-light: #1e293b;
--primary-color: #3b82f6;
--hover-bg: #334155;
--input-bg: #0f172a;
--input-text: #f1f5f9;
--input-border: #475569;
--sub-tab-bg: #1e293b;
--sub-tab-text: #e2e8f0;
--sub-tab-border: #334155;
--sub-tab-active-bg: #3b82f6;
--sub-tab-active-text: #ffffff;
--empty-state-bg: #1e293b;
--table-header-bg: #334155;
--table-header-text: #e2e8f0;
--table-row-hover: #1e293b;
--table-border: #334155;
--modal-bg: #1e293b;
--shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
--success-color: #4caf50;
--success-bg: rgba(76, 175, 80, 0.1);
--danger-color: #ef5350;
--danger-bg: rgba(244, 67, 54, 0.1);
--warning-color: #ff9800;
--warning-bg: rgba(255, 152, 0, 0.1);
--info-color: #29b6f6;
--info-bg: rgba(3, 169, 244, 0.1);
}
.global-header {
width: 100%;
background: linear-gradient(135deg, #1565c0 0%, #0d47a1 100%);
color: white;
padding: 10px 20px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
position: fixed;
top: 0;
left: 0;
z-index: 1000;
}
/* Đẩy toàn bộ nội dung body xuống để không bị header che mất */
body {
margin-top: 60px !important;
background-color: var(--bg-main);
color: var(--text-main);
transition: background-color 0.3s ease, color 0.3s ease;
}
.header-logo {
font-weight: 700;
font-size: 18px;
display: flex;
align-items: center;
gap: 10px;
}
.header-logo span {
background: rgba(255, 255, 255, 0.2);
padding: 3px 8px;
border-radius: 5px;
font-size: 14px;
letter-spacing: 1px;
}
.header-user-info {
display: flex;
align-items: center;
gap: 15px;
font-size: 14px;
}
.header-user-details {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.header-user-name {
font-weight: 600;
}
.header-user-role {
font-size: 12px;
color: #bbdefb;
}
.header-action-btn {
background: rgba(255, 255, 255, 0.1);
color: white;
text-decoration: none;
padding: 6px 15px;
border-radius: 5px;
font-weight: 600;
transition: background 0.3s;
border: 1px solid rgba(255, 255, 255, 0.3);
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
}
.header-action-btn:hover {
background: rgba(255, 255, 255, 0.2);
color: white;
}
.theme-toggle-btn {
padding: 6px 10px;
font-size: 16px;
}
.header-guest {
background: rgba(255, 255, 255, 0.1);
padding: 6px 15px;
border-radius: 5px;
font-size: 14px;
}
</style>
<div class="global-header">
<div class="header-logo">
🛡️ Audit Hardening Tool <span>VNPT-MEDIA</span>
</div>
<div class="header-user-info">
<button id="themeToggleBtn" class="header-action-btn theme-toggle-btn" title="Chuyển đổi giao diện Sáng/Tối">
<span id="themeIcon">🌞</span>
</button>
{% if is_logged_in and user_info %}
<div class="header-user-details">
<span class="header-user-name">👤 {{ user_info.full_name or user_info.username }}</span>
{% if user_info.role %}
<span class="header-user-role">{{ user_info.role|upper }} {% if user_info.unit_name %} | {{ user_info.unit_name }}{% endif %}</span>
{% endif %}
</div>
<a href="{{ url_for('logout') }}" class="header-action-btn">🚪 Đăng xuất</a>
{% else %}
<div class="header-guest">
👤 Khách
</div>
{% endif %}
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
const toggleBtn = document.getElementById('themeToggleBtn');
const themeIcon = document.getElementById('themeIcon');
function updateIcon() {
if (document.documentElement.getAttribute('data-theme') === 'dark') {
themeIcon.textContent = '🌙';
} else {
themeIcon.textContent = '🌞';
}
}
updateIcon();
toggleBtn.addEventListener('click', function() {
let currentTheme = document.documentElement.getAttribute('data-theme');
let newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('audit_theme', newTheme);
updateIcon();
});
});
</script>
File diff suppressed because it is too large Load Diff
+599
View File
@@ -0,0 +1,599 @@
<!DOCTYPE html>
<html lang="vi">
<head>
<script>
var savedTheme = localStorage.getItem('audit_theme');
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.setAttribute('data-theme', 'dark');
} else {
document.documentElement.setAttribute('data-theme', 'light');
}
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="{{ url_for('icon', path='/icon.png') }}">
<title>Đăng nhập - Công cụ Kiểm tra Hardening - VNPT-MEDIA</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg-main: #f4f6f9;
--card-bg: #ffffff;
--text-main: #2b3445;
--text-muted: #7d879c;
--border-color: #e3e9ef;
--border-color-light: #f1f5f9;
--primary-color: #1976d2;
--hover-bg: #f8f9fa;
--input-bg: #ffffff;
--input-text: #2b3445;
--input-border: #ced4da;
--empty-state-bg: #f8f9fa;
--success-color: #2e7d32;
--success-bg: #e8f5e9;
--danger-color: #c62828;
--danger-bg: #ffebee;
--warning-color: #e65100;
--warning-bg: #fff3e0;
--info-color: #0277bd;
--info-bg: #e1f5fe;
}
[data-theme="dark"] {
--bg-main: #0f172a;
--card-bg: #1e293b;
--text-main: #f1f5f9;
--text-muted: #94a3b8;
--border-color: #334155;
--border-color-light: #1e293b;
--primary-color: #3b82f6;
--hover-bg: #334155;
--input-bg: #0f172a;
--input-text: #f1f5f9;
--input-border: #475569;
--empty-state-bg: #1e293b;
--success-color: #4caf50;
--success-bg: rgba(76, 175, 80, 0.1);
--danger-color: #ef5350;
--danger-bg: rgba(244, 67, 54, 0.1);
--warning-color: #ff9800;
--warning-bg: rgba(255, 152, 0, 0.1);
--info-color: #29b6f6;
--info-bg: rgba(3, 169, 244, 0.1);
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: var(--bg-main);
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
padding: 20px 10px;
position: relative;
overflow-x: hidden;
overflow-y: auto;
}
body::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background:
linear-gradient(135deg, transparent 0%, transparent 48%, rgba(33, 150, 243, 0.05) 48%, rgba(33, 150, 243, 0.05) 52%, transparent 52%, transparent 100%),
linear-gradient(45deg, transparent 0%, transparent 48%, rgba(33, 150, 243, 0.08) 48%, rgba(33, 150, 243, 0.08) 52%, transparent 52%, transparent 100%),
linear-gradient(135deg, transparent 0%, transparent 48%, rgba(33, 150, 243, 0.03) 48%, rgba(33, 150, 243, 0.03) 52%, transparent 52%, transparent 100%);
background-size: 300px 300px, 400px 400px, 500px 500px;
background-position: 0 0, 100px 100px, 200px 0;
z-index: 0;
pointer-events: none;
}
body::after {
content: '';
position: absolute;
top: 0;
right: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0 400px 400px 0;
border-color: transparent rgba(33, 150, 243, 0.03) transparent transparent;
z-index: 0;
pointer-events: none;
}
.menu-icon {
position: absolute;
top: 20px;
right: 20px;
width: 40px;
height: 40px;
display: flex;
flex-direction: column;
justify-content: space-around;
cursor: pointer;
padding: 8px;
}
.menu-icon span {
width: 100%;
height: 3px;
background: #1976d2;
border-radius: 2px;
}
.login-container {
background: var(--card-bg);
border-radius: 15px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
padding: 50px 55px;
width: 100%;
max-width: 480px;
position: relative;
z-index: 1;
}
.logo {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
gap: 0;
margin-bottom: 35px;
padding-bottom: 20px;
border-bottom: 2px solid var(--sub-tab-border);
}
.logo img {
width: 65px;
height: 65px;
object-fit: contain;
flex-shrink: 0;
}
.logo-text {
flex: 1;
font-size: 30px;
font-weight: 800;
color: var(--primary-color);
letter-spacing: 0.35em;
text-align: center;
white-space: nowrap;
padding-right: 0.35em; /* compensate last letter-spacing */
}
.logo-icon {
display: inline-block;
width: 60px;
height: 60px;
background: #1976d2;
border-radius: 50% 0 50% 50%;
position: relative;
margin-right: 10px;
vertical-align: middle;
}
.logo-icon::after {
content: '';
position: absolute;
width: 30px;
height: 30px;
background: var(--card-bg);
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.form-group {
margin-bottom: 20px;
}
.form-group input {
width: 100%;
padding: 14px 18px;
background-color: var(--input-bg);
color: var(--text-main);
border: 1px solid var(--input-border);
border-radius: 6px;
font-size: 15px;
transition: border-color 0.3s;
}
.form-group input:focus {
outline: none;
border-color: var(--primary-color);
}
.form-group input::placeholder {
color: var(--text-muted);
}
.password-wrapper {
position: relative;
}
.password-wrapper input {
padding-right: 45px;
}
.password-toggle {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
color: var(--text-muted);
font-size: 18px;
}
.btn-login {
width: 100%;
padding: 14px;
background: #1976d2;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: background 0.3s;
text-transform: uppercase;
letter-spacing: 1px;
white-space: nowrap;
}
.btn-login:hover {
background: #1565c0;
}
/* SSO Portal Button */
.sso-divider {
display: flex;
align-items: center;
gap: 12px;
margin: 20px 0;
color: var(--text-muted);
font-size: 13px;
}
.sso-divider::before,
.sso-divider::after {
content: '';
flex: 1;
height: 1px;
background-color: var(--border-color);
}
.btn-sso {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #0d47a1, #1976d2);
color: white;
border: none;
border-radius: 6px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
letter-spacing: 0.5px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
text-decoration: none;
}
.btn-sso:hover {
background: linear-gradient(135deg, #1565c0, #1e88e5);
box-shadow: 0 4px 15px rgba(25, 118, 210, 0.4);
transform: translateY(-1px);
}
.sso-info {
margin-top: 10px;
padding: 10px 14px;
background-color: var(--info-bg);
border-radius: 6px;
border-left: 3px solid #1976d2;
font-size: 12px;
color: var(--primary-color);
line-height: 1.6;
}
.help-text {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
font-size: 12px;
color: var(--text-muted);
line-height: 1.8;
}
.help-text a {
color: var(--primary-color);
text-decoration: none;
}
.help-text a:hover {
text-decoration: underline;
}
.help-text strong {
color: var(--danger-color);
}
.footer {
position: absolute;
bottom: 20px;
text-align: center;
color: var(--primary-color);
font-size: 13px;
z-index: 1;
}
.footer strong {
color: var(--danger-color);
}
.alert {
padding: 12px;
border-radius: 5px;
margin-bottom: 20px;
font-size: 14px;
}
.alert-error {
background-color: var(--danger-bg);
color: var(--danger-color);
border: 1px solid #ef9a9a;
}
.alert-success {
background-color: var(--success-bg);
color: var(--success-color);
border: 1px solid #a5d6a7;
}
/* Responsive Styles */
@media screen and (max-width: 768px) {
.login-container {
padding: 30px 25px;
}
.logo-text {
font-size: 38px;
letter-spacing: 5px;
}
.logo-icon {
width: 50px;
height: 50px;
}
.logo-icon::after {
width: 25px;
height: 25px;
}
.footer {
position: relative;
bottom: auto;
margin-top: 20px;
}
}
@media screen and (max-width: 480px) {
body {
padding: 10px 5px;
}
.login-container {
padding: 25px 20px;
border-radius: 12px;
}
.logo {
margin-bottom: 25px;
}
.logo-text {
font-size: 32px;
letter-spacing: 4px;
}
.logo-icon {
width: 40px;
height: 40px;
}
.logo-icon::after {
width: 20px;
height: 20px;
}
.form-group input {
padding: 10px 12px;
font-size: 13px;
}
.btn-login {
padding: 10px;
font-size: 14px;
}
.btn-guest {
padding: 10px;
font-size: 13px;
}
.help-text {
font-size: 11px;
margin-top: 20px;
padding-top: 15px;
}
.footer {
font-size: 11px;
position: relative;
bottom: auto;
margin-top: 15px;
}
.menu-icon {
top: 10px;
right: 10px;
width: 35px;
height: 35px;
}
}
</style>
</head>
<body>
<div class="menu-icon">
<span></span>
<span></span>
<span></span>
</div>
<div class="login-container">
<div class="logo">
<img src="{{ url_for('icon', path='/icon.png') }}" alt="VNPT-MEDIA Logo">
<span class="logo-text">VNPT-MEDIA</span>
</div>
{% if message %}
<div class="alert alert-{{ message.type }}">
{{ message.text }}
</div>
{% endif %}
<form method="post" action="login" id="loginForm">
<div class="form-group">
<div style="position: relative;">
<input
type="email"
id="emailInput"
name="username"
placeholder="ten.nv@vnpt.vn"
required
autocomplete="email"
style="padding-left: 44px;"
oninput="validateEmailDomain(this)"
>
<span style="position:absolute;left:14px;top:50%;transform:translateY(-50%);font-size:17px;pointer-events:none;">✉️</span>
</div>
<div id="emailHint" style="margin-top:6px;font-size:12px;color: var(--danger-color);display:none;">
⚠️ Vui lòng nhập email có đuôi <strong>@vnpt.vn</strong>
</div>
</div>
<div class="form-group">
<div class="password-wrapper">
<input type="password" id="password" name="password" placeholder="Mật khẩu" required autocomplete="current-password">
<span class="password-toggle" onclick="togglePassword()">👁</span>
</div>
</div>
<div class="form-group">
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: nowrap;">
<span style="font-size: 14px; color: var(--text-muted); white-space: nowrap;">🔐 Mã xác thực 2FA (OTP)</span>
<span style="
background: linear-gradient(135deg, #1565c0, #1976d2);
color: white;
padding: 2px 10px;
border-radius: 10px;
font-size: 11px;
font-weight: 600;
white-space: nowrap;
flex-shrink: 0;
">RADIUS</span>
</div>
<input type="text" name="otp" id="otp"
maxlength="6" pattern="[0-9]*" inputmode="numeric"
autocomplete="one-time-code"
style="letter-spacing: 8px; text-align: center; font-size: 18px; font-weight: 600;">
</div>
<button type="submit" class="btn-login">🔑 Đăng nhập qua RADIUS</button>
</form>
{% if sso_enabled %}
<div class="sso-divider">hoặc</div>
<div style="text-align:center; margin-bottom: 10px;">
<div class="sso-info">
🌐 <strong>Đăng nhập qua SSO Portal:</strong><br>
Truy cập hệ thống bằng tài khoản tập đoàn VNPT-MEDIA.<br>
SSO Portal sẽ tự động chuyển hướng bạn về đây sau khi xác thực.
</div>
</div>
{% endif %}
</div>
<script>
function togglePassword() {
const passwordInput = document.getElementById('password');
const toggle = document.querySelector('.password-toggle');
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
toggle.textContent = '🙈';
} else {
passwordInput.type = 'password';
toggle.textContent = '👁';
}
}
// Validate domain @vnpt.vn khi người dùng gõ
function validateEmailDomain(input) {
const hint = document.getElementById('emailHint');
const val = input.value.trim().toLowerCase();
// Chỉ hiện cảnh báo khi người dùng đã gõ @ nhưng domain sai
if (val.includes('@') && !val.endsWith('@vnpt.vn')) {
hint.style.display = 'block';
input.style.borderColor = '#e53935';
} else {
hint.style.display = 'none';
input.style.borderColor = '';
}
}
// Chặn submit nếu domain sai
document.getElementById('loginForm').addEventListener('submit', function(e) {
const emailVal = document.getElementById('emailInput').value.trim().toLowerCase();
if (!emailVal.endsWith('@vnpt.vn')) {
e.preventDefault();
document.getElementById('emailHint').style.display = 'block';
document.getElementById('emailInput').style.borderColor = '#e53935';
document.getElementById('emailInput').focus();
}
});
// Auto-focus OTP field after password
document.getElementById('password').addEventListener('keydown', function(e) {
if (e.key === 'Tab' || e.key === 'Enter') {
if (e.key === 'Enter') e.preventDefault();
document.getElementById('otp').focus();
}
});
// OTP: only allow digits
document.getElementById('otp').addEventListener('input', function(e) {
this.value = this.value.replace(/[^0-9]/g, '');
});
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+44
View File
@@ -0,0 +1,44 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['windows_audit.py'],
pathex=[],
binaries=[],
datas=[('audit_cis_windows.ps1.enc', '.')],
hiddenimports=['colorama', 'unidecode', 'Crypto', 'Crypto.Cipher', 'Crypto.PublicKey', 'Crypto.Util.Padding'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='AuditTool',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
Binary file not shown.
@@ -0,0 +1,201 @@
Unnamed: 0,Unnamed: 1,KẾT QUẢ,Unnamed: 3,Unnamed: 4,Unnamed: 5
,Hạng mục đánh giá ,Đáp ứng,,,Ghi chú
,,,Không,Bắt buộc,
1,Thiết lập ban đầu,,,,
1.1,Cấu hình filesystem,,,,
1.1.1,Cấu hình vô hiệu hoá các filesystem không sử dụng,,,,
1.1.1.1,Cấu hình vô hiệu hoá cramfs filesystem,,,,
1.1.1.2,Cấu hình vô hiệu hoá freevxfs filesystem,,,,
1.1.1.3,Cấu hình vô hiệu hoá hfs filesystem,,,,
1.1.1.4,Cấu hình vô hiệu hoá hfsplus filesystem,,,,
1.1.1.5,Cấu hình vô hiệu hoá jffs2 filesystem,,,,
1.1.1.6,Cấu hình vô hiệu hoá squashfs filesystem,,,,
1.1.1.7,Cấu hình vô hiệu hoá udf filesystem,,,,
1.1.1.8,Cấu hình vô hiệu hoá usb storage,,,,
1.1.2,Cấu hình phân vùng /tmp,,,,
1.1.2.1,Cấu hình tuỳ chọn nodev cho phân vùng /tmp,,,,
1.1.2.2,Cấu hình tuỳ chọn nosuid cho phân vùng /tmp,,,,
1.1.2.3,Cấu hình tuỳ chọn noexec cho phân vùng /tmp,,,,
1.1.3,Cấu hình phân vùng /var/tmp,,,,
1.1.3.1,Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp,,,,
1.1.3.2,Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp,,,,
1.1.3.3,Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp,,,,
1.1.4,Cấu hình phân vùng /home,,,,
1.1.4.1,Cấu hình tuỳ chọn nodev cho phân vùng /home,,,,
1.1.4.2,Cấu hình tuỳ chọn nosuid cho phân vùng /home,,,,
1.1.5,Cấu hình phân vùng /dev/shm,,,,
1.1.5.1,Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm,,,,
1.1.5.2,Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm,,,,
1.1.5.3,Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm,,,,
1.2,Cấu hình cập nhật phần mềm,,,,
1.2.1 ,Cấu hình kích hoạt gpgcheck,,,,
1.3,Kiểm tra tính toàn vẹn của filesystem,,,,
1.3.1,Kiểm tra cài đặt AIDE,,,,
1.3.2 ,Cấu hình kiểm tra tính toàn vẹn của filesystem,,,,
1.4,Cấu hình khởi động an toàn,,,,
1.4.1,Phân quyền đối với file cấu hình bootloader,,,,
1.4.2,Cấu hình mật khẩu cho bootloader,,,,
1.4.3,Cấu hình xác thực khi truy cập single user mode,,,,
1.4.4,Cấu hình vô hiệu hoá interactive boot ,,,,
1.5,Additional Process Hardening,,,,
1.5.1 ,Cấu hình vô hiệu hoá core dump,,,,
1.5.2,Cấu hình kích hoạt ASLR (address space layout randomization),,,,
1.5.3,Cấu hình vô hiệu hoá prelink,,,,
1.6,Kiểm soát nội dung cảnh báo,,,,
1.6.1,Kiểm soát nội dung motd (Message Of The Day),,,,
1.6.2,Kiểm soát nội dung thông báo khi đăng nhập,,,,
1.6.3,Kiểm soát nội dung thông báo khi đăng nhập từ xa,,,,
1.6.4,Cấu hình phân quyền đối với file /etc/motd,,,,
1.6.5,Cấu hình phân quyền đối với file /etc/issue,,,,
1.6.6,Cấu hình phân quyền đối với file /etc/issue.net,,,,
1.6.7,Kiểm soát nội dung thông báo khi truy cập GNOME,,,,
2,Service,,,,
2.1,Cấu hình Time Synchronization,,,,
2.1.1,Cấu hình sử dụng chrony,,,x,
2.1.2,Cấu hình sử dụng ntp,,,x,
2.2,Các Service với mục đích riêng biệt,,,,
2.2.1,Cấu hình vô hiệu hoá xinetd services,,,,
2.2.2,Cấu hình vô hiệu hoá chargen services,,,,
2.2.3,Cấu hình vô hiệu hoá daytime services,,,,
2.2.4,Cấu hình vô hiệu hoá discard services,,,,
2.2.5,Cấu hình vô hiệu hoá echo services,,,,
2.2.6,Cấu hình vô hiệu hoá time services,,,,
2.2.7,Cấu hình vô hiệu hoá rsh server,,,,
2.2.8,Cấu hình vô hiệu hoá talk server,,,,
2.2.9,Cấu hình vô hiệu hoá autofs services,,,,
2.2.10,Cấu hình vô hiệu hoá X window server services,,,,
2.2.11,Cấu hình vô hiệu hoá avahi daemon services,,,,
2.2.12,Cấu hình vô hiệu hoá cups services,,,,
2.2.13,Cấu hình vô hiệu hoá dhcp server services,,,,
2.2.14,Cấu hình vô hiệu hoá ldap server services,,,,
2.2.15,Cấu hình vô hiệu hoá dns server services,,,,
2.2.16,Cấu hình vô hiệu hoá dnsmasq services,,,,
2.2.17,Cấu hình vô hiệu hoá ftp server services,,,,
2.2.18,Cấu hình vô hiệu hoá tftp server services,,,,
2.2.19,Cấu hình vô hiệu hoá web server services,,,,
2.2.20,Cấu hình vô hiệu hoá imap and pop3 server services,,,,
2.2.21,Cấu hình vô hiệu hoá samba file server services,,,,
2.2.22,Cấu hình vô hiệu hoá web proxy server services,,,,
2.2.23,Cấu hình vô hiệu hoá snmp services,,,,
2.2.24,Cấu hình vô hiệu hoá nis server services,,,,
2.2.25,Cấu hình vô hiệu hoá telnet server services,,,,
2.2.26,Cấu hình mail transfer agents sang chế độ local-only,,,,
2.2.27,Cấu hình vô hiệu hoá network file system services,,,,
2.2.28,Cấu hình vô hiệu hoá rpcbind services,,,,
2.2.29,Cấu hình vô hiệu hoá rsync services,,,,
2.3,Service Clients,,,,
2.3.1,Cấu hình vô hiệu hoá nis client,,,,
2.3.2,Cấu hình vô hiệu hoá rsh client,,,,
2.3.3,Cấu hình vô hiệu hoá talk client,,,,
2.3.4,Cấu hình vô hiệu hoá telnet client,,,,
2.3.5,Cấu hình vô hiệu hoá ldap client,,,,
2.3.6,Cấu hình vô hiệu hoá ftp client,,,,
2.3.7,Cấu hình vô hiệu hoá tftp client,,,,
3,Cấu hình mạng,,,,
3.1,Tham số cấu hình mạng (Host Only),,,,
3.1.1 ,Cấu hình vô hiệu hoá IP forwarding,,,,
3.1.2,Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect),,,,
3.2,Tham số cấu hình mạng (Host và Router),,,,
3.2.1 ,Cấu hình từ chối các gói tin với nguồn được định tuyến trước,,,,
3.2.2,Cấu hình từ chối các ICMP redirect message,,,,
3.2.3,Cấu hình từ chối các secure ICMP redirect message,,,,
3.2.4,Cấu hình từ chối các gói tin ICMP request broadcast,,,,
3.2.5,Cấu hình bỏ qua phản hồi ICMP không hợp lệ,,,,
3.2.6,Cấu hình Reverse Path Filtering,,,,
3.2.7,Cấu hình TCP SYN Cookies,,,,
3.4,Cấu hình Firewall,,,,
3.4.1,Cấu hình firewalld,,,,
3.4.1.1,Cấu hình kích hoạt firewalld,,,x,
3.4.1.3,Cấu hình firewalld rule cho tất cả các port và protocol đang mở,,,x,
3.4.1.4,Cấu hình chính sách từ chối mặc định cho firewalld,,,x,
3.4.2,Iptables,,,,
3.4.2.1,Cấu hình kích hoạt Iptables,,,x,
3.4.2.3,Cấu hình iptables loopback traffic,,,x,
3.4.2.4,Cấu hình iptables rule cho tất cả các port và protocol đang mở,,,x,
3.4.2.5,Cấu hình chính sách từ chối mặc định cho iptables,,,x,
4,Logging và Auditing,,,,
4.1,Cấu hình logging,,,,
4.1.1,Cấu hình rsyslog,,,,
4.1.1.1 ,Cấu hình kích hoạt rsyslog service,,,,
4.1.1.2,Phân quyền đối với file log sinh ra từ rsyslog,,,,
4.1.1.3,Cấu hình lưu trữ log sinh ra từ rsyslog tập trung,,,x,
4.1.1.4,Phân quyền đối với tất cả các file log,,,,
5,"Cấu hình truy cập, xác thực và ủy quyền",,,,
5.1,Cấu hình cron,,,,
5.1.1 ,Cấu hình kích hoạt cron daemon,,,,
5.1.2 ,Cấu hình phân quyền cho file /etc/crontab,,,,
5.1.3 ,Cấu hình phân quyền cho file /etc/cron.hourly,,,,
5.1.4 ,Cấu hình phân quyền cho file /etc/cron.daily,,,,
5.1.5 ,Cấu hình phân quyền cho file /etc/cron.weekly,,,,
5.1.6 ,Cấu hình phân quyền cho của file /etc/cron.monthly,,,,
5.1.7 ,Cấu hình phân quyền cho file /etc/cron.d,,,,
5.1.8 ,Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền,,,,
5.2,Cấu hình máy chủ SSH,,,,
5.2.1 ,Cấu hình phân quyền cho file /etc/ssh/sshd_config,,,,
5.2.2,Cấu hình phân quyền cho các file SSH private host key,,,,
5.2.3,Cấu hình phân quyền cho các file SSH public host key,,,,
5.2.4,Cấu hình giới hạn truy cập cho máy chủ SSH,,,,
5.2.5,Cấu hình LogLevel cho máy chủ SSH,,,,
5.2.6,Cấu hình sử dụng SSH PAM,,,,
5.2.7,Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH,,,,
5.2.8,Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH,,,,
5.2.9,Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH,,,,
5.2.10,Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH,,,,
5.2.11,Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH,,,,
5.2.12,Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH,,,,
5.2.13,Cấu hình vô hiệu hoá SSH AllowTcpForwarding,,,,
5.2.14,Cấu hình cảnh báo SSH,,,,
5.2.15,Cấu hình SSH MaxAuthTries,,,,
5.2.16,Cấu hình SSH MaxStartups,,,,
5.2.17,Cấu hình SSH MaxSessions,,,,
5.2.18,Cấu hình SSH LoginGraceTime,,,,
5.2.19,Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH,,,,
5.2.20,Cấu hình các thuật toán MAC được cho phép,,,,
5.3,Cấu hình PAM,,,,
5.3.1 ,Cấu hình điều kiện tạo mật khẩu,,,x,
5.3.2 ,Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại,,,x,
5.3.3 ,Giới hạn việc sử dụng lại mật khẩu,,,,
5.3.4 ,Cấu hình thuật toán hash mật khẩu sang SHA-512,,,,
5.4,Cấu hình tài khoản người dùng và môi trường,,,,
5.4.1 ,Cấu hình mật khẩu người dùng,,,,
5.4.1.1 ,Cấu hình thời gian hết hạn sử dụng mật khẩu,,,x,
5.4.1.2 ,Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu,,,x,
5.4.1.3 ,Cấu hình thời gian cảnh báo mật khẩu hết hạn,,,,
5.4.1.4 ,Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn,,,,
5.4.1.5,Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ,,,,
5.4.2 ,Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống,,,,
5.4.3,Cấu hình shell timeout mặc định,,,,
5.4.4,Cấu hình group mặc định của tài khoản root,,,,
5.4.5,Cấu hình user umask mặc định,,,,
5.4.6,Cấu hình hạn chế truy cập cho câu lệnh su,,,,
6,System Maintenance,,,,
6.1,Quyền của file hệ thống,,,,
6.1.1,Cấu hình sticky bit cho tất cả các thư mục dùng chung,,,,
6.1.2,Cấu hình phân quyền cho file /etc/passwd,,,,
6.1.3,Cấu hình phân quyền cho file /etc/shadow,,,,
6.1.4,Cấu hình phân quyền cho file /etc/group,,,,
6.1.5,Cấu hình phân quyền cho file /etc/gshadow,,,,
6.1.6,Cấu hình phân quyền cho file /etc/passwd-,,,,
6.1.7,Cấu hình phân quyền cho file /etc/shadow-,,,,
6.1.8,Cấu hình phân quyền cho file /etc/group-,,,,
6.1.9,Cấu hình phân quyền cho file /etc/gshadow-,,,,
6.1.10,Đảm bảo không có file world-writable tồn tại,,,,
6.1.11,Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại,,,,
6.1.12,Đảm bảo các file hoặc thư mục không có nhóm không tồn tại,,,,
6.2,Thiết lập cho người dùng và nhóm,,,,
6.2.1 ,Đảm bảo trường mật khẩu không để trống,,,,
6.2.2,Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group,,,,
6.2.3,Đảm bảo UID không bị lặp,,,,
6.2.4,Đảm bảo GID không bị lặp,,,,
6.2.5,Đảm bảo tên người dùng không bị lặp,,,,
6.2.6,Đảm bảo tên group không bị lặp,,,,
6.2.7,Đảm bảo tính toàn vẹn cho biến môi trường PATH của root,,,,
6.2.8,Đảm bảo root là tài khoản duy nhất có UID là 0,,,,
6.2.9,Đảm bảo mọi người dùng đều tồn tại thư mục home,,,,
6.2.10,Đảm bảo người dùng sở hữu thư mục home của chính họ,,,,
6.2.11,Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao,,,,
6.2.12,Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other,,,,
6.2.13,Đảm bảo không người dùng nào có file .forward,,,,
6.2.14,Đảm bảo không người dùng nào có file .netrc,,,,
6.2.15,Đảm bảo không người dùng nào có file .rhosts,,,,
,0,0,0,,
1 Unnamed: 0 Unnamed: 1 KẾT QUẢ Unnamed: 3 Unnamed: 4 Unnamed: 5
2 Hạng mục đánh giá Đáp ứng Ghi chú
3 Không Bắt buộc
4 1 Thiết lập ban đầu
5 1.1 Cấu hình filesystem
6 1.1.1 Cấu hình vô hiệu hoá các filesystem không sử dụng
7 1.1.1.1 Cấu hình vô hiệu hoá cramfs filesystem
8 1.1.1.2 Cấu hình vô hiệu hoá freevxfs filesystem
9 1.1.1.3 Cấu hình vô hiệu hoá hfs filesystem
10 1.1.1.4 Cấu hình vô hiệu hoá hfsplus filesystem
11 1.1.1.5 Cấu hình vô hiệu hoá jffs2 filesystem
12 1.1.1.6 Cấu hình vô hiệu hoá squashfs filesystem
13 1.1.1.7 Cấu hình vô hiệu hoá udf filesystem
14 1.1.1.8 Cấu hình vô hiệu hoá usb storage
15 1.1.2 Cấu hình phân vùng /tmp
16 1.1.2.1 Cấu hình tuỳ chọn nodev cho phân vùng /tmp
17 1.1.2.2 Cấu hình tuỳ chọn nosuid cho phân vùng /tmp
18 1.1.2.3 Cấu hình tuỳ chọn noexec cho phân vùng /tmp
19 1.1.3 Cấu hình phân vùng /var/tmp
20 1.1.3.1 Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp
21 1.1.3.2 Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp
22 1.1.3.3 Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp
23 1.1.4 Cấu hình phân vùng /home
24 1.1.4.1 Cấu hình tuỳ chọn nodev cho phân vùng /home
25 1.1.4.2 Cấu hình tuỳ chọn nosuid cho phân vùng /home
26 1.1.5 Cấu hình phân vùng /dev/shm
27 1.1.5.1 Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm
28 1.1.5.2 Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm
29 1.1.5.3 Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm
30 1.2 Cấu hình cập nhật phần mềm
31 1.2.1 Cấu hình kích hoạt gpgcheck
32 1.3 Kiểm tra tính toàn vẹn của filesystem
33 1.3.1 Kiểm tra cài đặt AIDE
34 1.3.2 Cấu hình kiểm tra tính toàn vẹn của filesystem
35 1.4 Cấu hình khởi động an toàn
36 1.4.1 Phân quyền đối với file cấu hình bootloader
37 1.4.2 Cấu hình mật khẩu cho bootloader
38 1.4.3 Cấu hình xác thực khi truy cập single user mode
39 1.4.4 Cấu hình vô hiệu hoá interactive boot
40 1.5 Additional Process Hardening
41 1.5.1 Cấu hình vô hiệu hoá core dump
42 1.5.2 Cấu hình kích hoạt ASLR (address space layout randomization)
43 1.5.3 Cấu hình vô hiệu hoá prelink
44 1.6 Kiểm soát nội dung cảnh báo
45 1.6.1 Kiểm soát nội dung motd (Message Of The Day)
46 1.6.2 Kiểm soát nội dung thông báo khi đăng nhập
47 1.6.3 Kiểm soát nội dung thông báo khi đăng nhập từ xa
48 1.6.4 Cấu hình phân quyền đối với file /etc/motd
49 1.6.5 Cấu hình phân quyền đối với file /etc/issue
50 1.6.6 Cấu hình phân quyền đối với file /etc/issue.net
51 1.6.7 Kiểm soát nội dung thông báo khi truy cập GNOME
52 2 Service
53 2.1 Cấu hình Time Synchronization
54 2.1.1 Cấu hình sử dụng chrony x
55 2.1.2 Cấu hình sử dụng ntp x
56 2.2 Các Service với mục đích riêng biệt
57 2.2.1 Cấu hình vô hiệu hoá xinetd services
58 2.2.2 Cấu hình vô hiệu hoá chargen services
59 2.2.3 Cấu hình vô hiệu hoá daytime services
60 2.2.4 Cấu hình vô hiệu hoá discard services
61 2.2.5 Cấu hình vô hiệu hoá echo services
62 2.2.6 Cấu hình vô hiệu hoá time services
63 2.2.7 Cấu hình vô hiệu hoá rsh server
64 2.2.8 Cấu hình vô hiệu hoá talk server
65 2.2.9 Cấu hình vô hiệu hoá autofs services
66 2.2.10 Cấu hình vô hiệu hoá X window server services
67 2.2.11 Cấu hình vô hiệu hoá avahi daemon services
68 2.2.12 Cấu hình vô hiệu hoá cups services
69 2.2.13 Cấu hình vô hiệu hoá dhcp server services
70 2.2.14 Cấu hình vô hiệu hoá ldap server services
71 2.2.15 Cấu hình vô hiệu hoá dns server services
72 2.2.16 Cấu hình vô hiệu hoá dnsmasq services
73 2.2.17 Cấu hình vô hiệu hoá ftp server services
74 2.2.18 Cấu hình vô hiệu hoá tftp server services
75 2.2.19 Cấu hình vô hiệu hoá web server services
76 2.2.20 Cấu hình vô hiệu hoá imap and pop3 server services
77 2.2.21 Cấu hình vô hiệu hoá samba file server services
78 2.2.22 Cấu hình vô hiệu hoá web proxy server services
79 2.2.23 Cấu hình vô hiệu hoá snmp services
80 2.2.24 Cấu hình vô hiệu hoá nis server services
81 2.2.25 Cấu hình vô hiệu hoá telnet server services
82 2.2.26 Cấu hình mail transfer agents sang chế độ local-only
83 2.2.27 Cấu hình vô hiệu hoá network file system services
84 2.2.28 Cấu hình vô hiệu hoá rpcbind services
85 2.2.29 Cấu hình vô hiệu hoá rsync services
86 2.3 Service Clients
87 2.3.1 Cấu hình vô hiệu hoá nis client
88 2.3.2 Cấu hình vô hiệu hoá rsh client
89 2.3.3 Cấu hình vô hiệu hoá talk client
90 2.3.4 Cấu hình vô hiệu hoá telnet client
91 2.3.5 Cấu hình vô hiệu hoá ldap client
92 2.3.6 Cấu hình vô hiệu hoá ftp client
93 2.3.7 Cấu hình vô hiệu hoá tftp client
94 3 Cấu hình mạng
95 3.1 Tham số cấu hình mạng (Host Only)
96 3.1.1 Cấu hình vô hiệu hoá IP forwarding
97 3.1.2 Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)
98 3.2 Tham số cấu hình mạng (Host và Router)
99 3.2.1 Cấu hình từ chối các gói tin với nguồn được định tuyến trước
100 3.2.2 Cấu hình từ chối các ICMP redirect message
101 3.2.3 Cấu hình từ chối các secure ICMP redirect message
102 3.2.4 Cấu hình từ chối các gói tin ICMP request broadcast
103 3.2.5 Cấu hình bỏ qua phản hồi ICMP không hợp lệ
104 3.2.6 Cấu hình Reverse Path Filtering
105 3.2.7 Cấu hình TCP SYN Cookies
106 3.4 Cấu hình Firewall
107 3.4.1 Cấu hình firewalld
108 3.4.1.1 Cấu hình kích hoạt firewalld x
109 3.4.1.3 Cấu hình firewalld rule cho tất cả các port và protocol đang mở x
110 3.4.1.4 Cấu hình chính sách từ chối mặc định cho firewalld x
111 3.4.2 Iptables
112 3.4.2.1 Cấu hình kích hoạt Iptables x
113 3.4.2.3 Cấu hình iptables loopback traffic x
114 3.4.2.4 Cấu hình iptables rule cho tất cả các port và protocol đang mở x
115 3.4.2.5 Cấu hình chính sách từ chối mặc định cho iptables x
116 4 Logging và Auditing
117 4.1 Cấu hình logging
118 4.1.1 Cấu hình rsyslog
119 4.1.1.1 Cấu hình kích hoạt rsyslog service
120 4.1.1.2 Phân quyền đối với file log sinh ra từ rsyslog
121 4.1.1.3 Cấu hình lưu trữ log sinh ra từ rsyslog tập trung x
122 4.1.1.4 Phân quyền đối với tất cả các file log
123 5 Cấu hình truy cập, xác thực và ủy quyền
124 5.1 Cấu hình cron
125 5.1.1 Cấu hình kích hoạt cron daemon
126 5.1.2 Cấu hình phân quyền cho file /etc/crontab
127 5.1.3 Cấu hình phân quyền cho file /etc/cron.hourly
128 5.1.4 Cấu hình phân quyền cho file /etc/cron.daily
129 5.1.5 Cấu hình phân quyền cho file /etc/cron.weekly
130 5.1.6 Cấu hình phân quyền cho của file /etc/cron.monthly
131 5.1.7 Cấu hình phân quyền cho file /etc/cron.d
132 5.1.8 Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền
133 5.2 Cấu hình máy chủ SSH
134 5.2.1 Cấu hình phân quyền cho file /etc/ssh/sshd_config
135 5.2.2 Cấu hình phân quyền cho các file SSH private host key
136 5.2.3 Cấu hình phân quyền cho các file SSH public host key
137 5.2.4 Cấu hình giới hạn truy cập cho máy chủ SSH
138 5.2.5 Cấu hình LogLevel cho máy chủ SSH
139 5.2.6 Cấu hình sử dụng SSH PAM
140 5.2.7 Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH
141 5.2.8 Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH
142 5.2.9 Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH
143 5.2.10 Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH
144 5.2.11 Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH
145 5.2.12 Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH
146 5.2.13 Cấu hình vô hiệu hoá SSH AllowTcpForwarding
147 5.2.14 Cấu hình cảnh báo SSH
148 5.2.15 Cấu hình SSH MaxAuthTries
149 5.2.16 Cấu hình SSH MaxStartups
150 5.2.17 Cấu hình SSH MaxSessions
151 5.2.18 Cấu hình SSH LoginGraceTime
152 5.2.19 Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH
153 5.2.20 Cấu hình các thuật toán MAC được cho phép
154 5.3 Cấu hình PAM
155 5.3.1 Cấu hình điều kiện tạo mật khẩu x
156 5.3.2 Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại x
157 5.3.3 Giới hạn việc sử dụng lại mật khẩu
158 5.3.4 Cấu hình thuật toán hash mật khẩu sang SHA-512
159 5.4 Cấu hình tài khoản người dùng và môi trường
160 5.4.1 Cấu hình mật khẩu người dùng
161 5.4.1.1 Cấu hình thời gian hết hạn sử dụng mật khẩu x
162 5.4.1.2 Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu x
163 5.4.1.3 Cấu hình thời gian cảnh báo mật khẩu hết hạn
164 5.4.1.4 Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn
165 5.4.1.5 Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ
166 5.4.2 Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống
167 5.4.3 Cấu hình shell timeout mặc định
168 5.4.4 Cấu hình group mặc định của tài khoản root
169 5.4.5 Cấu hình user umask mặc định
170 5.4.6 Cấu hình hạn chế truy cập cho câu lệnh su
171 6 System Maintenance
172 6.1 Quyền của file hệ thống
173 6.1.1 Cấu hình sticky bit cho tất cả các thư mục dùng chung
174 6.1.2 Cấu hình phân quyền cho file /etc/passwd
175 6.1.3 Cấu hình phân quyền cho file /etc/shadow
176 6.1.4 Cấu hình phân quyền cho file /etc/group
177 6.1.5 Cấu hình phân quyền cho file /etc/gshadow
178 6.1.6 Cấu hình phân quyền cho file /etc/passwd-
179 6.1.7 Cấu hình phân quyền cho file /etc/shadow-
180 6.1.8 Cấu hình phân quyền cho file /etc/group-
181 6.1.9 Cấu hình phân quyền cho file /etc/gshadow-
182 6.1.10 Đảm bảo không có file world-writable tồn tại
183 6.1.11 Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại
184 6.1.12 Đảm bảo các file hoặc thư mục không có nhóm không tồn tại
185 6.2 Thiết lập cho người dùng và nhóm
186 6.2.1 Đảm bảo trường mật khẩu không để trống
187 6.2.2 Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group
188 6.2.3 Đảm bảo UID không bị lặp
189 6.2.4 Đảm bảo GID không bị lặp
190 6.2.5 Đảm bảo tên người dùng không bị lặp
191 6.2.6 Đảm bảo tên group không bị lặp
192 6.2.7 Đảm bảo tính toàn vẹn cho biến môi trường PATH của root
193 6.2.8 Đảm bảo root là tài khoản duy nhất có UID là 0
194 6.2.9 Đảm bảo mọi người dùng đều tồn tại thư mục home
195 6.2.10 Đảm bảo người dùng sở hữu thư mục home của chính họ
196 6.2.11 Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao
197 6.2.12 Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other
198 6.2.13 Đảm bảo không người dùng nào có file .forward
199 6.2.14 Đảm bảo không người dùng nào có file .netrc
200 6.2.15 Đảm bảo không người dùng nào có file .rhosts
201 0 0 0
@@ -0,0 +1,236 @@
STT,Hạng mục đánh giá,Unnamed: 2,Unnamed: 3,Unnamed: 4
,,KẾT QUẢ,,
,,,,
,,Đạt,Không,
2.1,Thiết lập ban đầu,,,
2.1.1,Cấu hình filesystem,,,
2.1.1.1,"Cấu hình vô hiệu hoá cramfs, freevxfs, jffs2, hfs, hfsplus, squashfs, udf filesystem",,,
,Cấu hình vô hiệu hoá cramfs filesystem,,,
,Cấu hình vô hiệu hoá freevxfs filesystem,,,
,Cấu hình vô hiệu hoá hfs filesystem,,,
,Cấu hình vô hiệu hoá hfsplus filesystem,,,
,Cấu hình vô hiệu hoá jffs2 filesystem,,,
,Cấu hình vô hiệu hoá squashfs filesystem,,,
,Cấu hình vô hiệu hoá udf filesystem,,,
,Cấu hình vô hiệu hoá usb storage,,,
,Cấu hình phân vùng /tmp,,,
2.1.1.2,Cấu hình tuỳ chọn nodev cho phân vùng /tmp,,,
2.1.1.3,Cấu hình tuỳ chọn nosuid cho phân vùng /tmp,,,
2.1.1.4,Cấu hình tuỳ chọn noexec cho phân vùng /tmp,,,
,Cấu hình phân vùng /var/tmp,,,
2.1.1.5,Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp,,,
2.1.1.6,Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp,,,
2.1.1.7,Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp,,,
,Cấu hình phân vùng /home,,,
2.1.1.8,Cấu hình tuỳ chọn nodev cho phân vùng /home,,,
,Cấu hình phân vùng /dev/shm,,,
2.1.1.9,Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm,,,
2.1.1.10,Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm,,,
2.1.1.11,Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm,,,
2.1.1.12,Cấu hình sticky bit cho tất cả các thư mục dùng chung,,,
2.1.1.13,Cấu hình vô hiệu hoá automounting,,,
2.1.2,Cấu hình sudo (áp dụng dành riêng cho Ubuntu),,,
2.1.2.1,Kiểm tra việc cài đặt sudo,,,
2.1.2.2,Cấu hình các lệnh sudo sử dụng pty,,,
2.1.2.3,Đảm bảo file nhật ký của sudo tồn tại,,,
2.1.3,Cấu hình cập nhật phần mềm,,,
2.1.3.1,Cấu hình kích hoạt gpgcheck,,,
2.1.4,Kiểm tra tính toàn vẹn của filesystem,,,
2.1.4.1,Kiểm tra việc cài đặt AIDE,,,
2.1.4.2,Cấu hình kiểm tra tính toàn vẹn của filesystem,,,
2.1.5,Cấu hình khởi động an toàn,,,
2.1.5.1,Phân quyền đối với file cấu hình bootloader,,,
2.1.5.2,Cấu hình mật khẩu cho bootloader,,,
2.1.5.3,Cấu hình xác thực khi truy cập single user mode,,,
2.1.5.4,Cấu hình vô hiệu hoá interactive boot,,,
2.1.6,Additional Process Hardening,,,
2.1.6.1,Cấu hình kiểm soát core dump,,,
2.1.6.2,Cấu hình kích hoạt ASLR (address space layout randomization),,,
2.1.6.3,Cấu hình vô hiệu hoá prelink,,,
2.1.7,Kiểm soát nội dung cảnh báo,,,
2.1.7.1,Kiểm soát nội dung motd (Message Of The Day),,,
2.1.7.2,Kiểm soát nội dung thông báo khi đăng nhập,,,
2.1.7.3,Kiểm soát nội dung thông báo khi đăng nhập từ xa,,,
2.1.7.4,Cấu hình phân quyền đối với file /etc/motd,,,
2.1.7.5,Cấu hình phân quyền đối với file /etc/issue,,,
2.1.7.6,Cấu hình phân quyền đối với file /etc/issue.net,,,
2.1.7.7,Kiểm soát nội dung thông báo khi truy cập GNOME,,,
2.2,Service,,,
2.2.1, Cấu hình inetd Service,,,
2.2.1.1,"Cấu hình vô hiệu hoá chargen service, daytime service,",,,
,"discard service, echo service, time service, rsh, talk service, telnet, tftp, rsync, xinetd.",,,
2.2.2,Các Service với mục đích riêng biệt,,,
2.2.2.1,Cấu hình sử dụng NTP,,,
2.2.2.2,Cấu hình sử dụng chrony,,,
2.2.2.3,"Cấu hình vô hiệu hoá X window, Avahi, CUPS, DHCP, LDAP, NFS, RPC, DNS , FTP, HTTP, POP3, IMAP, Samba, HTTP Proxy, SNMP, NIS",,,
,Cấu hình vô hiệu hoá xinetd services,,,
,Cấu hình vô hiệu hoá autofs services,,,
,Cấu hình vô hiệu hoá X window server services,,,
,Cấu hình vô hiệu hoá avahi daemon services,,,
,Cấu hình vô hiệu hoá cups services,,,
,Cấu hình vô hiệu hoá dhcp server services,,,
,Cấu hình vô hiệu hoá ldap server services,,,
,Cấu hình vô hiệu hoá dns server services,,,
,Cấu hình vô hiệu hoá dnsmasq services,,,
,Cấu hình vô hiệu hoá ftp server services,,,
,Cấu hình vô hiệu hoá tftp server services,,,
,Cấu hình vô hiệu hoá web server services,,,
,Cấu hình vô hiệu hoá imap and pop3 server services,,,
,Cấu hình vô hiệu hoá samba file server services,,,
,Cấu hình vô hiệu hoá web proxy server services,,,
,Cấu hình vô hiệu hoá snmp services,,,
,Cấu hình vô hiệu hoá nis server services,,,
,Cấu hình vô hiệu hoá network file system services,,,
,Cấu hình vô hiệu hoá rsync services,,,
2.2.2.4,Cấu hình mail transfer agents sang chế độ local-only,,,
2.2.3,Service Clients,,,
2.2.3.1,"Cấu hình xoá bỏ NIS client, rsh client, talk client, telnet client, LDAP client",,,
,Cấu hình vô hiệu hoá nis client,,,
,Cấu hình vô hiệu hoá rsh client,,,
,Cấu hình vô hiệu hoá talk client,,,
,Cấu hình vô hiệu hoá telnet client,,,
,Cấu hình vô hiệu hoá ldap client,,,
,Cấu hình vô hiệu hoá rpc,,,
,Cấu hình vô hiệu hoá ftp client,,,
2.3,Cấu hình mạng,,,
2.3.1,Tham số cấu hình mạng (Host Only),,,
2.3.1.1,Cấu hình vô hiệu hoá IP forwarding,,,
2.3.1.2,Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect),,,
2.3.2,Tham số cấu hình mạng (Host và Router),,,
2.3.2.1,Cấu hình từ chối các gói tin với nguồn được định tuyến trước,,,
2.3.2.2,Cấu hình từ chối các ICMP redirect message,,,
2.3.2.3,Cấu hình từ chối các secure ICMP redirect message,,,
2.3.2.4,Ghi lại các gói tin khả nghi (Suspicious Packets),,,
2.3.2.5,Cấu hình từ chối các gói tin ICMP request broadcast,,,
2.3.2.6,Cấu hình bỏ qua phản hồi ICMP không hợp lệ,,,
2.3.2.7,Cấu hình Reverse Path Filtering,,,
2.3.2.8,Cấu hình TCP SYN Cookies,,,
2.3.3,TCP Wrappers,,,
2.3.3.1,Kiêm tra việc cài đặt TCP Wrappers,,,
2.3.3.2,Cấu hình file /etc/host.allow,,,
2.3.3.3,Cấu hình file /etc/hosts.deny,,,
2.3.3.4,Cấu hình quyền truy cập /etc/hosts.allow,,,
2.3.3.5,Cấu hình quyền truy cập /etc/hosts.deny,,,
2.3.4,Tưởng lửa (áp dụng dành riêng cho ubuntu),,,
2.3.4.1,Cài đặt tưởng lửa mềm (soft firewall),,,
2.3.4.1.1,Cài đặt Firewall package ,,,
2.3.4.2,Cấu hình ufw (UncomplicatedFirewal),,,
2.3.4.2.1,Cấu hình kích hoạt ufw,,,
2.3.4.2.2,Cấu hình chính sách từ chối mặc định của tường lửa,,,
2.3.4.2.3,Cấu hình loopback traffic,,,
2.3.4.3,Cấu hình tường lửa nftable,,,
2.3.4.3.1,Cấu hình tạo ít nhất 1 bảng trong nftable,,,
2.3.4.3.2,Cấu hình các base chain,,,
2.3.4.3.3,Cấu hình loopback traffic,,,
2.3.4.3.4,Cấu hình chính sách từ chối mặc định của tường lửa,,,
2.3.4.3.5,Cấu hình kích hoạt nftable,,,
2.3.4.3.6,Cấu hình nftable rule,,,
2.3.5,Iptables,,,
2.3.5.1,Cấu hình kích hoạt Iptables,,,
2.3.5.2,Cấu hình chính sách từ chối mặc định trên firewall,,,
2.3.5.3,Cấu hình loopback traffic,,,
2.3.5.4,Cấu hình iptables rule cho tất cả các port và protocol đang mở,,,
2.4,Logging và Auditing,,,
2.4.1,Cấu hình logging,,,
2.4.1.1,Cấu hình rsyslog,,,
2.4.1.1.1,Cấu hình kích hoạt rsyslog service,,,
2.4.1.1.2,Phân quyền đối với file log sinh ra từ rsyslog,,,
2.4.1.1.3,Cấu hình lưu trữ log sinh ra từ rsyslog tập trung,,,
2.4.1.2,Phân quyền đối với tất cả các file log,,,
,Áp dụng đối với Centos,,,
2.4.1.2.1,Cấu hình kích hoạt syslog-ng service,,,
2.4.1.2.2,Phân quyền đối với file log sinh ra từ syslog-ng,,,
2.4.1.2.3,Cấu hình lưu trữ log tập trung,,,
2.4.1.3,Cấu hình journald,,,
,Áp dụng riêng cho ubuntu,,,
2.4.1.3.1,Cấu hình journald để gửi file log đến rsyslog,,,
2.4.1.3.2,Cấu hình journald để nén các file log lớn,,,
2.4.1.3.3,Cấu hình journald để viết các logfile vào persistent disk,,,
2.4.1.3.4,Đảm bảo các quyền trên toàn bộ logfile được cấu hình,,,
2.4.1.4,Đảm bảo rsyslog hoặc syslog-ng được cài đặt,,,
2.4.1.5,Phân quyền đối với tất cả các file log,,,
2.5,"Cấu hình truy cập, xác thực và ủy quyền",,,
2.5.1,Cấu hình cron,,,
2.5.1.1,Cấu hình kích hoạt cron daemon,,,
2.5.1.2,Cấu hình phân quyền cho file /etc/crontab,,,
2.5.1.2.1,Cấu hình phân quyền cho file /etc/cron.hourly,,,
2.5.1.3,Cấu hình phân quyền cho file /etc/cron.daily,,,
2.5.1.4,Cấu hình phân quyền cho file /etc/cron.weekly,,,
2.5.1.5,Cấu hình phân quyền cho của file /etc/cron.monthly,,,
2.5.1.6,Cấu hình phân quyền cho file /etc/cron.d,,,
2.5.1.7,Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền,,,
2.5.2,Cấu hình máy chủ SSH,,,
2.5.2.1,Cấu hình quyền cho file /etc/ssh/sshd_config,,,
2.5.2.1.1,Cấu hình quyền cho các file SSH private host,,,
2.5.2.2,Cấu hình quyền cho các file SSH public host key,,,
2.5.2.3,Cấu hình giao thức SSH sử dụng SSHv2,,,
2.5.2.4,Cấu hình LogLevel cho máy chủ SSH,,,
2.5.2.5,Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH,,,
2.5.2.6,Cấu hình SSH MaxAuthTries,,,
2.5.2.7,Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH,,,
2.5.2.8,Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH,,,
2.5.2.9,Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH,,,
2.5.2.10,Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH,,,
2.5.2.11,Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH,,,
2.5.2.12,Cấu hình sử dụng các thuật toán mã hoá được cho phép,,,
2.5.2.13,Cấu hình các thuật toán MAC được cho phép,,,
2.5.2.14,Đảm bảo chỉ có thuật toán trao đổi khóa mạnh được sử dụng,,,
2.5.2.15,Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH,,,
2.5.2.16,Cấu hình SSH LoginGraceTime,,,
2.5.2.17,Cấu hình giới hạn truy cập cho máy chủ SSH,,,
2.5.2.18,Cấu hình cảnh báo SSH,,,
2.5.2.19,Cấu hình sử dụng SSH PAM,,,
2.5.2.20,Cấu hình SSH MaxStartups,,,
2.5.2.21,Cấu hình SSH MaxSessions,,,
2.5.3,Cấu hình PAM,,,
2.5.3.1,Cấu hình điều kiện tạo mật khẩu,,,
2.5.3.2,Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại,,,
2.5.3.3,Giới hạn việc sử dụng lại mật khẩu,,,
2.5.3.4,Cấu hình thuật toán hash mật khẩu mạnh,,,
2.5.4,Cấu hình tài khoản người dùng và môi trường,,,
,Cấu hình mật khẩu người dùng,,,
2.5.4.1,Cấu hình thời gian hết hạn sử dụng mật khẩu,,,
2.5.4.2,Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu,,,
2.5.4.3,Cấu hình thời gian cảnh báo mật khẩu hết hạn,,,
2.5.4.4,Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn,,,
2.5.4.5,Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ,,,
2.5.4.6, Đảm bảo group mặc định của tài khoản root là GID 0,,,
2.5.4.7,Cấu hình tham số user umask mặc định,,,
2.5.4.8,Đảm bảo shell timeout mặc định của người dùng là 900 giây hoặc ít hơn,,,
2.5.4.9,Cấu hình hạn chế truy cập cho câu lệnh su,,,
2.6,System Maintenance,,,
2.6.1,Quyền của file hệ thống,,,
2.6.1.1,"Cấu hình quyền cho file /etc/passwd /etc/shadow, /etc/group,",,,
,"/etc/gshadow, /etc/passwd-, /etc/shadow-, /etc/group-, /etc/gshadow-",,,
,Cấu hình phân quyền cho file /etc/passwd,,,
,Cấu hình phân quyền cho file /etc/shadow,,,
,Cấu hình phân quyền cho file /etc/group,,,
,Cấu hình phân quyền cho file /etc/gshadow,,,
,Cấu hình phân quyền cho file /etc/passwd-,,,
,Cấu hình phân quyền cho file /etc/shadow-,,,
,Cấu hình phân quyền cho file /etc/group-,,,
,Cấu hình phân quyền cho file /etc/gshadow-,,,
,Đảm bảo không có file world-writable tồn tại,,,
2.6.1.2,Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại,,,
2.6.1.3,Đảm bảo các file hoặc thư mục không có nhóm không tồn tại,,,
2.6.2,Thiết lập cho người dùng và nhóm,,,
2.6.2.1,Đảm bảo trường mật khẩu không để trống,,,
2.62.2,"Đảm bảo không có bản ghi chứa ""+"" trong file /etc/passwd",,,
2.6.2.3,Đảm bảo mọi người dùng đều tồn tại thư mục home,,,
2.6.2.4,"Đảm bảo không có bản ghi chứa ""+"" trong file /etc/shadow",,,
2.6.2.5,"Đảm bảo không có bản ghi chứa ""+"" trong file /etc/group",,,
2.6.2.6,Đảm bảo root là tài khoản duy nhất có UID là 0,,,
2.6.2.7,Đảm bảo tính toàn vẹn cho biến môi trường PATH của root,,,
2.6.2.8,Đảm bảo người dùng sở hữu thư mục home của chính họ,,,
2.6.2.9,Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc world-wide,,,
2.6.2.10,Đảm bảo không người dùng nào có file .forward,,,
2.6.2.11,Đảm bảo không người dùng nào có file .netrc,,,
2.6.2.12,Đảm bảo file netrc của người dùng không cấp quyền cho group hoặc other,,,
2.6.2.13,Đảm bảo không người dùng nào có file .rhosts,,,
2.6.2.14,Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group,,,
2.6.2.15,Đảm bảo UID không bị lặp,,,
2.6.2.16,Đảm bảo GID không bị lặp,,,
2.6.2.17,Đảm bảo tên người dùng không bị lặp,,,
2.6.2.18,Đảm bảo tên group không lặp,,,
2.6.2.19,Đảm bảo không có tài khoản trong shadow group,,,
Tổng,,,,
1 STT Hạng mục đánh giá Unnamed: 2 Unnamed: 3 Unnamed: 4
2 KẾT QUẢ
3
4 Đạt Không
5 2.1 Thiết lập ban đầu
6 2.1.1 Cấu hình filesystem
7 2.1.1.1 Cấu hình vô hiệu hoá cramfs, freevxfs, jffs2, hfs, hfsplus, squashfs, udf filesystem
8 Cấu hình vô hiệu hoá cramfs filesystem
9 Cấu hình vô hiệu hoá freevxfs filesystem
10 Cấu hình vô hiệu hoá hfs filesystem
11 Cấu hình vô hiệu hoá hfsplus filesystem
12 Cấu hình vô hiệu hoá jffs2 filesystem
13 Cấu hình vô hiệu hoá squashfs filesystem
14 Cấu hình vô hiệu hoá udf filesystem
15 Cấu hình vô hiệu hoá usb storage
16 Cấu hình phân vùng /tmp
17 2.1.1.2 Cấu hình tuỳ chọn nodev cho phân vùng /tmp
18 2.1.1.3 Cấu hình tuỳ chọn nosuid cho phân vùng /tmp
19 2.1.1.4 Cấu hình tuỳ chọn noexec cho phân vùng /tmp
20 Cấu hình phân vùng /var/tmp
21 2.1.1.5 Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp
22 2.1.1.6 Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp
23 2.1.1.7 Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp
24 Cấu hình phân vùng /home
25 2.1.1.8 Cấu hình tuỳ chọn nodev cho phân vùng /home
26 Cấu hình phân vùng /dev/shm
27 2.1.1.9 Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm
28 2.1.1.10 Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm
29 2.1.1.11 Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm
30 2.1.1.12 Cấu hình sticky bit cho tất cả các thư mục dùng chung
31 2.1.1.13 Cấu hình vô hiệu hoá automounting
32 2.1.2 Cấu hình sudo (áp dụng dành riêng cho Ubuntu)
33 2.1.2.1 Kiểm tra việc cài đặt sudo
34 2.1.2.2 Cấu hình các lệnh sudo sử dụng pty
35 2.1.2.3 Đảm bảo file nhật ký của sudo tồn tại
36 2.1.3 Cấu hình cập nhật phần mềm
37 2.1.3.1 Cấu hình kích hoạt gpgcheck
38 2.1.4 Kiểm tra tính toàn vẹn của filesystem
39 2.1.4.1 Kiểm tra việc cài đặt AIDE
40 2.1.4.2 Cấu hình kiểm tra tính toàn vẹn của filesystem
41 2.1.5 Cấu hình khởi động an toàn
42 2.1.5.1 Phân quyền đối với file cấu hình bootloader
43 2.1.5.2 Cấu hình mật khẩu cho bootloader
44 2.1.5.3 Cấu hình xác thực khi truy cập single user mode
45 2.1.5.4 Cấu hình vô hiệu hoá interactive boot
46 2.1.6 Additional Process Hardening
47 2.1.6.1 Cấu hình kiểm soát core dump
48 2.1.6.2 Cấu hình kích hoạt ASLR (address space layout randomization)
49 2.1.6.3 Cấu hình vô hiệu hoá prelink
50 2.1.7 Kiểm soát nội dung cảnh báo
51 2.1.7.1 Kiểm soát nội dung motd (Message Of The Day)
52 2.1.7.2 Kiểm soát nội dung thông báo khi đăng nhập
53 2.1.7.3 Kiểm soát nội dung thông báo khi đăng nhập từ xa
54 2.1.7.4 Cấu hình phân quyền đối với file /etc/motd
55 2.1.7.5 Cấu hình phân quyền đối với file /etc/issue
56 2.1.7.6 Cấu hình phân quyền đối với file /etc/issue.net
57 2.1.7.7 Kiểm soát nội dung thông báo khi truy cập GNOME
58 2.2 Service
59 2.2.1 Cấu hình inetd Service
60 2.2.1.1 Cấu hình vô hiệu hoá chargen service, daytime service,
61 discard service, echo service, time service, rsh, talk service, telnet, tftp, rsync, xinetd.
62 2.2.2 Các Service với mục đích riêng biệt
63 2.2.2.1 Cấu hình sử dụng NTP
64 2.2.2.2 Cấu hình sử dụng chrony
65 2.2.2.3 Cấu hình vô hiệu hoá X window, Avahi, CUPS, DHCP, LDAP, NFS, RPC, DNS , FTP, HTTP, POP3, IMAP, Samba, HTTP Proxy, SNMP, NIS
66 Cấu hình vô hiệu hoá xinetd services
67 Cấu hình vô hiệu hoá autofs services
68 Cấu hình vô hiệu hoá X window server services
69 Cấu hình vô hiệu hoá avahi daemon services
70 Cấu hình vô hiệu hoá cups services
71 Cấu hình vô hiệu hoá dhcp server services
72 Cấu hình vô hiệu hoá ldap server services
73 Cấu hình vô hiệu hoá dns server services
74 Cấu hình vô hiệu hoá dnsmasq services
75 Cấu hình vô hiệu hoá ftp server services
76 Cấu hình vô hiệu hoá tftp server services
77 Cấu hình vô hiệu hoá web server services
78 Cấu hình vô hiệu hoá imap and pop3 server services
79 Cấu hình vô hiệu hoá samba file server services
80 Cấu hình vô hiệu hoá web proxy server services
81 Cấu hình vô hiệu hoá snmp services
82 Cấu hình vô hiệu hoá nis server services
83 Cấu hình vô hiệu hoá network file system services
84 Cấu hình vô hiệu hoá rsync services
85 2.2.2.4 Cấu hình mail transfer agents sang chế độ local-only
86 2.2.3 Service Clients
87 2.2.3.1 Cấu hình xoá bỏ NIS client, rsh client, talk client, telnet client, LDAP client
88 Cấu hình vô hiệu hoá nis client
89 Cấu hình vô hiệu hoá rsh client
90 Cấu hình vô hiệu hoá talk client
91 Cấu hình vô hiệu hoá telnet client
92 Cấu hình vô hiệu hoá ldap client
93 Cấu hình vô hiệu hoá rpc
94 Cấu hình vô hiệu hoá ftp client
95 2.3 Cấu hình mạng
96 2.3.1 Tham số cấu hình mạng (Host Only)
97 2.3.1.1 Cấu hình vô hiệu hoá IP forwarding
98 2.3.1.2 Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)
99 2.3.2 Tham số cấu hình mạng (Host và Router)
100 2.3.2.1 Cấu hình từ chối các gói tin với nguồn được định tuyến trước
101 2.3.2.2 Cấu hình từ chối các ICMP redirect message
102 2.3.2.3 Cấu hình từ chối các secure ICMP redirect message
103 2.3.2.4 Ghi lại các gói tin khả nghi (Suspicious Packets)
104 2.3.2.5 Cấu hình từ chối các gói tin ICMP request broadcast
105 2.3.2.6 Cấu hình bỏ qua phản hồi ICMP không hợp lệ
106 2.3.2.7 Cấu hình Reverse Path Filtering
107 2.3.2.8 Cấu hình TCP SYN Cookies
108 2.3.3 TCP Wrappers
109 2.3.3.1 Kiêm tra việc cài đặt TCP Wrappers
110 2.3.3.2 Cấu hình file /etc/host.allow
111 2.3.3.3 Cấu hình file /etc/hosts.deny
112 2.3.3.4 Cấu hình quyền truy cập /etc/hosts.allow
113 2.3.3.5 Cấu hình quyền truy cập /etc/hosts.deny
114 2.3.4 Tưởng lửa (áp dụng dành riêng cho ubuntu)
115 2.3.4.1 Cài đặt tưởng lửa mềm (soft firewall)
116 2.3.4.1.1 Cài đặt Firewall package
117 2.3.4.2 Cấu hình ufw (UncomplicatedFirewal)
118 2.3.4.2.1 Cấu hình kích hoạt ufw
119 2.3.4.2.2 Cấu hình chính sách từ chối mặc định của tường lửa
120 2.3.4.2.3 Cấu hình loopback traffic
121 2.3.4.3 Cấu hình tường lửa nftable
122 2.3.4.3.1 Cấu hình tạo ít nhất 1 bảng trong nftable
123 2.3.4.3.2 Cấu hình các base chain
124 2.3.4.3.3 Cấu hình loopback traffic
125 2.3.4.3.4 Cấu hình chính sách từ chối mặc định của tường lửa
126 2.3.4.3.5 Cấu hình kích hoạt nftable
127 2.3.4.3.6 Cấu hình nftable rule
128 2.3.5 Iptables
129 2.3.5.1 Cấu hình kích hoạt Iptables
130 2.3.5.2 Cấu hình chính sách từ chối mặc định trên firewall
131 2.3.5.3 Cấu hình loopback traffic
132 2.3.5.4 Cấu hình iptables rule cho tất cả các port và protocol đang mở
133 2.4 Logging và Auditing
134 2.4.1 Cấu hình logging
135 2.4.1.1 Cấu hình rsyslog
136 2.4.1.1.1 Cấu hình kích hoạt rsyslog service
137 2.4.1.1.2 Phân quyền đối với file log sinh ra từ rsyslog
138 2.4.1.1.3 Cấu hình lưu trữ log sinh ra từ rsyslog tập trung
139 2.4.1.2 Phân quyền đối với tất cả các file log
140 Áp dụng đối với Centos
141 2.4.1.2.1 Cấu hình kích hoạt syslog-ng service
142 2.4.1.2.2 Phân quyền đối với file log sinh ra từ syslog-ng
143 2.4.1.2.3 Cấu hình lưu trữ log tập trung
144 2.4.1.3 Cấu hình journald
145 Áp dụng riêng cho ubuntu
146 2.4.1.3.1 Cấu hình journald để gửi file log đến rsyslog
147 2.4.1.3.2 Cấu hình journald để nén các file log lớn
148 2.4.1.3.3 Cấu hình journald để viết các logfile vào persistent disk
149 2.4.1.3.4 Đảm bảo các quyền trên toàn bộ logfile được cấu hình
150 2.4.1.4 Đảm bảo rsyslog hoặc syslog-ng được cài đặt
151 2.4.1.5 Phân quyền đối với tất cả các file log
152 2.5 Cấu hình truy cập, xác thực và ủy quyền
153 2.5.1 Cấu hình cron
154 2.5.1.1 Cấu hình kích hoạt cron daemon
155 2.5.1.2 Cấu hình phân quyền cho file /etc/crontab
156 2.5.1.2.1 Cấu hình phân quyền cho file /etc/cron.hourly
157 2.5.1.3 Cấu hình phân quyền cho file /etc/cron.daily
158 2.5.1.4 Cấu hình phân quyền cho file /etc/cron.weekly
159 2.5.1.5 Cấu hình phân quyền cho của file /etc/cron.monthly
160 2.5.1.6 Cấu hình phân quyền cho file /etc/cron.d
161 2.5.1.7 Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền
162 2.5.2 Cấu hình máy chủ SSH
163 2.5.2.1 Cấu hình quyền cho file /etc/ssh/sshd_config
164 2.5.2.1.1 Cấu hình quyền cho các file SSH private host
165 2.5.2.2 Cấu hình quyền cho các file SSH public host key
166 2.5.2.3 Cấu hình giao thức SSH sử dụng SSHv2
167 2.5.2.4 Cấu hình LogLevel cho máy chủ SSH
168 2.5.2.5 Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH
169 2.5.2.6 Cấu hình SSH MaxAuthTries
170 2.5.2.7 Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH
171 2.5.2.8 Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH
172 2.5.2.9 Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH
173 2.5.2.10 Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH
174 2.5.2.11 Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH
175 2.5.2.12 Cấu hình sử dụng các thuật toán mã hoá được cho phép
176 2.5.2.13 Cấu hình các thuật toán MAC được cho phép
177 2.5.2.14 Đảm bảo chỉ có thuật toán trao đổi khóa mạnh được sử dụng
178 2.5.2.15 Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH
179 2.5.2.16 Cấu hình SSH LoginGraceTime
180 2.5.2.17 Cấu hình giới hạn truy cập cho máy chủ SSH
181 2.5.2.18 Cấu hình cảnh báo SSH
182 2.5.2.19 Cấu hình sử dụng SSH PAM
183 2.5.2.20 Cấu hình SSH MaxStartups
184 2.5.2.21 Cấu hình SSH MaxSessions
185 2.5.3 Cấu hình PAM
186 2.5.3.1 Cấu hình điều kiện tạo mật khẩu
187 2.5.3.2 Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại
188 2.5.3.3 Giới hạn việc sử dụng lại mật khẩu
189 2.5.3.4 Cấu hình thuật toán hash mật khẩu mạnh
190 2.5.4 Cấu hình tài khoản người dùng và môi trường
191 Cấu hình mật khẩu người dùng
192 2.5.4.1 Cấu hình thời gian hết hạn sử dụng mật khẩu
193 2.5.4.2 Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu
194 2.5.4.3 Cấu hình thời gian cảnh báo mật khẩu hết hạn
195 2.5.4.4 Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn
196 2.5.4.5 Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ
197 2.5.4.6 Đảm bảo group mặc định của tài khoản root là GID 0
198 2.5.4.7 Cấu hình tham số user umask mặc định
199 2.5.4.8 Đảm bảo shell timeout mặc định của người dùng là 900 giây hoặc ít hơn
200 2.5.4.9 Cấu hình hạn chế truy cập cho câu lệnh su
201 2.6 System Maintenance
202 2.6.1 Quyền của file hệ thống
203 2.6.1.1 Cấu hình quyền cho file /etc/passwd /etc/shadow, /etc/group,
204 /etc/gshadow, /etc/passwd-, /etc/shadow-, /etc/group-, /etc/gshadow-
205 Cấu hình phân quyền cho file /etc/passwd
206 Cấu hình phân quyền cho file /etc/shadow
207 Cấu hình phân quyền cho file /etc/group
208 Cấu hình phân quyền cho file /etc/gshadow
209 Cấu hình phân quyền cho file /etc/passwd-
210 Cấu hình phân quyền cho file /etc/shadow-
211 Cấu hình phân quyền cho file /etc/group-
212 Cấu hình phân quyền cho file /etc/gshadow-
213 Đảm bảo không có file world-writable tồn tại
214 2.6.1.2 Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại
215 2.6.1.3 Đảm bảo các file hoặc thư mục không có nhóm không tồn tại
216 2.6.2 Thiết lập cho người dùng và nhóm
217 2.6.2.1 Đảm bảo trường mật khẩu không để trống
218 2.62.2 Đảm bảo không có bản ghi chứa "+" trong file /etc/passwd
219 2.6.2.3 Đảm bảo mọi người dùng đều tồn tại thư mục home
220 2.6.2.4 Đảm bảo không có bản ghi chứa "+" trong file /etc/shadow
221 2.6.2.5 Đảm bảo không có bản ghi chứa "+" trong file /etc/group
222 2.6.2.6 Đảm bảo root là tài khoản duy nhất có UID là 0
223 2.6.2.7 Đảm bảo tính toàn vẹn cho biến môi trường PATH của root
224 2.6.2.8 Đảm bảo người dùng sở hữu thư mục home của chính họ
225 2.6.2.9 Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc world-wide
226 2.6.2.10 Đảm bảo không người dùng nào có file .forward
227 2.6.2.11 Đảm bảo không người dùng nào có file .netrc
228 2.6.2.12 Đảm bảo file netrc của người dùng không cấp quyền cho group hoặc other
229 2.6.2.13 Đảm bảo không người dùng nào có file .rhosts
230 2.6.2.14 Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group
231 2.6.2.15 Đảm bảo UID không bị lặp
232 2.6.2.16 Đảm bảo GID không bị lặp
233 2.6.2.17 Đảm bảo tên người dùng không bị lặp
234 2.6.2.18 Đảm bảo tên group không lặp
235 2.6.2.19 Đảm bảo không có tài khoản trong shadow group
236 Tổng
@@ -0,0 +1,595 @@
{
"data": [
{
"4": "1. Thiết lập ban đầu"
},
{
"5": "1.1. Cấu hình filesystem"
},
{
"6": "1.1.1. Cấu hình vô hiệu hoá các filesystem không sử dụng"
},
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.1.8. Cấu hình vô hiệu hoá usb-storage filesystem"
},
{
"15": "1.1.2. Cấu hình phân vùng /tmp"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"19": "1.1.3. Cấu hình phân vùng /var/tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"23": "1.1.4. Cấu hình phân vùng /home"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"26": "1.1.5. Cấu hình phân vùng /dev/shm"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"30": "1.2. Cấu hình cập nhật phần mềm"
},
{
"31": "1.2.1. Cấu hình kích hoạt gpgcheck"
},
{
"32": "1.3. Kiểm tra tính toàn vẹn của filesystem"
},
{
"33": "1.3.1. Kiểm tra cài đặt AIDE"
},
{
"34": "1.3.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"35": "1.4. Cấu hình khởi động an toàn"
},
{
"36": "1.4.1. Phân quyền đối với file cấu hình bootloader"
},
{
"37": "1.4.2. Cấu hình xác thực khi truy cập rescue mode"
},
{
"38": "1.4.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"39": "1.4.4. Cấu hình vô hiệu hoá interactive boot"
},
{
"40": "1.5. Additional Process Hardening"
},
{
"41": "1.5.1. Cấu hình vô hiệu hoá core dump"
},
{
"42": "1.5.2. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"43": "1.5.3. Cấu hình vô hiệu hoá prelink"
},
{
"44": "1.6. Kiểm soát nội dung cảnh báo"
},
{
"45": "1.6.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"46": "1.6.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"47": "1.6.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"48": "1.6.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"49": "1.6.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"50": "1.6.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"51": "1.6.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"52": "2. Service"
},
{
"53": "2.1. Cấu hình Time Synchronization"
},
{
"54": "2.1.1. Cấu hình sử dụng chrony"
},
{
"55": "2.1.2. Cấu hình sử dụng NTP"
},
{
"56": "2.2. Các Service với mục đích riêng biệt"
},
{
"57": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"58": "2.2.2. Cấu hình vô hiệu hoá chargen services"
},
{
"59": "2.2.3. Cấu hình vô hiệu hoá daytime services"
},
{
"60": "2.2.4. Cấu hình vô hiệu hoá discard services"
},
{
"61": "2.2.5. Cấu hình vô hiệu hoá echo services"
},
{
"62": "2.2.6. Cấu hình vô hiệu hoá time services"
},
{
"63": "2.2.7. Cấu hình vô hiệu hoá rsh server"
},
{
"64": "2.2.8. Cấu hình vô hiệu hoá talk server"
},
{
"65": "2.2.9. Cấu hình vô hiệu hoá autofs services"
},
{
"66": "2.2.10. Cấu hình vô hiệu hoá X window server services"
},
{
"67": "2.2.11. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"68": "2.2.12. Cấu hình vô hiệu hoá cups services"
},
{
"69": "2.2.13. Cấu hình vô hiệu hoá dhcp server services"
},
{
"70": "2.2.14. Cấu hình vô hiệu hoá ldap server services"
},
{
"71": "2.2.15. Cấu hình vô hiệu hoá dns server services"
},
{
"72": "2.2.16. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"73": "2.2.17. Cấu hình vô hiệu hoá ftp server services"
},
{
"74": "2.2.18. Cấu hình vô hiệu hoá tftp server services"
},
{
"75": "2.2.19. Cấu hình vô hiệu hoá web server services"
},
{
"76": "2.2.20. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"77": "2.2.21. Cấu hình vô hiệu hoá samba file server services"
},
{
"78": "2.2.22. Cấu hình vô hiệu hoá web proxy server services"
},
{
"79": "2.2.23. Cấu hình vô hiệu hoá snmp services"
},
{
"80": "2.2.24. Cấu hình vô hiệu hoá nis server services"
},
{
"81": "2.2.25. Cấu hình vô hiệu hoá telnet server services"
},
{
"82": "2.2.26. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"83": "2.2.27. Cấu hình vô hiệu hoá network file system services"
},
{
"84": "2.2.28. Cấu hình vô hiệu hoá rpcbind services"
},
{
"85": "2.2.29. Cấu hình vô hiệu hoá rsync services"
},
{
"86": "2.3. Service Clients"
},
{
"87": "2.3.1. Cấu hình vô hiệu hoá NIS Client"
},
{
"88": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"89": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"90": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"91": "2.3.5. Cấu hình vô hiệu hoá LDAP client"
},
{
"92": "2.3.6. Cấu hình vô hiệu hoá ftp client"
},
{
"93": "2.3.7. Cấu hình vô hiệu hoá tftp client"
},
{
"94": "3. Cấu hình mạng"
},
{
"95": "3.1. Tham số cấu hình mạng (Host Only)"
},
{
"96": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"97": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"98": "3.2. Tham số cấu hình mạng (Host và Router)"
},
{
"99": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"100": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"101": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"102": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"103": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"104": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"105": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"106": "3.4. Cấu hình Firewall"
},
{
"107": "3.4.1. Cấu hình firewalld"
},
{
"108": "3.4.1.1. Cấu hình kích hoạt firewalld"
},
{
"109": "3.4.1.3. Cấu hình firewalld rule cho tất cả các port và protocol đang mở"
},
{
"110": "3.4.1.4. Cấu hình chính sách từ chối mặc định cho firewalld"
},
{
"111": "3.4.2. Iptables"
},
{
"112": "3.4.2.1. Cấu hình kích hoạt Iptables"
},
{
"113": "3.4.2.3. Cấu hình iptables loopback traffic"
},
{
"114": "3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"115": "3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"116": "4. Logging và Auditing"
},
{
"117": "4.1. Cấu hình logging"
},
{
"118": "4.1.1. Cấu hình rsyslog"
},
{
"119": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"120": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"121": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"122": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"123": "5. Cấu hình truy cập, xác thực và ủy quyền"
},
{
"124": "5.1. Cấu hình cron"
},
{
"125": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"126": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"127": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"128": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"129": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"130": "5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly"
},
{
"131": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"132": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền"
},
{
"133": "5.2. Cấu hình máy chủ SSH"
},
{
"134": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"135": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"136": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"137": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"138": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"139": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"140": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"141": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"142": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"143": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"144": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"145": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"146": "5.2.13. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"147": "5.2.14. Cấu hình cảnh báo SSH"
},
{
"148": "5.2.15. Cấu hình SSH MaxAuthTries"
},
{
"149": "5.2.16. Cấu hình SSH MaxStartups"
},
{
"150": "5.2.17. Cấu hình SSH MaxSessions"
},
{
"151": "5.2.18. Cấu hình SSH LoginGraceTime"
},
{
"152": "5.2.19. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"153": "5.2.20. Cấu hình các thuật toán MAC được cho phép"
},
{
"154": "5.3. Cấu hình PAM"
},
{
"155": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"156": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"157": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"158": "5.3.4. Cấu hình thuật toán hash mật khẩu sang SHA-512"
},
{
"159": "5.4. Cấu hình tài khoản người dùng và môi trường"
},
{
"160": "5.4.1. Cấu hình mật khẩu người dùng"
},
{
"161": "5.4.1.1. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"162": "5.4.1.2. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"163": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"164": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"165": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"166": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"167": "5.4.3. Cấu hình shell timeout mặc định"
},
{
"168": "5.4.4. Cấu hình group mặc định của tài khoản root"
},
{
"169": "5.4.5. Cấu hình user umask mặc định"
},
{
"170": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"171": "6. System Maintenance"
},
{
"172": "6.1. Quyền của file hệ thống"
},
{
"173": "6.1.1. Cấu hình sticky bit cho tất cả các thư mục dùng chung"
},
{
"174": "6.1.2. Cấu hình phân quyền cho file /etc/passwd"
},
{
"175": "6.1.3. Cấu hình phân quyền cho file /etc/shadow"
},
{
"176": "6.1.4. Cấu hình phân quyền cho file /etc/group"
},
{
"177": "6.1.5. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"178": "6.1.6. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"179": "6.1.7. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"180": "6.1.8. Cấu hình phân quyền cho file /etc/group-"
},
{
"181": "6.1.9. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"182": "6.1.10. Đảm bảo không có file world-writable tồn tại"
},
{
"183": "6.1.11. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"184": "6.1.12. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"185": "6.2. Thiết lập cho người dùng và nhóm"
},
{
"186": "6.2.1. Đảm bảo trường mật khẩu không để trống"
},
{
"187": "6.2.2. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"188": "6.2.3. Đảm bảo UID không bị lặp"
},
{
"189": "6.2.4. Đảm bảo GID không bị lặp"
},
{
"190": "6.2.5. Đảm bảo tên người dùng không bị lặp"
},
{
"191": "6.2.6. Đảm bảo tên group không bị lặp"
},
{
"192": "6.2.7. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"193": "6.2.8. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"194": "6.2.9. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"195": "6.2.10. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"196": "6.2.11. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"197": "6.2.12. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
},
{
"198": "6.2.13. Đảm bảo không người dùng nào có file .forward"
},
{
"199": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"200": "6.2.15. Đảm bảo không người dùng nào có file .rhosts"
}
]
}
@@ -0,0 +1,484 @@
{
"data": [
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.1.8. Cấu hình vô hiệu hoá usb storage"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"31": "1.2.1. Cấu hình kích hoạt gpgcheck"
},
{
"33": "1.3.1. Kiểm tra cài đặt AIDE"
},
{
"34": "1.3.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"36": "1.4.1. Phân quyền đối với file cấu hình bootloader"
},
{
"37": "1.4.2. Cấu hình mật khẩu cho bootloader"
},
{
"38": "1.4.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"39": "1.4.4. Cấu hình vô hiệu hoá interactive boot"
},
{
"41": "1.5.1. Cấu hình vô hiệu hoá core dump"
},
{
"42": "1.5.2. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"43": "1.5.3. Cấu hình vô hiệu hoá prelink"
},
{
"45": "1.6.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"46": "1.6.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"47": "1.6.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"48": "1.6.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"49": "1.6.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"50": "1.6.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"51": "1.6.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"54": "2.1.1. Cấu hình sử dụng chrony"
},
{
"55": "2.1.2. Cấu hình sử dụng ntp"
},
{
"57": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"58": "2.2.2. Cấu hình vô hiệu hoá chargen services"
},
{
"59": "2.2.3. Cấu hình vô hiệu hoá daytime services"
},
{
"60": "2.2.4. Cấu hình vô hiệu hoá discard services"
},
{
"61": "2.2.5. Cấu hình vô hiệu hoá echo services"
},
{
"62": "2.2.6. Cấu hình vô hiệu hoá time services"
},
{
"63": "2.2.7. Cấu hình vô hiệu hoá rsh server"
},
{
"64": "2.2.8. Cấu hình vô hiệu hoá talk server"
},
{
"65": "2.2.9. Cấu hình vô hiệu hoá autofs services"
},
{
"66": "2.2.10. Cấu hình vô hiệu hoá X window server services"
},
{
"67": "2.2.11. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"68": "2.2.12. Cấu hình vô hiệu hoá cups services"
},
{
"69": "2.2.13. Cấu hình vô hiệu hoá dhcp server services"
},
{
"70": "2.2.14. Cấu hình vô hiệu hoá ldap server services"
},
{
"71": "2.2.15. Cấu hình vô hiệu hoá dns server services"
},
{
"72": "2.2.16. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"73": "2.2.17. Cấu hình vô hiệu hoá ftp server services"
},
{
"74": "2.2.18. Cấu hình vô hiệu hoá tftp server services"
},
{
"75": "2.2.19. Cấu hình vô hiệu hoá web server services"
},
{
"76": "2.2.20. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"77": "2.2.21. Cấu hình vô hiệu hoá samba file server services"
},
{
"78": "2.2.22. Cấu hình vô hiệu hoá web proxy server services"
},
{
"79": "2.2.23. Cấu hình vô hiệu hoá snmp services"
},
{
"80": "2.2.24. Cấu hình vô hiệu hoá nis server services"
},
{
"81": "2.2.25. Cấu hình vô hiệu hoá telnet server services"
},
{
"82": "2.2.26. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"83": "2.2.27. Cấu hình vô hiệu hoá network file system services"
},
{
"84": "2.2.28. Cấu hình vô hiệu hoá rpcbind services"
},
{
"85": "2.2.29. Cấu hình vô hiệu hoá rsync services"
},
{
"87": "2.3.1. Cấu hình vô hiệu hoá nis client"
},
{
"88": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"89": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"90": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"91": "2.3.5. Cấu hình vô hiệu hoá ldap client"
},
{
"92": "2.3.6. Cấu hình vô hiệu hoá ftp client"
},
{
"93": "2.3.7. Cấu hình vô hiệu hoá tftp client"
},
{
"96": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"97": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"99": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"100": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"101": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"102": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"103": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"104": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"105": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"108": "3.3.1.1. Cấu hình kích hoạt Iptables"
},
{
"109": "3.3.1.2. Cấu hình iptables loopback traffic"
},
{
"110": "3.3.1.3. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"111": "3.3.1.4. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"115": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"116": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"117": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"118": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"121": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"122": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"123": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"124": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"125": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"126": "5.1.6. Cấu hình phân quyền cho file /etc/cron.monthly"
},
{
"127": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"128": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được uỷ quyền"
},
{
"130": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"131": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"132": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"133": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"134": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"135": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"136": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"137": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"138": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"139": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"140": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"141": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"142": "5.2.13. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"143": "5.2.14. Cấu hình cảnh báo SSH"
},
{
"144": "5.2.15. Cấu hình SSH MaxAuthTries"
},
{
"145": "5.2.16. Cấu hình SSH MaxStartups"
},
{
"146": "5.2.17. Cấu hình SSH MaxSessions"
},
{
"147": "5.2.18. Cấu hình SSH LoginGraceTime"
},
{
"148": "5.2.19. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"149": "5.2.20. Cấu hình các thuật toán MAC được cho phép"
},
{
"151": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"152": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"153": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"154": "5.3.4. Cấu hình thuật toán hash mật khẩu sang SHA-512"
},
{
"157": "5.4.1.1. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"158": "5.4.1.2. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"159": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"160": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"161": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"162": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"163": "5.4.3. Cấu hình shell timeout mặc định"
},
{
"164": "5.4.4. Cấu hình group mặc định của tài khoản root"
},
{
"165": "5.4.5. Cấu hình user umask mặc định"
},
{
"166": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"169": "6.1.1. Cấu hình sticky bit cho tất cả các thư mục dùng chung"
},
{
"170": "6.1.2. Cấu hình phân quyền cho file /etc/passwd"
},
{
"171": "6.1.3. Cấu hình phân quyền cho file /etc/shadow"
},
{
"172": "6.1.4. Cấu hình phân quyền cho file /etc/group"
},
{
"173": "6.1.5. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"174": "6.1.6. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"175": "6.1.7. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"176": "6.1.8. Cấu hình phân quyền cho file /etc/group-"
},
{
"177": "6.1.9. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"178": "6.1.10. Đảm bảo không có file world-writable tồn tại"
},
{
"179": "6.1.11. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"180": "6.1.12. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"182": "6.2.1. Đảm bảo trường mật khẩu không để trống"
},
{
"183": "6.2.2. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"184": "6.2.3. Đảm bảo UID không bị lặp"
},
{
"185": "6.2.4. Đảm bảo GID không bị lặp"
},
{
"186": "6.2.5. Đảm bảo tên người dùng không bị lặp"
},
{
"187": "6.2.6. Đảm bảo tên group không bị lặp"
},
{
"188": "6.2.7. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"189": "6.2.8. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"190": "6.2.9. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"191": "6.2.10. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"192": "6.2.11. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"193": "6.2.12. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
},
{
"194": "6.2.13. Đảm bảo không người dùng nào có file .forward"
},
{
"195": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"196": "6.2.15. Đảm bảo không người dùng nào có file .rhosts"
}
]
}
@@ -0,0 +1,595 @@
{
"data": [
{
"": "1. Thiết lập ban đầu"
},
{
"": "1.1. Cấu hình filesystem"
},
{
"": "1.1.1. Cấu hình vô hiệu hoá các filesystem không sử dụng"
},
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.1.8. Cấu hình vô hiệu hoá usb-storage filesystem"
},
{
"15": "1.1.2. Cấu hình phân vùng /tmp"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"19": "1.1.3. Cấu hình phân vùng /var/tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"23": "1.1.4. Cấu hình phân vùng /home"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"26": "1.1.5. Cấu hình phân vùng /dev/shm"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"30": "1.2. Cấu hình cập nhật phần mềm"
},
{
"31": "1.2.1. Cấu hình kích hoạt gpgcheck"
},
{
"32": "1.3. Kiểm tra tính toàn vẹn của filesystem"
},
{
"33": "1.3.1. Kiểm tra cài đặt AIDE"
},
{
"34": "1.3.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"35": "1.4. Cấu hình khởi động an toàn"
},
{
"36": "1.4.1. Phân quyền đối với file cấu hình bootloader"
},
{
"37": "1.4.2. Cấu hình xác thực khi truy cập rescue mode"
},
{
"38": "1.4.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"39": "1.4.4. Cấu hình vô hiệu hoá interactive boot"
},
{
"40": "1.5. Additional Process Hardening"
},
{
"41": "1.5.1. Cấu hình vô hiệu hoá core dump"
},
{
"42": "1.5.2. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"43": "1.5.3. Cấu hình vô hiệu hoá prelink"
},
{
"44": "1.6. Kiểm soát nội dung cảnh báo"
},
{
"45": "1.6.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"46": "1.6.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"47": "1.6.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"48": "1.6.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"49": "1.6.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"50": "1.6.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"51": "1.6.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"52": "2. Service"
},
{
"53": "2.1. Cấu hình Time Synchronization"
},
{
"54": "2.1.1. Cấu hình sử dụng chrony"
},
{
"55": "2.1.2. Cấu hình sử dụng NTP"
},
{
"56": "2.2. Các Service với mục đích riêng biệt"
},
{
"57": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"58": "2.2.2. Cấu hình vô hiệu hoá chargen services"
},
{
"59": "2.2.3. Cấu hình vô hiệu hoá daytime services"
},
{
"60": "2.2.4. Cấu hình vô hiệu hoá discard services"
},
{
"61": "2.2.5. Cấu hình vô hiệu hoá echo services"
},
{
"62": "2.2.6. Cấu hình vô hiệu hoá time services"
},
{
"63": "2.2.7. Cấu hình vô hiệu hoá rsh server"
},
{
"64": "2.2.8. Cấu hình vô hiệu hoá talk server"
},
{
"65": "2.2.9. Cấu hình vô hiệu hoá autofs services"
},
{
"66": "2.2.10. Cấu hình vô hiệu hoá X window server services"
},
{
"67": "2.2.11. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"68": "2.2.12. Cấu hình vô hiệu hoá cups services"
},
{
"69": "2.2.13. Cấu hình vô hiệu hoá dhcp server services"
},
{
"70": "2.2.14. Cấu hình vô hiệu hoá ldap server services"
},
{
"71": "2.2.15. Cấu hình vô hiệu hoá dns server services"
},
{
"72": "2.2.16. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"73": "2.2.17. Cấu hình vô hiệu hoá ftp server services"
},
{
"74": "2.2.18. Cấu hình vô hiệu hoá tftp server services"
},
{
"75": "2.2.19. Cấu hình vô hiệu hoá web server services"
},
{
"76": "2.2.20. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"77": "2.2.21. Cấu hình vô hiệu hoá samba file server services"
},
{
"78": "2.2.22. Cấu hình vô hiệu hoá web proxy server services"
},
{
"79": "2.2.23. Cấu hình vô hiệu hoá snmp services"
},
{
"80": "2.2.24. Cấu hình vô hiệu hoá nis server services"
},
{
"81": "2.2.25. Cấu hình vô hiệu hoá telnet server services"
},
{
"82": "2.2.26. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"83": "2.2.27. Cấu hình vô hiệu hoá network file system services"
},
{
"84": "2.2.28. Cấu hình vô hiệu hoá rpcbind services"
},
{
"85": "2.2.29. Cấu hình vô hiệu hoá rsync services"
},
{
"86": "2.3. Service Clients"
},
{
"87": "2.3.1. Cấu hình vô hiệu hoá NIS Client"
},
{
"88": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"89": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"90": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"91": "Cấu hình vô hiệu hoá LDAP client"
},
{
"92": "2.3.6. Cấu hình vô hiệu hoá ftp client"
},
{
"93": "2.3.7. Cấu hình vô hiệu hoá tftp client"
},
{
"94": "3. Cấu hình mạng"
},
{
"95": "3.1. Tham số cấu hình mạng (Host Only)"
},
{
"96": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"97": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"98": "3.2. Tham số cấu hình mạng (Host và Router)"
},
{
"99": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"100": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"101": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"102": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"103": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"104": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"105": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"106": "3.4. Cấu hình Firewall"
},
{
"107": "3.4.1. Cấu hình firewalld"
},
{
"108": "3.4.1.1. Cấu hình kích hoạt firewalld"
},
{
"109": "3.4.1.3. Cấu hình firewalld rule cho tất cả các port và protocol đang mở"
},
{
"110": "3.4.1.4. Cấu hình chính sách từ chối mặc định cho firewalld"
},
{
"111": "3.4.2. Iptables"
},
{
"112": "3.4.2.1. Cấu hình kích hoạt Iptables"
},
{
"113": "3.4.2.3. Cấu hình iptables loopback traffic"
},
{
"114": "3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"115": "3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"116": "4. Logging và Auditing"
},
{
"117": "4.1. Cấu hình logging"
},
{
"118": "4.1.1. Cấu hình rsyslog"
},
{
"119": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"120": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"121": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"122": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"123": "5. Cấu hình truy cập, xác thực và ủy quyền"
},
{
"124": "5.1. Cấu hình cron"
},
{
"125": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"126": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"127": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"128": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"129": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"130": "5.1.6. Cấu hình phân quyền cho file /etc/cron.monthly"
},
{
"131": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"132": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền"
},
{
"133": "5.2. Cấu hình máy chủ SSH"
},
{
"134": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"135": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"136": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"137": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"138": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"139": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"140": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"141": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"142": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"143": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"144": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"145": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"146": "5.2.13. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"147": "5.2.14. Cấu hình cảnh báo SSH"
},
{
"148": "5.2.15. Cấu hình SSH MaxAuthTries"
},
{
"149": "5.2.16. Cấu hình SSH MaxStartups"
},
{
"150": "5.2.17. Cấu hình SSH MaxSessions"
},
{
"151": "5.2.18. Cấu hình SSH LoginGraceTime"
},
{
"152": "5.2.19. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"153": "5.2.20. Cấu hình các thuật toán MAC được cho phép"
},
{
"154": "5.3. Cấu hình PAM"
},
{
"155": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"156": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"157": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"158": "5.3.4. Cấu hình thuật toán hash mật khẩu sang SHA-512"
},
{
"159": "5.4. Cấu hình tài khoản người dùng và môi trường"
},
{
"160": "5.4.1. Cấu hình mật khẩu người dùng"
},
{
"161": "5.4.1.1. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"162": "5.4.1.2. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"163": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"164": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"165": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"166": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"167": "5.4.3. Cấu hình shell timeout mặc định"
},
{
"168": "5.4.4. Cấu hình group mặc định của tài khoản root"
},
{
"169": "5.4.5. Cấu hình user umask mặc định"
},
{
"170": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"171": "6. System Maintenance"
},
{
"172": "6.1. Quyền của file hệ thống"
},
{
"173": "6.1.1. Cấu hình sticky bit cho tất cả các thư mục dùng chung"
},
{
"174": "6.1.2. Cấu hình phân quyền cho file /etc/passwd"
},
{
"175": "6.1.3. Cấu hình phân quyền cho file /etc/shadow"
},
{
"176": "6.1.4. Cấu hình phân quyền cho file /etc/group"
},
{
"177": "6.1.5. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"178": "6.1.6. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"179": "6.1.7. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"180": "6.1.8. Cấu hình phân quyền cho file /etc/group-"
},
{
"181": "6.1.9. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"182": "6.1.10. Đảm bảo không có file world-writable tồn tại"
},
{
"183": "6.1.11. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"184": "6.1.12. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"185": "6.2. Thiết lập cho người dùng và nhóm"
},
{
"186": "6.2.1. Đảm bảo trường mật khẩu không để trống"
},
{
"187": "6.2.2. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"188": "6.2.3. Đảm bảo UID không bị lặp"
},
{
"189": "6.2.4. Đảm bảo GID không bị lặp"
},
{
"190": "6.2.5. Đảm bảo tên người dùng không bị lặp"
},
{
"191": "6.2.6. Đảm bảo tên group không bị lặp"
},
{
"192": "6.2.7. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"193": "6.2.8. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"194": "6.2.9. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"195": "6.2.10. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"196": "6.2.11. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"197": "6.2.12. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
},
{
"198": "6.2.13. Đảm bảo không người dùng nào có file .forward"
},
{
"199": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"200": "6.2.15. Đảm bảo không người dùng nào có file .rhosts"
}
]
}
@@ -0,0 +1,577 @@
{
"data": [
{
"": "1. Thiết lập ban đầu"
},
{
"": "1.1. Cấu hình filesystem"
},
{
"": "1.1.1. Cấu hình vô hiệu hoá các filesystem không sử dụng"
},
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.8. Cấu hình vô hiệu hoá usb storage"
},
{
"15": "1.1.2. Cấu hình phân vùng /tmp"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"19": "1.1.3. Cấu hình phân vùng /var/tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"23": "1.1.4. Cấu hình phân vùng /home"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"26": "1.1.5. Cấu hình phân vùng /dev/shm"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"30": "1.2. Kiểm tra tính toàn vẹn của filesystem"
},
{
"31": "1.2.1. Kiểm tra cài đặt AIDE"
},
{
"32": "1.2.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"33": "1.3. Cấu hình khởi động an toàn"
},
{
"34": "1.3.1. Phân quyền đối với file cấu hình bootloader"
},
{
"35": "1.3.1. Phân quyền đối với file cấu hình bootloader"
},
{
"36": "1.3.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"37": "1.4. Additional Process Hardening"
},
{
"38": "1.4.1. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"39": "1.4.2. Cấu hình vô hiệu hoá prelink"
},
{
"40": "1.4.3. Cấu hình vô hiệu hoá core dump"
},
{
"41": "1.5. Kiểm soát nội dung cảnh báo"
},
{
"42": "1.5.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"43": "1.5.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"44": "1.5.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"45": "1.5.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"46": "1.5.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"47": "1.5.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"48": "1.5.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"49": "2. Service"
},
{
"50": "2.1. Cấu hình Time Synchronization"
},
{
"51": "2.1.1. Cấu hình sử dụng chrony"
},
{
"52": "2.1.2. Cấu hình sử dụng NTP"
},
{
"53": "2.2. Các Service với mục đích riêng biệt"
},
{
"54": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"55": "2.2.2. Cấu hình vô hiệu hoá autofs services"
},
{
"56": "2.2.3. Cấu hình vô hiệu hoá X window server services"
},
{
"57": "2.2.4. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"58": "2.2.5. Cấu hình vô hiệu hoá cups services"
},
{
"59": "2.2.6. Cấu hình vô hiệu hoá dhcp server services"
},
{
"60": "2.2.7. Cấu hình vô hiệu hoá ldap server services"
},
{
"61": "2.2.8. Cấu hình vô hiệu hoá dns server services"
},
{
"62": "2.2.9. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"63": "2.2.10. Cấu hình vô hiệu hoá ftp server services"
},
{
"64": "2.2.11. Cấu hình vô hiệu hoá tftp server services"
},
{
"65": "2.2.12. Cấu hình vô hiệu hoá web server services"
},
{
"66": "2.2.13. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"67": "2.2.14. Cấu hình vô hiệu hoá samba file server services"
},
{
"68": "2.2.15. Cấu hình vô hiệu hoá web proxy server services"
},
{
"69": "2.2.16. Cấu hình vô hiệu hoá snmp services"
},
{
"70": "2.2.17. Cấu hình vô hiệu hoá nis server services"
},
{
"71": "2.2.18. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"72": "2.2.19. Cấu hình vô hiệu hoá network file system services"
},
{
"73": "2.2.20. Cấu hình vô hiệu hoá rsync services"
},
{
"74": "2.3. Service Clients"
},
{
"75": "2.3.1. Cấu hình vô hiệu hoá nis client"
},
{
"76": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"77": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"78": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"79": "2.3.5. Cấu hình vô hiệu hoá ldap client"
},
{
"80": "2.3.6. Cấu hình vô hiệu hoá rpc"
},
{
"81": "2.3.7. Cấu hình vô hiệu hoá ftp client"
},
{
"82": "3. Cấu hình mạng"
},
{
"83": "3.1. Tham số cấu hình mạng (Host Only)"
},
{
"84": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"85": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"86": "3.2. Tham số cấu hình mạng (Host và Router)"
},
{
"87": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"88": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"89": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"90": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"91": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"92": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"93": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"94": "3.4. Cấu hình Firewall"
},
{
"95": "3.4.1. Cấu hình Uncomplicated Firewall"
},
{
"96": "3.4.1.1. Cấu hình kích hoạt ufw"
},
{
"97": "3.4.1.2. Cấu hình vô hiệu hoá iptables-persistent, nftables khi sử dụng ufw"
},
{
"98": "3.4.1.3. Cấu hình ufw loopback traffic"
},
{
"99": "3.4.1.4. Cấu hình ufw rule cho tất cả các port và protocol đang mở"
},
{
"100": "3.4.1.5. Cấu hình chính sách từ chối mặc định cho ufw"
},
{
"101": "3.4.2. Iptables"
},
{
"102": "3.4.2.1. Cấu hình kích hoạt Iptables"
},
{
"103": "3.4.2.2. Cấu hình vô hiệu hoá ufw, nftables khi sử dụng iptables"
},
{
"104": "3.4.2.3. Cấu hình iptables loopback traffic"
},
{
"105": "3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"106": "3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"107": "4. Logging và Auditing"
},
{
"108": "4.1. Cấu hình logging"
},
{
"109": "4.1.1. Cấu hình rsyslog"
},
{
"110": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"111": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"112": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"113": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"114": "5. Cấu hình truy cập, xác thực và ủy quyền"
},
{
"115": "5.1. Cấu hình cron"
},
{
"116": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"117": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"118": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"119": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"120": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"121": "5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly"
},
{
"122": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"123": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền"
},
{
"124": "5.2. Cấu hình máy chủ SSH"
},
{
"125": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"126": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"127": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"128": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"129": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"130": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"131": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"132": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"133": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"134": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"135": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"136": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"137": "5.2.13. Cấu hình sử dụng các thuật toán mã hoá được cho phép"
},
{
"138": "5.2.14. Cấu hình các thuật toán MAC được cho phép"
},
{
"139": "5.2.15. Cấu hình thuật toán trao đổi khoá được cho phép"
},
{
"140": "5.2.16. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"141": "5.2.17. Cấu hình cảnh báo SSH"
},
{
"142": "5.2.18. Cấu hình SSH MaxAuthTries"
},
{
"143": "5.2.19. Cấu hình SSH MaxStartups"
},
{
"144": "5.2.20. Cấu hình SSH MaxSessions"
},
{
"145": "5.2.21. Cấu hình SSH LoginGraceTime"
},
{
"146": "5.2.22. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"147": "5.3. Cấu hình PAM"
},
{
"148": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"149": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"150": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"151": "5.3.4. Cấu hình thuật toán hash mật khẩu mạnh"
},
{
"152": "5.4. Cấu hình tài khoản người dùng và môi trường"
},
{
"153": "5.4.1. Cấu hình mật khẩu người dùng"
},
{
"154": "5.4.1.1. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"155": "5.4.1.2. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"156": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"157": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"158": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"159": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"160": "5.4.3. Cấu hình group mặc định của tài khoản root"
},
{
"161": "5.4.4. Cấu hình user umask mặc định"
},
{
"162": "5.4.5. Cấu hình shell timeout mặc định"
},
{
"163": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"164": "6. System Maintenance"
},
{
"165": "6.1. Quyền của file hệ thống"
},
{
"166": "6.1.1. Cấu hình phân quyền cho file /etc/passwd"
},
{
"167": "6.1.2. Cấu hình phân quyền cho file /etc/shadow"
},
{
"168": "6.1.3. Cấu hình phân quyền cho file /etc/group"
},
{
"169": "6.1.4. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"170": "6.1.5. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"171": "6.1.6. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"172": "6.1.7. Cấu hình phân quyền cho file /etc/group-"
},
{
"173": "6.1.8. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"174": "6.1.9. Đảm bảo không có file world-writable tồn tại"
},
{
"175": "6.1.10. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"176": "6.1.11. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"177": "6.2. Thiết lập cho người dùng và nhóm"
},
{
"178": "6.2.1. Cấu hình tài khoản trong /etc/passwd sử dụng shadowed passwords"
},
{
"179": "6.2.2. Đảm bảo trường mật khẩu không để trống"
},
{
"180": "6.2.3. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"181": "6.2.4. Đảm bảo shadow group rỗng"
},
{
"182": "6.2.5. Đảm bảo UID không bị lặp"
},
{
"183": "6.2.6. Đảm bảo GID không bị lặp"
},
{
"184": "6.2.7. Đảm bảo tên người dùng không bị lặp"
},
{
"185": "6.2.8. Đảm bảo tên group không bị lặp"
},
{
"186": "6.2.9. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"187": "6.2.10. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"188": "6.2.11. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"189": "6.2.12. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"190": "6.2.13. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"191": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"192": "6.2.15. Đảm bảo không người dùng nào có file .forward"
},
{
"193": "6.2.16. Đảm bảo không người dùng nào có file .rhosts"
},
{
"194": "6.2.17. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
}
]
}
@@ -0,0 +1,577 @@
{
"data": [
{
"": "1. Thiết lập ban đầu"
},
{
"": "1.1. Cấu hình filesystem"
},
{
"": "1.1.1. Cấu hình vô hiệu hoá các filesystem không sử dụng"
},
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.8. Cấu hình vô hiệu hoá usb storage"
},
{
"15": "1.1.2. Cấu hình phân vùng /tmp"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"19": "1.1.3. Cấu hình phân vùng /var/tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"23": "1.1.4. Cấu hình phân vùng /home"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"26": "1.1.5. Cấu hình phân vùng /dev/shm"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"30": "1.2. Kiểm tra tính toàn vẹn của filesystem"
},
{
"31": "1.2.1. Kiểm tra cài đặt AIDE"
},
{
"32": "1.2.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"33": "1.3. Cấu hình khởi động an toàn"
},
{
"34": "1.3.1. Phân quyền đối với file cấu hình bootloader"
},
{
"35": "1.3.1. Phân quyền đối với file cấu hình bootloader"
},
{
"36": "1.3.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"37": "1.4. Additional Process Hardening"
},
{
"38": "1.4.1. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"39": "1.4.2. Cấu hình vô hiệu hoá prelink"
},
{
"40": "1.4.3. Cấu hình vô hiệu hoá core dump"
},
{
"41": "1.5. Kiểm soát nội dung cảnh báo"
},
{
"42": "1.5.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"43": "1.5.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"44": "1.5.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"45": "1.5.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"46": "1.5.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"47": "1.5.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"48": "1.5.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"49": "2. Service"
},
{
"50": "2.1. Cấu hình Time Synchronization"
},
{
"51": "2.1.1. Cấu hình sử dụng chrony"
},
{
"52": "2.1.2. Cấu hình sử dụng NTP"
},
{
"53": "2.2. Các Service với mục đích riêng biệt"
},
{
"54": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"55": "2.2.2. Cấu hình vô hiệu hoá autofs services"
},
{
"56": "2.2.3. Cấu hình vô hiệu hoá X window server services"
},
{
"57": "2.2.4. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"58": "2.2.5. Cấu hình vô hiệu hoá cups services"
},
{
"59": "2.2.6. Cấu hình vô hiệu hoá dhcp server services"
},
{
"60": "2.2.7. Cấu hình vô hiệu hoá ldap server services"
},
{
"61": "2.2.8. Cấu hình vô hiệu hoá dns server services"
},
{
"62": "2.2.9. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"63": "2.2.10. Cấu hình vô hiệu hoá ftp server services"
},
{
"64": "2.2.11. Cấu hình vô hiệu hoá tftp server services"
},
{
"65": "2.2.12. Cấu hình vô hiệu hoá web server services"
},
{
"66": "2.2.13. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"67": "2.2.14. Cấu hình vô hiệu hoá samba file server services"
},
{
"68": "2.2.15. Cấu hình vô hiệu hoá web proxy server services"
},
{
"69": "2.2.16. Cấu hình vô hiệu hoá snmp services"
},
{
"70": "2.2.17. Cấu hình vô hiệu hoá nis server services"
},
{
"71": "2.2.18. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"72": "2.2.19. Cấu hình vô hiệu hoá network file system services"
},
{
"73": "2.2.20. Cấu hình vô hiệu hoá rsync services"
},
{
"74": "2.3. Service Clients"
},
{
"75": "2.3.1. Cấu hình vô hiệu hoá nis client"
},
{
"76": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"77": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"78": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"79": "2.3.5. Cấu hình vô hiệu hoá ldap client"
},
{
"80": "2.3.6. Cấu hình vô hiệu hoá rpc"
},
{
"81": "2.3.7. Cấu hình vô hiệu hoá ftp client"
},
{
"82": "3. Cấu hình mạng"
},
{
"83": "3.1. Tham số cấu hình mạng (Host Only)"
},
{
"84": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"85": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"86": "3.2. Tham số cấu hình mạng (Host và Router)"
},
{
"87": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"88": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"89": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"90": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"91": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"92": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"93": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"94": "3.4. Cấu hình Firewall"
},
{
"95": "3.4.1. Cấu hình Uncomplicated Firewall"
},
{
"96": "3.4.1.1. Cấu hình kích hoạt ufw"
},
{
"97": "3.4.1.2. Cấu hình vô hiệu hoá iptables-persistent, nftables khi sử dụng ufw"
},
{
"98": "3.4.1.3. Cấu hình ufw loopback traffic"
},
{
"99": "3.4.1.4. Cấu hình ufw rule cho tất cả các port và protocol đang mở"
},
{
"100": "3.4.1.5. Cấu hình chính sách từ chối mặc định cho ufw"
},
{
"101": "3.4.2. Iptables"
},
{
"102": "3.4.2.1. Cấu hình kích hoạt Iptables"
},
{
"103": "3.4.2.2. Cấu hình vô hiệu hoá ufw, nftables khi sử dụng iptables"
},
{
"104": "3.4.2.3. Cấu hình iptables loopback traffic"
},
{
"105": "3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"106": "3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"107": "4. Logging và Auditing"
},
{
"108": "4.1. Cấu hình logging"
},
{
"109": "4.1.1. Cấu hình rsyslog"
},
{
"110": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"111": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"112": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"113": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"114": "5. Cấu hình truy cập, xác thực và ủy quyền"
},
{
"115": "5.1. Cấu hình cron"
},
{
"116": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"117": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"118": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"119": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"120": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"121": "5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly"
},
{
"122": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"123": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền"
},
{
"124": "5.2. Cấu hình máy chủ SSH"
},
{
"125": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"126": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"127": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"128": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"129": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"130": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"131": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"132": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"133": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"134": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"135": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"136": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"137": "5.2.13. Cấu hình sử dụng các thuật toán mã hoá được cho phép"
},
{
"138": "5.2.14. Cấu hình các thuật toán MAC được cho phép"
},
{
"139": "5.2.15. Cấu hình thuật toán trao đổi khoá được cho phép"
},
{
"140": "5.2.16. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"141": "5.2.17. Cấu hình cảnh báo SSH"
},
{
"142": "5.2.18. Cấu hình SSH MaxAuthTries"
},
{
"143": "5.2.19. Cấu hình SSH MaxStartups"
},
{
"144": "5.2.20. Cấu hình SSH MaxSessions"
},
{
"145": "5.2.21. Cấu hình SSH LoginGraceTime"
},
{
"146": "5.2.22. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"147": "5.3. Cấu hình PAM"
},
{
"148": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"149": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"150": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"151": "5.3.4. Cấu hình thuật toán hash mật khẩu mạnh"
},
{
"152": "5.4. Cấu hình tài khoản người dùng và môi trường"
},
{
"153": "5.4.1. Cấu hình mật khẩu người dùng"
},
{
"154": "5.4.1.1. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"155": "5.4.1.2. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"156": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"157": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"158": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"159": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"160": "5.4.3. Cấu hình group mặc định của tài khoản root"
},
{
"161": "5.4.4. Cấu hình user umask mặc định"
},
{
"162": "5.4.5. Cấu hình shell timeout mặc định"
},
{
"163": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"164": "6. System Maintenance"
},
{
"165": "6.1. Quyền của file hệ thống"
},
{
"166": "6.1.1. Cấu hình phân quyền cho file /etc/passwd"
},
{
"167": "6.1.2. Cấu hình phân quyền cho file /etc/shadow"
},
{
"168": "6.1.3. Cấu hình phân quyền cho file /etc/group"
},
{
"169": "6.1.4. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"170": "6.1.5. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"171": "6.1.6. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"172": "6.1.7. Cấu hình phân quyền cho file /etc/group-"
},
{
"173": "6.1.8. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"174": "6.1.9. Đảm bảo không có file world-writable tồn tại"
},
{
"175": "6.1.10. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"176": "6.1.11. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"177": "6.2. Thiết lập cho người dùng và nhóm"
},
{
"178": "6.2.1. Cấu hình tài khoản trong /etc/passwd sử dụng shadowed passwords"
},
{
"179": "6.2.2. Đảm bảo trường mật khẩu không để trống"
},
{
"180": "6.2.3. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"181": "6.2.4. Đảm bảo shadow group rỗng"
},
{
"182": "6.2.5. Đảm bảo UID không bị lặp"
},
{
"183": "6.2.6. Đảm bảo GID không bị lặp"
},
{
"184": "6.2.7. Đảm bảo tên người dùng không bị lặp"
},
{
"185": "6.2.8. Đảm bảo tên group không bị lặp"
},
{
"186": "6.2.9. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"187": "6.2.10. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"188": "6.2.11. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"189": "6.2.12. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"190": "6.2.13. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"191": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"192": "6.2.15. Đảm bảo không người dùng nào có file .forward"
},
{
"193": "6.2.16. Đảm bảo không người dùng nào có file .rhosts"
},
{
"194": "6.2.17. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
}
]
}
@@ -0,0 +1,619 @@
{
"data": [
{
"6": "1.1.1. Cấu hình tham số 'Enforce password history'"
},
{
"7": "1.1.2. Cấu hình tham số 'Maximum password age'"
},
{
"8": "1.1.3. Cấu hình tham số 'Minimum password age'"
},
{
"9": "1.1.4. Cấu hình tham số 'Minimum password length'"
},
{
"10": "1.1.5. Cấu hình chính sách 'Password must meet complexity requirements'"
},
{
"11": "1.1.6. Cấu hình tham số 'Store passwords using reversible encryption'"
},
{
"13": "1.2.1. Cấu hình tham số 'Account lockout duration'"
},
{
"14": "1.2.2. Cấu hình tham số 'Account lockout threshold'"
},
{
"15": "1.2.3. Cấu hình tham số 'Reset account lockout counter after'"
},
{
"18": "2.1.1. Cấu hình chính sách 'Access Credential Manager as a trusted caller'"
},
{
"19": "2.1.2. Cấu hình chính sách 'Access this computer from the network' [Chỉ MS]"
},
{
"20": "2.1.2. Cấu hình chính sách 'Access this computer from the network' [Chỉ DC]"
},
{
"21": "2.1.3. Cấu hình chính sách 'Act as part of the operating system'"
},
{
"22": "2.1.4. Cấu hình chỉ định người dùng được thêm các máy trạm vào Domain [Chỉ DC]"
},
{
"23": "2.1.5. Cấu hình chính sách 'Adjust memory quotas for a process'"
},
{
"24": "2.1.6. Cấu hình chính sách 'Allow log on locally'"
},
{
"25": "2.1.7. Cấu hình chính sách 'Allow log on through Remote Desktop Services' [Chỉ DC]"
},
{
"26": "2.1.7. Cấu hình chính sách 'Allow log on through Remote Desktop Services' [Chỉ MS]"
},
{
"27": "2.1.8. Cấu hình sao lưu tệp và thư mục 'Back up files and directories'"
},
{
"28": "2.1.9. Cấu hình thay đổi thời gian hệ thống 'Change the system time'"
},
{
"29": "2.1.10. Cấu hình thay đổi thời gian hệ thống 'Change the time zone'"
},
{
"30": "2.1.11. Cấu hình chính sách 'Create a pagefile'"
},
{
"31": "2.1.12. Cấu hình chính sách 'Create a token object'"
},
{
"32": "2.1.13. Cấu hình chính sách 'Create global objects'"
},
{
"33": "2.1.14. Cấu hình chính sách 'Create permanent shared objects'"
},
{
"34": "2.1.15. Cấu hình chính sách 'Create symbolic links' [Chỉ DC]"
},
{
"35": "2.1.15. Cấu hình chính sách 'Create symbolic links' [Chỉ MS]"
},
{
"36": "2.1.16. Cấu hình chính sách 'Debug programs'"
},
{
"37": "2.1.17. Cấu hình chính sách 'Deny access to this computer from the network' [Chỉ DC]"
},
{
"38": "2.1.17. Cấu hình chính sách 'Deny access to this computer from the network' [Chỉ MS]"
},
{
"39": "2.1.18. Cấu hình chính sách 'Deny log on as a batch job'"
},
{
"40": "2.1.19. Cấu hình chính sách 'Deny log on as a service'"
},
{
"41": "2.1.20. Cấu hình chính sách 'Deny log on locally'"
},
{
"42": "2.1.21. Cấu hình chính sách 'Deny log on through Remote Desktop Services' [Chỉ DC]"
},
{
"43": "2.1.21. Cấu hình chính sách 'Deny log on through Remote Desktop Services' [Chỉ MS]"
},
{
"44": "2.1.22. Cấu hình chính sách 'Enable computer and user accounts to be trusted for delegation' [Chỉ DC]"
},
{
"45": "2.1.22. Cấu hình chính sách 'Enable computer and user accounts to be trusted for delegation' [Chỉ MS]"
},
{
"46": "2.1.23. Cấu hình chính sách 'Force shutdown from a remote system'"
},
{
"47": "2.1.24. Cấu hình chính sách 'Generate security audits'"
},
{
"48": "2.1.25. Cấu hình chính sách 'Impersonate a client after authentication' [Chỉ DC]"
},
{
"49": "2.1.25. Cấu hình chính sách 'Impersonate a client after authentication' [Chỉ MS]"
},
{
"50": "2.1.26. Cấu hình chính sách 'Increase scheduling priority'"
},
{
"51": "2.1.27. Cấu hình chính sách 'Load and unload device drivers'"
},
{
"52": "2.1.28. Cấu hình chính sách 'Lock pages in memory'"
},
{
"53": "2.1.29. Cấu hình chính sách 'Manage auditing and security log' [Chỉ DC]"
},
{
"54": "2.1.29. Cấu hình chính sách 'Manage auditing and security log' [Chỉ MS]"
},
{
"55": "2.1.30. Cấu hình chính sách 'Modify an object label'"
},
{
"56": "2.1.31. Cấu hình giá trị 'Modify firmware environment values'"
},
{
"57": "2.1.32. Cấu hình chính sách 'Perform volume maintenance tasks'"
},
{
"58": "2.1.33. Cấu hình chính sách 'Profile single process'"
},
{
"59": "2.1.34. Cấu hình chính sách 'Profile system performance'"
},
{
"60": "2.1.35. Cấu hình chính sách 'Replace a process level token'"
},
{
"61": "2.1.36. Cấu hình chính sách 'Restore files and directories'"
},
{
"62": "2.1.37. Cấu hình chính sách 'Shut down the system'"
},
{
"63": "2.1.38. Cấu hình chính sách 'Synchronize directory service data' [Chỉ DC]"
},
{
"64": "2.1.39. Cấu hình chính sách 'Take ownership of files or other objects'"
},
{
"66": "2.2.1.1. Cấu hình trạng thái tài khoản 'Administrator account status'"
},
{
"67": "2.2.1.2. Cấu hình chính sách tài khoản 'Block Microsoft accounts'"
},
{
"68": "2.2.1.3. Cấu hình trạng thái tài khoản 'Guest account status' [Chỉ MS]"
},
{
"69": "2.2.1.4. Cấu hình chính sách tài khoản 'Limit local account use of blank passwords to console logon only'"
},
{
"70": "2.2.1.5. Cấu hình thay đổi tên mặc định tài khoản quản trị 'Rename administrator account'"
},
{
"71": "2.2.1.6. Cấu hình thay đổi tên mặc định tài khoản Guests 'Rename guest account'"
},
{
"73": "2.2.2.1. Cấu hình chính sách 'Audit: Force audit policy subcategory settings to override audit policy category settings'"
},
{
"74": "2.2.2.2. Cấu hình chính sách 'Audit: Shut down system immediately if unable to log security audits'"
},
{
"76": "2.2.3.1. Cấu hình chính sách 'Devices: Allowed to format and eject removable media'"
},
{
"77": "2.2.3.2. Cấu hình chính sách 'Devices: Prevent users from installing printer drivers'"
},
{
"79": "2.2.4.1. Cấu hình chính sách 'Domain controller: Allow server operators to schedule tasks' is set to 'Disabled'"
},
{
"80": "2.2.4.2. Cấu hình chính sách 'Domain controller: Refuse machine account password changes'"
},
{
"82": "2.2.5.1. Cấu hình chính sách 'Domain member: Digitally encrypt or sign secure channel data (always)'"
},
{
"83": "2.2.5.2. Cấu hình chính sách 'Domain member: Digitally encrypt secure channel data (when possible)'"
},
{
"84": "2.2.5.3. Cấu hình chính sách 'Domain member: Digitally sign secure channel data (when possible)'"
},
{
"85": "2.2.5.4. Cấu hình chính sách 'Domain member: Disable machine account password changes'"
},
{
"86": "2.2.5.5. Cấu hình chính sách 'Domain member: Maximum machine account password age'"
},
{
"87": "2.2.5.6. Cấu hình chính sách 'Domain member: Require strong (Windows 2000 or later) session key'"
},
{
"89": "2.2.6.1. Thiết lập 'Interactive logon: Do not display last user name'"
},
{
"90": "2.2.6.2. Thiết lập 'CTRL+ALT+DEL'"
},
{
"91": "2.2.6.3. Thiết lập 'Interactive logon: Machine inactivity limit'"
},
{
"92": "2.2.6.4. Cấu hình 'Interactive logon: Message text for users attempting to log on'"
},
{
"93": "2.2.6.5. Thiết lập 'Interactive logon: Message title for users attempting to log on'"
},
{
"94": "2.2.6.6. Thiết lập 'Interactive logon: Prompt user to change password before expiration'"
},
{
"95": "2.2.6.7. Thiết lập 'Interactive logon: Require Domain Controller Authentication to unlock workstation' [Chỉ MS]"
},
{
"96": "2.2.6.8. Thiết lập 'Interactive logon: Smart card removal behavior' is set to 'Lock Workstation'"
},
{
"98": "2.2.7.1. Thiết lập 'Microsoft network client: Digitally sign communications (if server agrees)'"
},
{
"99": "2.2.7.2. Thiết lập 'Microsoft network client: Send unencrypted password to third-party SMB servers'"
},
{
"100": "2.2.7.3. Thiết lập 'Microsoft network client: Digitally sign communications (if server always)'"
},
{
"102": "2.2.8.1. Thiết lập 'Microsoft network server: Amount of idle time required before suspending session'"
},
{
"103": "2.2.8.2. Thiết lập 'Microsoft network server: Disconnect clients when logon hours expire'"
},
{
"104": "2.2.8.3. Thiết lập 'Microsoft network server: Digitally sign communications (always)'"
},
{
"105": "2.2.8.4. Thiết lập 'Microsoft network server: Digitally sign communications (if client agrees)'"
},
{
"106": "2.2.8.5. Thiết lập 'Microsoft network server: Server SPN target name validation level' [Chỉ MS]"
},
{
"108": "2.2.9.1. Thiết lập 'Network access: Allow anonymous SID/Name translation'"
},
{
"109": "2.2.9.2. Thiết lập 'Network access: Do not allow anonymous enumeration of SAM accounts' [Chỉ MS]"
},
{
"110": "2.2.9.3. Thiết lập 'Network access: Do not allow anonymous enumeration of SAM accounts and shares' [Chỉ MS]"
},
{
"111": "2.2.9.4. Thiết lập 'Network access: Let Everyone permissions apply to anonymous users'"
},
{
"112": "2.2.9.5. Cấu hình 'Network access: Named Pipes that can be accessed anonymously' [Chỉ MS]"
},
{
"113": "2.2.9.5. Cấu hình 'Network access: Named Pipes that can be accessed anonymously' [Chỉ DC]"
},
{
"114": "2.2.9.6. Cấu hình 'Network access: Remotely accessible registry paths'"
},
{
"115": "2.2.9.7. Cấu hình 'Network access: Remotely accessible registry paths and sub-paths'"
},
{
"116": "2.2.9.8. Cấu hình 'Network access: Restrict anonymous access to Named Pipes and Shares'"
},
{
"117": "2.2.9.9. Cấu hình 'Network access: Shares that can be accessed anonymously'"
},
{
"118": "2.2.9.10. Cấu hình 'Network access: Sharing and security model for local accounts'"
},
{
"120": "2.2.10.1. Thiết lập 'Network security: Allow LocalSystem NULL session fallback'"
},
{
"121": "2.2.10.2. Thiết lập 'Network Security: Allow PKU2U authentication requests to this computer to use online identities'"
},
{
"122": "2.2.10.3. Thiết lập 'Network security: Configure encryption types allowed for Kerberos'"
},
{
"123": "2.2.10.4. Thiết lập 'Network security: Do not store LAN Manager hash value on next password change'"
},
{
"124": "2.2.10.5. Thiết lập 'Network security: Force logoff when logon hours expire'"
},
{
"125": "2.2.10.6. Thiết lập 'Network security: Allow Local System to use computer identity for NTLM'"
},
{
"126": "2.2.10.7. Thiết lập 'Network security: LAN Manager authentication level'"
},
{
"127": "2.2.10.8. Thiết lập 'Network security: LDAP client signing requirements'"
},
{
"128": "2.2.10.9. Thiết lập 'Network security: Minimum session security for NTLM SSP based (including secure RPC) clients'"
},
{
"129": "2.2.10.10. Thiết lập 'Network security: Minimum session security for NTLM SSP based (including secure RPC) servers'"
},
{
"131": "2.2.11.1. Thiết lập cơ chế 'Shutdown: Allow system to be shut down without having to log on'"
},
{
"133": "2.2.12.1. Cấu hình chính sách 'System objects: Require case insensitivity for non-Windows subsystems'"
},
{
"134": "2.2.12.2. Cấu hình chính sách 'System objects: Strengthen default permissions of internal system objects (e.g. Symbolic Links)'"
},
{
"136": "2.2.13.1. Thiết lập 'User Account Control: Admin Approval Mode for the Built-in Administrator account'"
},
{
"137": "2.2.13.2. Thiết lập 'User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode'"
},
{
"138": "2.2.13.3. Thiết lập 'User Account Control: Detect application installations and prompt for elevation'"
},
{
"139": "2.2.13.4. Thiết lập 'User Account Control: Only elevate UIAccess applications that are installed in secure locations'"
},
{
"140": "2.2.13.5. Thiết lập 'User Account Control: Run all administrators in Admin Approval Mode'"
},
{
"141": "2.2.13.6. Thiết lập 'User Account Control: Switch to the secure desktop when prompting for elevation'"
},
{
"142": "2.2.13.7. Thiết lập 'User Account Control: Virtualize file and registry write failures to per-user locations'"
},
{
"143": "2.2.13.8. Thiết lập 'User Account Control: Behavior of the elevation prompt for standard users' is set to 'Automatically deny elevation requests'"
},
{
"146": "3.1.1. Thiết lập trạng thái 'Windows Firewall: Domain: Firewall state'"
},
{
"147": "3.1.2. Thiết lập trạng thái 'Windows Firewall: Domain: Inbound connections'"
},
{
"148": "3.1.3. Thiết lập trạng thái 'Windows Firewall: Domain: Outbound connections'"
},
{
"149": "3.1.4. Cấu hình vị trí lưu trữ nhật ký 'Windows Firewall: Domain: Logging: Name'"
},
{
"150": "3.1.5. Cấu hình kích thước giới hạn 'Windows Firewall: Domain: Logging: Size limit (KB)'"
},
{
"151": "3.1.6. Thiết lập chính sách 'Windows Firewall: Domain: Logging: Log dropped packets'"
},
{
"152": "3.1.7. Thiết lập chính sách 'Windows Firewall: Domain: Logging: Log successful connections'"
},
{
"153": "3.1.8. Thiết lập chính sách 'Windows Firewall: Domain: Settings: Display a notification'"
},
{
"155": "3.2.1. Thiết lập trạng thái 'Windows Firewall: Private: Firewall state'"
},
{
"156": "3.2.2. Thiết lập trạng thái 'Windows Firewall: Private: Inbound connections'"
},
{
"157": "3.2.3. Thiết lập trạng thái 'Windows Firewall: Private: Outbound connections'"
},
{
"158": "3.2.4. Cấu hình vị trí lưu trữ nhật ký 'Windows Firewall: Private: Logging: Name'"
},
{
"159": "3.2.5. Cấu hình kích thước giới hạn 'Windows Firewall: Private: Logging: Size limit (KB)'"
},
{
"160": "3.2.6. Thiết lập chính sách 'Windows Firewall: Private: Logging: Log dropped packets'"
},
{
"161": "3.2.7. Thiết lập chính sách 'Windows Firewall: Private: Logging: Log successful connections'"
},
{
"162": "3.2.8. Thiết lập trạng thái 'Windows Firewall: Private: Settings: Display a notification'"
},
{
"164": "3.3.1. Thiết lập trạng thái 'Windows Firewall: Public: Firewall state'"
},
{
"165": "3.3.2. Thiết lập trạng thái 'Windows Firewall: Public: Inbound connections'"
},
{
"166": "3.3.3. Thiết lập trạng thái 'Windows Firewall: Public: Outbound connections'"
},
{
"167": "3.3.4. Cấu hình vị trí lưu trữ nhật ký 'Windows Firewall: Public: Logging: Name'"
},
{
"168": "3.3.5. Cấu hình kích thước giới hạn 'Windows Firewall: Public: Logging: Size limit (KB)'"
},
{
"169": "3.3.6. Thiết lập chính sách 'Windows Firewall: Public: Logging: Log dropped packets'"
},
{
"170": "3.3.7. Thiết lập chính sách 'Windows Firewall: Public: Logging: Log successful connections'"
},
{
"171": "3.3.8. Thiết lập trạng thái 'Windows Firewall: Public: Settings: Display a notification'"
},
{
"172": "3.3.9. Thiết lập trạng thái 'Windows Firewall: Public: Settings: Apply local connection security rules'"
},
{
"175": "4.1.1. Cấu hình chính sách 'Audit Credential Validation'"
},
{
"176": "4.1.2. Cấu hình chính sách 'Audit Kerberos Authentication Service' [Chỉ DC]"
},
{
"177": "4.1.3. Cấu hình chính sách 'Audit Kerberos Service Ticket Operations' [Chỉ DC]"
},
{
"179": "4.2.1. Cấu hình chính sách 'Audit Application Group Management'"
},
{
"180": "4.2.2. Cấu hình chính sách 'Audit Computer Account Management' [Chỉ DC]"
},
{
"181": "4.2.3. Cấu hình chính sách 'Audit Distribution Group Management' [Chỉ DC]"
},
{
"182": "4.2.4. Cấu hình chính sách 'Audit Other Account Management Events' [Chỉ DC]"
},
{
"183": "4.2.5. Cấu hình chính sách 'Audit Security Group Management'"
},
{
"184": "4.2.6. Cấu hình chính sách 'Audit User Account Management'"
},
{
"186": "4.3.1. Cấu hình chính sách 'Audit Process Creation'"
},
{
"187": "4.3.2. Cấu hình chính sách 'Audit PNP Activity'"
},
{
"189": "4.4.1. Cấu hình chính sách 'Audit Directory Service Access' [Chỉ DC]"
},
{
"190": "4.4.2. Cấu hình chính sách 'Audit Directory Service Changes' [Chỉ DC]"
},
{
"192": "4.5.1. Cấu hình chính sách 'Audit Account Lockout'"
},
{
"193": "4.5.2. Cấu hình chính sách 'Audit Logoff'"
},
{
"194": "4.5.3. Cấu hình chính sách 'Audit Logon'"
},
{
"195": "4.5.4. Cấu hình chính sách 'Audit Other Logon/Logoff Events'"
},
{
"196": "4.5.5. Cấu hình chính sách 'Audit Special Logon'"
},
{
"197": "4.5.6. Cấu hình chính sách 'Audit Group Membership'"
},
{
"199": "4.6.1. Cấu hình chính sách 'Audit Detailed File Share'"
},
{
"200": "4.6.2. Cấu hình chính sách 'Audit File Share'"
},
{
"201": "4.6.3. Cấu hình chính sách 'Audit Other Object Access Events'"
},
{
"202": "4.6.4. Cấu hình chính sách 'Audit Removable Storage'"
},
{
"204": "4.7.1. Cấu hình chính sách 'Audit Audit Policy Change'"
},
{
"205": "4.7.2. Cấu hình chính sách 'Audit Authentication Policy Change'"
},
{
"206": "4.7.3. Cấu hình chính sách 'Audit Authorization Policy Change'"
},
{
"207": "4.7.4. Cấu hình chính sách 'Audit MPSSVC Rule-Level Policy Change'"
},
{
"208": "4.7.5. Cấu hình chính sách 'Audit Other Policy Change Events'"
},
{
"210": "4.8.1. Cấu hình chính sách 'Audit Sensitive Privilege Use'"
},
{
"212": "4.9.1. Cấu hình chính sách 'Audit IPsec Driver'"
},
{
"213": "4.9.2. Cấu hình chính sách 'Audit Other System Events'"
},
{
"214": "4.9.3. Cấu hình chính sách 'Audit Security State Change'"
},
{
"215": "4.9.4. Cấu hình chính sách 'Audit Security System Extension'"
},
{
"216": "4.9.5. Cấu hình chính sách 'Audit System Integrity'"
},
{
"219": "5.1.1. Cấu hình chính sách 'Turn off app notifications on the lock screen'"
},
{
"220": "5.1.2. Cấu hình chính sách 'Turn off picture password sign-in'"
},
{
"221": "5.1.3. Cấu hình chính sách 'Turn on convenience PIN sign-in'"
},
{
"222": "5.1.4. Cấu hình chính sách 'Block user from showing account details on sign-in'"
},
{
"223": "5.1.5. Cấu hình chính sách 'Do not display network selection UI'"
},
{
"224": "5.1.6. Cấu hình chính sách 'Do not enumerate connected users on domain joined computers'"
},
{
"225": "5.1.7. Cấu hình chính sách 'Enumerate local users on domain-joined computers' [Chỉ MS]"
},
{
"227": "5.2.1. Cấu hình chính sách 'Require a password when a computer wakes (on battery)'"
},
{
"228": "5.2.2. Cấu hình chính sách 'Require a password when a computer wakes (plugged in)'"
},
{
"230": "5.3.1. Cấu hình chính sách 'Disallow Autoplay for non-volume devices'"
},
{
"231": "5.3.2. Cấu hình chính sách 'Set the default behavior for AutoRun'"
},
{
"232": "5.3.3. Cấu hình chính sách 'Turn off Autoplay'"
},
{
"235": "5.4.1.1. Thiết lập chính sách 'Application: Control Event Log behavior when the log file reaches its maximum size'"
},
{
"236": "5.4.1.2. Thiết lập chính sách 'Application: Specify the maximum log file size (KB)'"
},
{
"238": "5.4.2.1. Thiết lập chính sách 'Security: Control Event Log behavior when the log file reaches its maximum size'"
},
{
"239": "5.4.2.2. Thiết lập chính sách 'Security: Specify the maximum log file size (KB)'"
},
{
"241": "5.4.3.1. Thiết lập chính sách 'Setup: Control Event Log behavior when the log file reaches its maximum size'"
},
{
"242": "5.4.3.2. Thiết lập chính sách 'Setup: Specify the maximum log file size (KB)'"
},
{
"244": "5.4.4.1. Thiết lập chính sách 'System: Control Event Log behavior when the log file reaches its maximum size'"
},
{
"245": "5.4.4.2. Thiết lập chính sách 'System: Specify the maximum log file size (KB)'"
},
{
"247": "6.1. Cài đặt và cập nhật các bản vá bảo mật"
},
{
"249": "7.1. Kiểm tra trạng thái phần mềm"
},
{
"250": "7.2. Kiểm tra tính năng tự động cập nhật của phần mềm"
},
{
"251": "7.3. Thực hiện lịch quét định kỳ máy chủ"
}
]
}
@@ -0,0 +1,195 @@
Unnamed: 0,Unnamed: 1,KẾT QUẢ,Unnamed: 3,Unnamed: 4,Unnamed: 5
,Hạng mục đánh giá ,Đáp ứng,,,Ghi chú
,,,Không,Bắt buộc,
1,Thiết lập ban đầu,,,,
1.1,Cấu hình filesystem,,,,
1.1.1,Cấu hình vô hiệu hoá các filesystem không sử dụng,,,,
1.1.1.1,Cấu hình vô hiệu hoá cramfs filesystem,,,,
1.1.1.2,Cấu hình vô hiệu hoá freevxfs filesystem,,,,
1.1.1.3,Cấu hình vô hiệu hoá hfs filesystem,,,,
1.1.1.4,Cấu hình vô hiệu hoá hfsplus filesystem,,,,
1.1.1.5,Cấu hình vô hiệu hoá jffs2 filesystem,,,,
1.1.1.6,Cấu hình vô hiệu hoá squashfs filesystem,,,,
1.1.1.7,Cấu hình vô hiệu hoá udf filesystem,,,,
1.1.1.8,Cấu hình vô hiệu hoá usb storage,,,,
1.1.2,Cấu hình phân vùng /tmp,,,,
1.1.2.1,Cấu hình tuỳ chọn nodev cho phân vùng /tmp,,,,
1.1.2.2,Cấu hình tuỳ chọn nosuid cho phân vùng /tmp,,,,
1.1.2.3,Cấu hình tuỳ chọn noexec cho phân vùng /tmp,,,,
1.1.3,Cấu hình phân vùng /var/tmp,,,,
1.1.3.1,Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp,,,,
1.1.3.2,Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp,,,,
1.1.3.3,Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp,,,,
1.1.4,Cấu hình phân vùng /home,,,,
1.1.4.1,Cấu hình tuỳ chọn nodev cho phân vùng /home,,,,
1.1.4.2,Cấu hình tuỳ chọn nosuid cho phân vùng /home,,,,
1.1.5,Cấu hình phân vùng /dev/shm,,,,
1.1.5.1,Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm,,,,
1.1.5.2,Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm,,,,
1.1.5.3,Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm,,,,
1.2,Kiểm tra tính toàn vẹn của filesystem,,,,
1.2.1 ,Kiểm tra cài đặt AIDE,,,,
1.2.2,Cấu hình kiểm tra tính toàn vẹn của filesystem,,,,
1.3,Cấu hình khởi động an toàn,,,,
1.3.1,Phân quyền đối với file cấu hình bootloader,,,,
1.3.2,Cấu hình mật khẩu cho bootloader,,,,
1.3.3,Cấu hình xác thực khi truy cập single user mode,,,,
1.4,Additional Process Hardening,,,,
1.4.1 ,Cấu hình kích hoạt ASLR (address space layout randomization),,,,
1.4.2,Cấu hình vô hiệu hoá prelink,,,,
1.4.3,Cấu hình vô hiệu hoá core dump,,,,
1.5,Kiểm soát nội dung cảnh báo,,,,
1.5.1,Kiểm soát nội dung motd (Message Of The Day),,,,
1.5.2,Kiểm soát nội dung thông báo khi đăng nhập,,,,
1.5.3,Kiểm soát nội dung thông báo khi đăng nhập từ xa,,,,
1.5.4,Cấu hình phân quyền đối với file /etc/motd,,,,
1.5.5,Cấu hình phân quyền đối với file /etc/issue,,,,
1.5.6,Cấu hình phân quyền đối với file /etc/issue.net,,,,
1.5.7,Kiểm soát nội dung thông báo khi truy cập GNOME,,,,
2,Service,,,,
2.1,Cấu hình Time Synchronization,,,,
2.1.1,Cấu hình sử dụng chrony,,,x,
2.1.2,Cấu hình sử dụng ntp,,,x,
2.2,Các Service với mục đích riêng biệt,,,,
2.2.1,Cấu hình vô hiệu hoá xinetd services,,,,
2.2.2,Cấu hình vô hiệu hoá autofs services,,,,
2.2.3,Cấu hình vô hiệu hoá X window server services,,,,
2.2.4,Cấu hình vô hiệu hoá avahi daemon services,,,,
2.2.5,Cấu hình vô hiệu hoá cups services,,,,
2.2.6,Cấu hình vô hiệu hoá dhcp server services,,,,
2.2.7,Cấu hình vô hiệu hoá ldap server services,,,,
2.2.8,Cấu hình vô hiệu hoá dns server services,,,,
2.2.9,Cấu hình vô hiệu hoá dnsmasq services,,,,
2.2.10,Cấu hình vô hiệu hoá ftp server services,,,,
2.2.11,Cấu hình vô hiệu hoá tftp server services,,,,
2.2.12,Cấu hình vô hiệu hoá web server services,,,,
2.2.13,Cấu hình vô hiệu hoá imap and pop3 server services,,,,
2.2.14,Cấu hình vô hiệu hoá samba file server services,,,,
2.2.15,Cấu hình vô hiệu hoá web proxy server services,,,,
2.2.16,Cấu hình vô hiệu hoá snmp services,,,,
2.2.17,Cấu hình vô hiệu hoá nis server services,,,,
2.2.18,Cấu hình mail transfer agents sang chế độ local-only,,,,
2.2.19,Cấu hình vô hiệu hoá network file system services,,,,
2.2.20,Cấu hình vô hiệu hoá rsync services,,,,
2.3,Service Clients,,,,
2.3.1,Cấu hình vô hiệu hoá nis client,,,,
2.3.2,Cấu hình vô hiệu hoá rsh client,,,,
2.3.3,Cấu hình vô hiệu hoá talk client,,,,
2.3.4,Cấu hình vô hiệu hoá telnet client,,,,
2.3.5,Cấu hình vô hiệu hoá ldap client,,,,
2.3.6,Cấu hình vô hiệu hoá rpc,,,,
2.3.7,Cấu hình vô hiệu hoá ftp client,,,,
3,Cấu hình mạng,,,,
3.1,Tham số cấu hình mạng (Host Only),,,,
3.1.1 ,Cấu hình vô hiệu hoá IP forwarding,,,,
3.1.2,Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect),,,,
3.2,Tham số cấu hình mạng (Host và Router),,,,
3.2.1 ,Cấu hình từ chối các gói tin với nguồn được định tuyến trước,,,,
3.2.2,Cấu hình từ chối các ICMP redirect message,,,,
3.2.3,Cấu hình từ chối các secure ICMP redirect message,,,,
3.2.4,Cấu hình từ chối các gói tin ICMP request broadcast,,,,
3.2.5,Cấu hình bỏ qua phản hồi ICMP không hợp lệ,,,,
3.2.6,Cấu hình Reverse Path Filtering,,,,
3.2.7,Cấu hình TCP SYN Cookies,,,,
3.4,Cấu hình Firewall,,,,
3.4.1,Cấu hình Uncomplicated Firewall,,,,
3.4.1.1,Cấu hình kích hoạt ufw,,,x,
3.4.1.2,"Cấu hình vô hiệu hoá iptables-persistent, nftables khi sử dụng ufw",,,x,
3.4.1.3,Cấu hình ufw loopback traffic,,,x,
3.4.1.4,Cấu hình ufw rule cho tất cả các port và protocol đang mở,,,x,
3.4.1.5,Cấu hình chính sách từ chối mặc định cho ufw,,,x,
3.4.2,Iptables,,,,
3.4.2.1,Cấu hình kích hoạt Iptables,,,x,
3.4.2.2,"Cấu hình vô hiệu hoá ufw, nftables khi sử dụng iptables",,,x,
3.4.2.3,Cấu hình iptables loopback traffic,,,x,
3.4.2.4,Cấu hình iptables rule cho tất cả các port và protocol đang mở,,,x,
3.4.2.5,Cấu hình chính sách từ chối mặc định cho iptables,,,x,
4,Logging và Auditing,,,,
4.1,Cấu hình logging,,,,
4.1.1,Cấu hình rsyslog,,,,
4.1.1.1 ,Cấu hình kích hoạt rsyslog service,,,,
4.1.1.2,Phân quyền đối với file log sinh ra từ rsyslog,,,,
4.1.1.3,Cấu hình lưu trữ log sinh ra từ rsyslog tập trung,,,x,
4.1.1.4,Phân quyền đối với tất cả các file log,,,,
5,"Cấu hình truy cập, xác thực và ủy quyền",,,,
5.1,Cấu hình cron,,,,
5.1.1 ,Cấu hình kích hoạt cron daemon,,,,
5.1.2,Cấu hình phân quyền cho file /etc/crontab,,,,
5.1.3,Cấu hình phân quyền cho file /etc/cron.hourly,,,,
5.1.4,Cấu hình phân quyền cho file /etc/cron.daily,,,,
5.1.5,Cấu hình phân quyền cho file /etc/cron.weekly,,,,
5.1.6,Cấu hình phân quyền cho của file /etc/cron.monthly,,,,
5.1.7,Cấu hình phân quyền cho file /etc/cron.d,,,,
5.1.8,Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền,,,,
5.2,Cấu hình máy chủ SSH,,,,
5.2.1 ,Cấu hình phân quyền cho file /etc/ssh/sshd_config,,,,
5.2.2,Cấu hình phân quyền cho các file SSH private host key,,,,
5.2.3,Cấu hình phân quyền cho các file SSH public host key,,,,
5.2.4,Cấu hình giới hạn truy cập cho máy chủ SSH,,,,
5.2.5,Cấu hình LogLevel cho máy chủ SSH,,,,
5.2.6,Cấu hình sử dụng SSH PAM,,,,
5.2.7,Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH,,,,
5.2.8,Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH,,,,
5.2.9,Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH,,,,
5.2.10,Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH,,,,
5.2.11,Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH,,,,
5.2.12,Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH,,,,
5.2.13,Cấu hình sử dụng các thuật toán mã hoá được cho phép,,,,
5.2.14,Cấu hình các thuật toán MAC được cho phép,,,,
5.2.15,Cấu hình thuật toán trao đổi khoá được cho phép,,,,
5.2.16,Cấu hình vô hiệu hoá SSH AllowTcpForwarding,,,,
5.2.17,Cấu hình cảnh báo SSH,,,,
5.2.18,Cấu hình SSH MaxAuthTries,,,,
5.2.19,Cấu hình SSH MaxStartups,,,,
5.2.20,Cấu hình SSH MaxSessions,,,,
5.2.21,Cấu hình SSH LoginGraceTime,,,,
5.2.22,Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH,,,,
5.3,Cấu hình PAM,,,,
5.3.1 ,Cấu hình điều kiện tạo mật khẩu,,,x,
5.3.2 ,Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại,,,x,
5.3.3 ,Giới hạn việc sử dụng lại mật khẩu,,,,
5.3.4 ,Cấu hình thuật toán hash mật khẩu mạnh,,,,
5.4,Cấu hình tài khoản người dùng và môi trường,,,,
5.4.1 ,Cấu hình mật khẩu người dùng,,,,
5.4.1.1 ,Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu,,,x,
5.4.1.2 ,Cấu hình thời gian hết hạn sử dụng mật khẩu,,,x,
5.4.1.3 ,Cấu hình thời gian cảnh báo mật khẩu hết hạn,,,,
5.4.1.4 ,Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn,,,,
5.4.1.5,Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ,,,,
5.4.2 ,Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống,,,,
5.4.3,Cấu hình group mặc định của tài khoản root,,,,
5.4.4,Cấu hình user umask mặc định,,,,
5.4.5,Cấu hình shell timeout mặc định,,,,
5.4.6,Cấu hình hạn chế truy cập cho câu lệnh su,,,,
6,System Maintenance,,,,
6.1,Quyền của file hệ thống,,,,
6.1.1,Cấu hình phân quyền cho file /etc/passwd,,,,
6.1.2,Cấu hình phân quyền cho file /etc/shadow,,,,
6.1.3,Cấu hình phân quyền cho file /etc/group,,,,
6.1.4,Cấu hình phân quyền cho file /etc/gshadow,,,,
6.1.5,Cấu hình phân quyền cho file /etc/passwd-,,,,
6.1.6,Cấu hình phân quyền cho file /etc/shadow-,,,,
6.1.7,Cấu hình phân quyền cho file /etc/group-,,,,
6.1.8,Cấu hình phân quyền cho file /etc/gshadow-,,,,
6.1.9,Đảm bảo không có file world-writable tồn tại,,,,
6.1.10,Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại,,,,
6.1.11,Đảm bảo các file hoặc thư mục không có nhóm không tồn tại,,,,
6.2,Thiết lập cho người dùng và nhóm,,,,
6.2.1 ,Cấu hình tài khoản trong /etc/passwd sử dụng shadowed passwords,,,,
6.2.2,Đảm bảo trường mật khẩu không để trống,,,,
6.2.3,Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group,,,,
6.2.4,Đảm bảo shadow group rỗng,,,,
6.2.5,Đảm bảo UID không bị lặp,,,,
6.2.6,Đảm bảo GID không bị lặp,,,,
6.2.7,Đảm bảo tên người dùng không bị lặp,,,,
6.2.8,Đảm bảo tên group không bị lặp,,,,
6.2.9,Đảm bảo tính toàn vẹn cho biến môi trường PATH của root,,,,
6.2.10,Đảm bảo root là tài khoản duy nhất có UID là 0,,,,
6.2.11,Đảm bảo mọi người dùng đều tồn tại thư mục home,,,,
6.2.12,Đảm bảo người dùng sở hữu thư mục home của chính họ,,,,
6.2.13,Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao,,,,
6.2.14,Đảm bảo không người dùng nào có file .netrc,,,,
6.2.15,Đảm bảo không người dùng nào có file .forward,,,,
6.2.16,Đảm bảo không người dùng nào có file .rhosts,,,,
6.2.17,Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other,,,,
,0,0,0,17,
1 Unnamed: 0 Unnamed: 1 KẾT QUẢ Unnamed: 3 Unnamed: 4 Unnamed: 5
2 Hạng mục đánh giá Đáp ứng Ghi chú
3 Không Bắt buộc
4 1 Thiết lập ban đầu
5 1.1 Cấu hình filesystem
6 1.1.1 Cấu hình vô hiệu hoá các filesystem không sử dụng
7 1.1.1.1 Cấu hình vô hiệu hoá cramfs filesystem
8 1.1.1.2 Cấu hình vô hiệu hoá freevxfs filesystem
9 1.1.1.3 Cấu hình vô hiệu hoá hfs filesystem
10 1.1.1.4 Cấu hình vô hiệu hoá hfsplus filesystem
11 1.1.1.5 Cấu hình vô hiệu hoá jffs2 filesystem
12 1.1.1.6 Cấu hình vô hiệu hoá squashfs filesystem
13 1.1.1.7 Cấu hình vô hiệu hoá udf filesystem
14 1.1.1.8 Cấu hình vô hiệu hoá usb storage
15 1.1.2 Cấu hình phân vùng /tmp
16 1.1.2.1 Cấu hình tuỳ chọn nodev cho phân vùng /tmp
17 1.1.2.2 Cấu hình tuỳ chọn nosuid cho phân vùng /tmp
18 1.1.2.3 Cấu hình tuỳ chọn noexec cho phân vùng /tmp
19 1.1.3 Cấu hình phân vùng /var/tmp
20 1.1.3.1 Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp
21 1.1.3.2 Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp
22 1.1.3.3 Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp
23 1.1.4 Cấu hình phân vùng /home
24 1.1.4.1 Cấu hình tuỳ chọn nodev cho phân vùng /home
25 1.1.4.2 Cấu hình tuỳ chọn nosuid cho phân vùng /home
26 1.1.5 Cấu hình phân vùng /dev/shm
27 1.1.5.1 Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm
28 1.1.5.2 Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm
29 1.1.5.3 Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm
30 1.2 Kiểm tra tính toàn vẹn của filesystem
31 1.2.1 Kiểm tra cài đặt AIDE
32 1.2.2 Cấu hình kiểm tra tính toàn vẹn của filesystem
33 1.3 Cấu hình khởi động an toàn
34 1.3.1 Phân quyền đối với file cấu hình bootloader
35 1.3.2 Cấu hình mật khẩu cho bootloader
36 1.3.3 Cấu hình xác thực khi truy cập single user mode
37 1.4 Additional Process Hardening
38 1.4.1 Cấu hình kích hoạt ASLR (address space layout randomization)
39 1.4.2 Cấu hình vô hiệu hoá prelink
40 1.4.3 Cấu hình vô hiệu hoá core dump
41 1.5 Kiểm soát nội dung cảnh báo
42 1.5.1 Kiểm soát nội dung motd (Message Of The Day)
43 1.5.2 Kiểm soát nội dung thông báo khi đăng nhập
44 1.5.3 Kiểm soát nội dung thông báo khi đăng nhập từ xa
45 1.5.4 Cấu hình phân quyền đối với file /etc/motd
46 1.5.5 Cấu hình phân quyền đối với file /etc/issue
47 1.5.6 Cấu hình phân quyền đối với file /etc/issue.net
48 1.5.7 Kiểm soát nội dung thông báo khi truy cập GNOME
49 2 Service
50 2.1 Cấu hình Time Synchronization
51 2.1.1 Cấu hình sử dụng chrony x
52 2.1.2 Cấu hình sử dụng ntp x
53 2.2 Các Service với mục đích riêng biệt
54 2.2.1 Cấu hình vô hiệu hoá xinetd services
55 2.2.2 Cấu hình vô hiệu hoá autofs services
56 2.2.3 Cấu hình vô hiệu hoá X window server services
57 2.2.4 Cấu hình vô hiệu hoá avahi daemon services
58 2.2.5 Cấu hình vô hiệu hoá cups services
59 2.2.6 Cấu hình vô hiệu hoá dhcp server services
60 2.2.7 Cấu hình vô hiệu hoá ldap server services
61 2.2.8 Cấu hình vô hiệu hoá dns server services
62 2.2.9 Cấu hình vô hiệu hoá dnsmasq services
63 2.2.10 Cấu hình vô hiệu hoá ftp server services
64 2.2.11 Cấu hình vô hiệu hoá tftp server services
65 2.2.12 Cấu hình vô hiệu hoá web server services
66 2.2.13 Cấu hình vô hiệu hoá imap and pop3 server services
67 2.2.14 Cấu hình vô hiệu hoá samba file server services
68 2.2.15 Cấu hình vô hiệu hoá web proxy server services
69 2.2.16 Cấu hình vô hiệu hoá snmp services
70 2.2.17 Cấu hình vô hiệu hoá nis server services
71 2.2.18 Cấu hình mail transfer agents sang chế độ local-only
72 2.2.19 Cấu hình vô hiệu hoá network file system services
73 2.2.20 Cấu hình vô hiệu hoá rsync services
74 2.3 Service Clients
75 2.3.1 Cấu hình vô hiệu hoá nis client
76 2.3.2 Cấu hình vô hiệu hoá rsh client
77 2.3.3 Cấu hình vô hiệu hoá talk client
78 2.3.4 Cấu hình vô hiệu hoá telnet client
79 2.3.5 Cấu hình vô hiệu hoá ldap client
80 2.3.6 Cấu hình vô hiệu hoá rpc
81 2.3.7 Cấu hình vô hiệu hoá ftp client
82 3 Cấu hình mạng
83 3.1 Tham số cấu hình mạng (Host Only)
84 3.1.1 Cấu hình vô hiệu hoá IP forwarding
85 3.1.2 Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)
86 3.2 Tham số cấu hình mạng (Host và Router)
87 3.2.1 Cấu hình từ chối các gói tin với nguồn được định tuyến trước
88 3.2.2 Cấu hình từ chối các ICMP redirect message
89 3.2.3 Cấu hình từ chối các secure ICMP redirect message
90 3.2.4 Cấu hình từ chối các gói tin ICMP request broadcast
91 3.2.5 Cấu hình bỏ qua phản hồi ICMP không hợp lệ
92 3.2.6 Cấu hình Reverse Path Filtering
93 3.2.7 Cấu hình TCP SYN Cookies
94 3.4 Cấu hình Firewall
95 3.4.1 Cấu hình Uncomplicated Firewall
96 3.4.1.1 Cấu hình kích hoạt ufw x
97 3.4.1.2 Cấu hình vô hiệu hoá iptables-persistent, nftables khi sử dụng ufw x
98 3.4.1.3 Cấu hình ufw loopback traffic x
99 3.4.1.4 Cấu hình ufw rule cho tất cả các port và protocol đang mở x
100 3.4.1.5 Cấu hình chính sách từ chối mặc định cho ufw x
101 3.4.2 Iptables
102 3.4.2.1 Cấu hình kích hoạt Iptables x
103 3.4.2.2 Cấu hình vô hiệu hoá ufw, nftables khi sử dụng iptables x
104 3.4.2.3 Cấu hình iptables loopback traffic x
105 3.4.2.4 Cấu hình iptables rule cho tất cả các port và protocol đang mở x
106 3.4.2.5 Cấu hình chính sách từ chối mặc định cho iptables x
107 4 Logging và Auditing
108 4.1 Cấu hình logging
109 4.1.1 Cấu hình rsyslog
110 4.1.1.1 Cấu hình kích hoạt rsyslog service
111 4.1.1.2 Phân quyền đối với file log sinh ra từ rsyslog
112 4.1.1.3 Cấu hình lưu trữ log sinh ra từ rsyslog tập trung x
113 4.1.1.4 Phân quyền đối với tất cả các file log
114 5 Cấu hình truy cập, xác thực và ủy quyền
115 5.1 Cấu hình cron
116 5.1.1 Cấu hình kích hoạt cron daemon
117 5.1.2 Cấu hình phân quyền cho file /etc/crontab
118 5.1.3 Cấu hình phân quyền cho file /etc/cron.hourly
119 5.1.4 Cấu hình phân quyền cho file /etc/cron.daily
120 5.1.5 Cấu hình phân quyền cho file /etc/cron.weekly
121 5.1.6 Cấu hình phân quyền cho của file /etc/cron.monthly
122 5.1.7 Cấu hình phân quyền cho file /etc/cron.d
123 5.1.8 Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền
124 5.2 Cấu hình máy chủ SSH
125 5.2.1 Cấu hình phân quyền cho file /etc/ssh/sshd_config
126 5.2.2 Cấu hình phân quyền cho các file SSH private host key
127 5.2.3 Cấu hình phân quyền cho các file SSH public host key
128 5.2.4 Cấu hình giới hạn truy cập cho máy chủ SSH
129 5.2.5 Cấu hình LogLevel cho máy chủ SSH
130 5.2.6 Cấu hình sử dụng SSH PAM
131 5.2.7 Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH
132 5.2.8 Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH
133 5.2.9 Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH
134 5.2.10 Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH
135 5.2.11 Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH
136 5.2.12 Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH
137 5.2.13 Cấu hình sử dụng các thuật toán mã hoá được cho phép
138 5.2.14 Cấu hình các thuật toán MAC được cho phép
139 5.2.15 Cấu hình thuật toán trao đổi khoá được cho phép
140 5.2.16 Cấu hình vô hiệu hoá SSH AllowTcpForwarding
141 5.2.17 Cấu hình cảnh báo SSH
142 5.2.18 Cấu hình SSH MaxAuthTries
143 5.2.19 Cấu hình SSH MaxStartups
144 5.2.20 Cấu hình SSH MaxSessions
145 5.2.21 Cấu hình SSH LoginGraceTime
146 5.2.22 Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH
147 5.3 Cấu hình PAM
148 5.3.1 Cấu hình điều kiện tạo mật khẩu x
149 5.3.2 Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại x
150 5.3.3 Giới hạn việc sử dụng lại mật khẩu
151 5.3.4 Cấu hình thuật toán hash mật khẩu mạnh
152 5.4 Cấu hình tài khoản người dùng và môi trường
153 5.4.1 Cấu hình mật khẩu người dùng
154 5.4.1.1 Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu x
155 5.4.1.2 Cấu hình thời gian hết hạn sử dụng mật khẩu x
156 5.4.1.3 Cấu hình thời gian cảnh báo mật khẩu hết hạn
157 5.4.1.4 Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn
158 5.4.1.5 Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ
159 5.4.2 Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống
160 5.4.3 Cấu hình group mặc định của tài khoản root
161 5.4.4 Cấu hình user umask mặc định
162 5.4.5 Cấu hình shell timeout mặc định
163 5.4.6 Cấu hình hạn chế truy cập cho câu lệnh su
164 6 System Maintenance
165 6.1 Quyền của file hệ thống
166 6.1.1 Cấu hình phân quyền cho file /etc/passwd
167 6.1.2 Cấu hình phân quyền cho file /etc/shadow
168 6.1.3 Cấu hình phân quyền cho file /etc/group
169 6.1.4 Cấu hình phân quyền cho file /etc/gshadow
170 6.1.5 Cấu hình phân quyền cho file /etc/passwd-
171 6.1.6 Cấu hình phân quyền cho file /etc/shadow-
172 6.1.7 Cấu hình phân quyền cho file /etc/group-
173 6.1.8 Cấu hình phân quyền cho file /etc/gshadow-
174 6.1.9 Đảm bảo không có file world-writable tồn tại
175 6.1.10 Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại
176 6.1.11 Đảm bảo các file hoặc thư mục không có nhóm không tồn tại
177 6.2 Thiết lập cho người dùng và nhóm
178 6.2.1 Cấu hình tài khoản trong /etc/passwd sử dụng shadowed passwords
179 6.2.2 Đảm bảo trường mật khẩu không để trống
180 6.2.3 Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group
181 6.2.4 Đảm bảo shadow group rỗng
182 6.2.5 Đảm bảo UID không bị lặp
183 6.2.6 Đảm bảo GID không bị lặp
184 6.2.7 Đảm bảo tên người dùng không bị lặp
185 6.2.8 Đảm bảo tên group không bị lặp
186 6.2.9 Đảm bảo tính toàn vẹn cho biến môi trường PATH của root
187 6.2.10 Đảm bảo root là tài khoản duy nhất có UID là 0
188 6.2.11 Đảm bảo mọi người dùng đều tồn tại thư mục home
189 6.2.12 Đảm bảo người dùng sở hữu thư mục home của chính họ
190 6.2.13 Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao
191 6.2.14 Đảm bảo không người dùng nào có file .netrc
192 6.2.15 Đảm bảo không người dùng nào có file .forward
193 6.2.16 Đảm bảo không người dùng nào có file .rhosts
194 6.2.17 Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other
195 0 0 0 17
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,206 @@
#!/bin/bash
##############################################################################
# SCRIPT CHẨN ĐOÁN CHI TIẾT NGUYÊN NHÂN FAILED CÁC TIÊU CHÍ CIS RHEL
# Tiêu chí: 1.3.1, 1.3.2, 5.1.6, 5.1.8
##############################################################################
# Màu sắc hiển thị
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
echo "=============================================================================="
echo " KIỂM TRA & CHẨN ĐOÁN CHI TIẾT CÁC ĐIỀU KIỆN FAILED"
echo "=============================================================================="
echo -e "Thời gian kiểm tra : $(date)"
echo -e "Hostname : $(hostname)"
echo -e "Hệ điều hành : $(cat /etc/redhat-release 2>/dev/null || cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')"
echo "=============================================================================="
echo ""
##############################################################################
# 1. KIỂM TRA TIÊU CHÍ 1.3.1: Cài đặt AIDE
##############################################################################
echo -e "${CYAN}--- [TIÊU CHÍ 1.3.1] Kiểm tra cài đặt gói AIDE ---${NC}"
echo "Lệnh thực hiện: rpm -q aide"
aide_pkg=$(rpm -q aide 2>&1)
if rpm -q aide >/dev/null 2>&1 || rpm -qa | grep -qi "^aide"; then
echo -e "Kết quả: ${GREEN}[PASSED]${NC} Gói AIDE đã được cài đặt ($aide_pkg)."
aide_installed=1
else
echo -e "Kết quả: ${RED}[FAILED]${NC} Gói AIDE chưa được cài đặt trên hệ thống."
echo -e "${YELLOW}-> Lý do FAILED:${NC} Lệnh 'rpm -q aide' trả về: $aide_pkg"
echo -e "${YELLOW}-> Cách khắc phục:${NC}"
echo " yum install aide # (hoặc dnf install aide)"
aide_installed=0
fi
echo ""
##############################################################################
# 2. KIỂM TRA TIÊU CHÍ 1.3.2: Cấu hình lịch chạy kiểm tra tính toàn vẹn (AIDE cron)
##############################################################################
echo -e "${CYAN}--- [TIÊU CHÍ 1.3.2] Cấu hình kiểm tra tính toàn vẹn filesystem ---${NC}"
echo "Yêu cầu: Gói AIDE phải được cài đặt VÀ có cấu hình crontab hoặc systemd timer chạy 'aide --check'."
cron_check=0
timer_check=0
# Kiểm tra crontab của root và file hệ thống
cron_matches=$(crontab -l 2>/dev/null | grep -E '^\s*[^#].*\baide\b.*--check')
sys_cron_matches=$(grep -rsE '^\s*[^#].*\baide\b.*--check' /etc/cron* /var/spool/cron 2>/dev/null)
if [ -n "$cron_matches" ] || [ -n "$sys_cron_matches" ]; then
cron_check=1
fi
# Kiểm tra systemd timer
if systemctl is-enabled aidecheck.timer 2>/dev/null | grep -q "^enabled" || \
systemctl is-enabled aide-check.timer 2>/dev/null | grep -q "^enabled"; then
timer_check=1
fi
if [ $aide_installed -eq 1 ] && { [ $cron_check -eq 1 ] || [ $timer_check -eq 1 ]; }; then
echo -e "Kết quả: ${GREEN}[PASSED]${NC} Đã cấu hình lịch kiểm tra AIDE định kỳ."
else
echo -e "Kết quả: ${RED}[FAILED]${NC} Chưa thỏa mãn yêu cầu tiêu chí 1.3.2."
echo -e "${YELLOW}-> Chi tiết chẩn đoán:${NC}"
if [ $aide_installed -eq 0 ]; then
echo " [X] Gói AIDE chưa được cài đặt (Tiền đề bắt buộc)."
else
echo " [V] Gói AIDE đã được cài đặt."
fi
if [ $cron_check -eq 1 ]; then
echo " [V] Tìm thấy lệnh chạy trong cron:"
[ -n "$cron_matches" ] && echo " + crontab: $cron_matches"
[ -n "$sys_cron_matches" ] && echo " + system cron: $sys_cron_matches"
else
echo " [X] Không tìm thấy dòng lệnh 'aide --check' trong crontab hoặc /etc/cron*."
fi
if [ $timer_check -eq 1 ]; then
echo " [V] Systemd timer aidecheck.timer đang enabled."
else
echo " [X] Systemd timer aidecheck.timer không được enable."
fi
echo -e "${YELLOW}-> Cách khắc phục:${NC}"
echo " 1. Cài đặt và khởi tạo AIDE:"
echo " yum install aide"
echo " aide --init"
echo " mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz"
echo " 2. Thêm lịch chạy vào crontab (chạy lúc 5h sáng mỗi ngày):"
echo " crontab -u root -e"
echo " # Thêm dòng sau:"
echo " 0 5 * * * /usr/sbin/aide --check"
fi
echo ""
##############################################################################
# 3. KIỂM TRA TIÊU CHÍ 5.1.6: Phân quyền file /etc/cron.monthly
##############################################################################
echo -e "${CYAN}--- [TIÊU CHÍ 5.1.6] Cấu hình phân quyền cho file /etc/cron.monthly ---${NC}"
target_file="/etc/cron.monthly"
if [ ! -e "$target_file" ]; then
echo -e "Kết quả: ${GREEN}[PASSED]${NC} Thư mục/file $target_file không tồn tại (Không bị đánh giá lỗi)."
else
file_stat=$(stat -c "%a:%u:%g" "$target_file" 2>/dev/null)
file_mode=$(stat -c "%a" "$target_file" 2>/dev/null)
file_owner=$(stat -c "%U (%u)" "$target_file" 2>/dev/null)
file_group=$(stat -c "%G (%g)" "$target_file" 2>/dev/null)
ls_info=$(ls -ld "$target_file" 2>/dev/null)
echo "Thông tin hiện tại của $target_file:"
echo " + Quyền (Permissions): $file_mode (Yêu cầu: Group và Other KHÔNG được có quyền write - tối đa 755 hoặc 700)"
echo " + Chủ sở hữu (Owner) : $file_owner (Yêu cầu: root / 0)"
echo " + Nhóm (Group) : $file_group (Yêu cầu: root / 0)"
echo " + Chi tiết ls -ld : $ls_info"
if echo "$file_stat" | grep -qE "^[0-7][0-5][0-5]:0:0$"; then
echo -e "Kết quả: ${GREEN}[PASSED]${NC} Phân quyền thỏa mãn điều kiện chuẩn CIS."
else
echo -e "Kết quả: ${RED}[FAILED]${NC} Phân quyền hoặc chủ sở hữu chưa đạt chuẩn."
echo -e "${YELLOW}-> Lý do FAILED:${NC}"
if ! echo "$file_mode" | grep -qE "^[0-7][0-5][0-5]$"; then
echo " [X] Quyền $file_mode đang cho phép Group hoặc Other có quyền ghi (write)."
fi
if [ "$(stat -c "%u" "$target_file")" != "0" ] || [ "$(stat -c "%g" "$target_file")" != "0" ]; then
echo " [X] Owner hoặc Group không phải là root (0:0)."
fi
echo -e "${YELLOW}-> Cách khắc phục:${NC}"
echo " chown root:root $target_file"
echo " chmod og-rwx $target_file # (Đưa về 700 hoặc 750/755 tùy hệ thống)"
fi
fi
echo ""
##############################################################################
# 4. KIỂM TRA TIÊU CHÍ 5.1.8: Giới hạn truy cập at/cron (cron.allow, cron.deny...)
##############################################################################
echo -e "${CYAN}--- [TIÊU CHÍ 5.1.8] Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền ---${NC}"
echo "Yêu cầu CIS: /etc/cron.allow & /etc/at.allow PHẢI TỒN TẠI | /etc/cron.deny & /etc/at.deny KHÔNG ĐƯỢC TỒN TẠI."
cron_allow_exist=0
cron_deny_exist=0
at_allow_exist=0
at_deny_exist=0
[ -f /etc/cron.allow ] && cron_allow_exist=1
[ -f /etc/cron.deny ] && cron_deny_exist=1
[ -f /etc/at.allow ] && at_allow_exist=1
[ -f /etc/at.deny ] && at_deny_exist=1
echo "Trạng thái các file trên hệ thống:"
if [ $cron_allow_exist -eq 1 ]; then
echo -e " + /etc/cron.allow : ${GREEN}Tồn tại${NC} ($(ls -l /etc/cron.allow 2>/dev/null | awk '{print $1, $3":"$4}'))"
else
echo -e " + /etc/cron.allow : ${RED}KHÔNG tồn tại (Bắt buộc phải có)${NC}"
fi
if [ $cron_deny_exist -eq 1 ]; then
echo -e " + /etc/cron.deny : ${RED}ĐANG TỒN TẠI (Bắt buộc phải XÓA bỏ)${NC} ($(ls -l /etc/cron.deny 2>/dev/null | awk '{print $1, $5" bytes"}'))"
else
echo -e " + /etc/cron.deny : ${GREEN}Không tồn tại (Đúng)${NC}"
fi
if [ $at_allow_exist -eq 1 ]; then
echo -e " + /etc/at.allow : ${GREEN}Tồn tại${NC} ($(ls -l /etc/at.allow 2>/dev/null | awk '{print $1, $3":"$4}'))"
else
echo -e " + /etc/at.allow : ${RED}KHÔNG tồn tại (Bắt buộc phải có)${NC}"
fi
if [ $at_deny_exist -eq 1 ]; then
echo -e " + /etc/at.deny : ${RED}ĐANG TỒN TẠI (Bắt buộc phải XÓA bỏ)${NC} ($(ls -l /etc/at.deny 2>/dev/null | awk '{print $1, $5" bytes"}'))"
else
echo -e " + /etc/at.deny : ${GREEN}Không tồn tại (Đúng)${NC}"
fi
if [ $cron_allow_exist -eq 1 ] && [ $cron_deny_exist -eq 0 ] && [ $at_allow_exist -eq 1 ] && [ $at_deny_exist -eq 0 ]; then
echo -e "Kết quả: ${GREEN}[PASSED]${NC} Cấu hình giới hạn at/cron hoàn toàn tuân thủ CIS."
else
echo -e "Kết quả: ${RED}[FAILED]${NC} Cấu hình at/cron chưa đạt chuẩn CIS."
echo -e "${YELLOW}-> Nguyên nhân chính khiến bạn FAILED:${NC}"
[ $cron_deny_exist -eq 1 ] && echo " [X] File /etc/cron.deny vẫn đang tồn tại (dù là file 0 bytes thì CIS vẫn đánh giá FAILED)."
[ $at_deny_exist -eq 1 ] && echo " [X] File /etc/at.deny vẫn đang tồn tại."
[ $cron_allow_exist -eq 0 ] && echo " [X] Thiếu file /etc/cron.allow."
[ $at_allow_exist -eq 0 ] && echo " [X] Thiếu file /etc/at.allow."
echo -e "${YELLOW}-> Cách khắc phục triệt để:${NC}"
echo " # Xóa file deny (Bắt buộc):"
echo " rm -f /etc/cron.deny /etc/at.deny"
echo " # Tạo file allow (Bắt buộc):"
echo " touch /etc/cron.allow /etc/at.allow"
echo " # Phân quyền chuẩn 600 root:root:"
echo " chown root:root /etc/cron.allow /etc/at.allow"
echo " chmod 600 /etc/cron.allow /etc/at.allow"
fi
echo ""
echo "=============================================================================="
echo "LƯU Ý QUAN TRỌNG VỀ CÔNG CỤ AUDIT:"
echo "Nếu bạn chạy script audit được mã hóa (.enc), hãy chắc chắn rằng file mã hóa"
echo "đã được tạo lại từ file .sh mới nhất sau khi sửa mã nguồn."
echo "=============================================================================="
+191
View File
@@ -0,0 +1,191 @@
1.1|Cấu hình filesystem
1.1.1|Cấu hình vô hiệu hoá các filesystem không sử dụng
1.1.1.1|Cấu hình vô hiệu hoá cramfs filesystem
1.1.1.2|Cấu hình vô hiệu hoá freevxfs filesystem
1.1.1.3|Cấu hình vô hiệu hoá hfs filesystem
1.1.1.4|Cấu hình vô hiệu hoá hfsplus filesystem
1.1.1.5|Cấu hình vô hiệu hoá jffs2 filesystem
1.1.1.6|Cấu hình vô hiệu hoá squashfs filesystem
1.1.1.7|Cấu hình vô hiệu hoá udf filesystem
1.1.1.8|Cấu hình vô hiệu hoá usb storage
1.1.2|Cấu hình phân vùng /tmp
1.1.2.1|Cấu hình tuỳ chọn nodev cho phân vùng /tmp
1.1.2.2|Cấu hình tuỳ chọn nosuid cho phân vùng /tmp
1.1.2.3|Cấu hình tuỳ chọn noexec cho phân vùng /tmp
1.1.3|Cấu hình phân vùng /var/tmp
1.1.3.1|Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp
1.1.3.2|Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp
1.1.3.3|Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp
1.1.4|Cấu hình phân vùng /home
1.1.4.1|Cấu hình tuỳ chọn nodev cho phân vùng /home
1.1.4.2|Cấu hình tuỳ chọn nosuid cho phân vùng /home
1.1.5|Cấu hình phân vùng /dev/shm
1.1.5.1|Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm
1.1.5.2|Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm
1.1.5.3|Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm
1.2|Cấu hình cập nhật phần mềm
1.2.1|Cấu hình kích hoạt gpgcheck
1.3|Kiểm tra tính toàn vẹn của filesystem
1.3.1|Kiểm tra cài đặt AIDE
1.3.2|Cấu hình kiểm tra tính toàn vẹn của filesystem
1.4|Cấu hình khởi động an toàn
1.4.1|Phân quyền đối với file cấu hình bootloader
1.4.2|Cấu hình mật khẩu cho bootloader
1.4.3|Cấu hình xác thực khi truy cập single user mode
1.4.4|Cấu hình vô hiệu hoá interactive boot
1.5|Additional Process Hardening
1.5.1|Cấu hình vô hiệu hoá core dump
1.5.2|Cấu hình kích hoạt ASLR (address space layout randomization)
1.5.3|Cấu hình vô hiệu hoá prelink
1.6|Kiểm soát nội dung cảnh báo
1.6.1|Kiểm soát nội dung motd (Message Of The Day)
1.6.2|Kiểm soát nội dung thông báo khi đăng nhập
1.6.3|Kiểm soát nội dung thông báo khi đăng nhập từ xa
1.6.4|Cấu hình phân quyền đối với file /etc/motd
1.6.5|Cấu hình phân quyền đối với file /etc/issue
1.6.6|Cấu hình phân quyền đối với file /etc/issue.net
1.6.7|Kiểm soát nội dung thông báo khi truy cập GNOME
2.1|Cấu hình Time Synchronization
2.1.1|Cấu hình sử dụng chrony
2.1.2|Cấu hình sử dụng ntp
2.2|Các Service với mục đích riêng biệt
2.2.1|Cấu hình vô hiệu hoá xinetd services
2.2.2|Cấu hình vô hiệu hoá chargen services
2.2.3|Cấu hình vô hiệu hoá daytime services
2.2.4|Cấu hình vô hiệu hoá discard services
2.2.5|Cấu hình vô hiệu hoá echo services
2.2.6|Cấu hình vô hiệu hoá time services
2.2.7|Cấu hình vô hiệu hoá rsh server
2.2.8|Cấu hình vô hiệu hoá talk server
2.2.9|Cấu hình vô hiệu hoá autofs services
2.2.10|Cấu hình vô hiệu hoá X window server services
2.2.11|Cấu hình vô hiệu hoá avahi daemon services
2.2.12|Cấu hình vô hiệu hoá cups services
2.2.13|Cấu hình vô hiệu hoá dhcp server services
2.2.14|Cấu hình vô hiệu hoá ldap server services
2.2.15|Cấu hình vô hiệu hoá dns server services
2.2.16|Cấu hình vô hiệu hoá dnsmasq services
2.2.17|Cấu hình vô hiệu hoá ftp server services
2.2.18|Cấu hình vô hiệu hoá tftp server services
2.2.19|Cấu hình vô hiệu hoá web server services
2.2.20|Cấu hình vô hiệu hoá imap and pop3 server services
2.2.21|Cấu hình vô hiệu hoá samba file server services
2.2.22|Cấu hình vô hiệu hoá web proxy server services
2.2.23|Cấu hình vô hiệu hoá snmp services
2.2.24|Cấu hình vô hiệu hoá nis server services
2.2.25|Cấu hình vô hiệu hoá telnet server services
2.2.26|Cấu hình mail transfer agents sang chế độ local-only
2.2.27|Cấu hình vô hiệu hoá network file system services
2.2.28|Cấu hình vô hiệu hoá rpcbind services
2.2.29|Cấu hình vô hiệu hoá rsync services
2.3|Service Clients
2.3.1|Cấu hình vô hiệu hoá nis client
2.3.2|Cấu hình vô hiệu hoá rsh client
2.3.3|Cấu hình vô hiệu hoá talk client
2.3.4|Cấu hình vô hiệu hoá telnet client
2.3.5|Cấu hình vô hiệu hoá ldap client
2.3.6|Cấu hình vô hiệu hoá ftp client
2.3.7|Cấu hình vô hiệu hoá tftp client
3.1|Tham số cấu hình mạng (Host Only)
3.1.1|Cấu hình vô hiệu hoá IP forwarding
3.1.2|Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)
3.2|Tham số cấu hình mạng (Host và Router)
3.2.1|Cấu hình từ chối các gói tin với nguồn được định tuyến trước
3.2.2|Cấu hình từ chối các ICMP redirect message
3.2.3|Cấu hình từ chối các secure ICMP redirect message
3.2.4|Cấu hình từ chối các gói tin ICMP request broadcast
3.2.5|Cấu hình bỏ qua phản hồi ICMP không hợp lệ
3.2.6|Cấu hình Reverse Path Filtering
3.2.7|Cấu hình TCP SYN Cookies
3.4|Cấu hình Firewall
3.4.1|Cấu hình firewalld
3.4.1.1|Cấu hình kích hoạt firewalld
3.4.1.3|Cấu hình firewalld rule cho tất cả các port và protocol đang mở
3.4.1.4|Cấu hình chính sách từ chối mặc định cho firewalld
3.4.2|Iptables
3.4.2.1|Cấu hình kích hoạt Iptables
3.4.2.3|Cấu hình iptables loopback traffic
3.4.2.4|Cấu hình iptables rule cho tất cả các port và protocol đang mở
3.4.2.5|Cấu hình chính sách từ chối mặc định cho iptables
4.1|Cấu hình logging
4.1.1|Cấu hình rsyslog
4.1.1.1|Cấu hình kích hoạt rsyslog service
4.1.1.2|Phân quyền đối với file log sinh ra từ rsyslog
4.1.1.3|Cấu hình lưu trữ log sinh ra từ rsyslog tập trung
4.1.1.4|Phân quyền đối với tất cả các file log
5.1|Cấu hình cron
5.1.1|Cấu hình kích hoạt cron daemon
5.1.2|Cấu hình phân quyền cho file /etc/crontab
5.1.3|Cấu hình phân quyền cho file /etc/cron.hourly
5.1.4|Cấu hình phân quyền cho file /etc/cron.daily
5.1.5|Cấu hình phân quyền cho file /etc/cron.weekly
5.1.6|Cấu hình phân quyền cho của file /etc/cron.monthly
5.1.7|Cấu hình phân quyền cho file /etc/cron.d
5.1.8|Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền
5.2|Cấu hình máy chủ SSH
5.2.1|Cấu hình phân quyền cho file /etc/ssh/sshd_config
5.2.2|Cấu hình phân quyền cho các file SSH private host key
5.2.3|Cấu hình phân quyền cho các file SSH public host key
5.2.4|Cấu hình giới hạn truy cập cho máy chủ SSH
5.2.5|Cấu hình LogLevel cho máy chủ SSH
5.2.6|Cấu hình sử dụng SSH PAM
5.2.7|Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH
5.2.8|Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH
5.2.9|Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH
5.2.10|Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH
5.2.11|Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH
5.2.12|Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH
5.2.13|Cấu hình vô hiệu hoá SSH AllowTcpForwarding
5.2.14|Cấu hình cảnh báo SSH
5.2.15|Cấu hình SSH MaxAuthTries
5.2.16|Cấu hình SSH MaxStartups
5.2.17|Cấu hình SSH MaxSessions
5.2.18|Cấu hình SSH LoginGraceTime
5.2.19|Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH
5.2.20|Cấu hình các thuật toán MAC được cho phép
5.3|Cấu hình PAM
5.3.1|Cấu hình điều kiện tạo mật khẩu
5.3.2|Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại
5.3.3|Giới hạn việc sử dụng lại mật khẩu
5.3.4|Cấu hình thuật toán hash mật khẩu sang SHA-512
5.4|Cấu hình tài khoản người dùng và môi trường
5.4.1|Cấu hình mật khẩu người dùng
5.4.1.1|Cấu hình thời gian hết hạn sử dụng mật khẩu
5.4.1.2|Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu
5.4.1.3|Cấu hình thời gian cảnh báo mật khẩu hết hạn
5.4.1.4|Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn
5.4.1.5|Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ
5.4.2|Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống
5.4.3|Cấu hình shell timeout mặc định
5.4.4|Cấu hình group mặc định của tài khoản root
5.4.5|Cấu hình user umask mặc định
5.4.6|Cấu hình hạn chế truy cập cho câu lệnh su
6.1|Quyền của file hệ thống
6.1.1|Cấu hình sticky bit cho tất cả các thư mục dùng chung
6.1.2|Cấu hình phân quyền cho file /etc/passwd
6.1.3|Cấu hình phân quyền cho file /etc/shadow
6.1.4|Cấu hình phân quyền cho file /etc/group
6.1.5|Cấu hình phân quyền cho file /etc/gshadow
6.1.6|Cấu hình phân quyền cho file /etc/passwd-
6.1.7|Cấu hình phân quyền cho file /etc/shadow-
6.1.8|Cấu hình phân quyền cho file /etc/group-
6.1.9|Cấu hình phân quyền cho file /etc/gshadow-
6.1.10|Đảm bảo không có file world-writable tồn tại
6.1.11|Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại
6.1.12|Đảm bảo các file hoặc thư mục không có nhóm không tồn tại
6.2|Thiết lập cho người dùng và nhóm
6.2.1|Đảm bảo trường mật khẩu không để trống
6.2.2|Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group
6.2.3|Đảm bảo UID không bị lặp
6.2.4|Đảm bảo GID không bị lặp
6.2.5|Đảm bảo tên người dùng không bị lặp
6.2.6|Đảm bảo tên group không bị lặp
6.2.7|Đảm bảo tính toàn vẹn cho biến môi trường PATH của root
6.2.8|Đảm bảo root là tài khoản duy nhất có UID là 0
6.2.9|Đảm bảo mọi người dùng đều tồn tại thư mục home
6.2.10|Đảm bảo người dùng sở hữu thư mục home của chính họ
6.2.11|Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao
6.2.12|Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other
6.2.13|Đảm bảo không người dùng nào có file .forward
6.2.14|Đảm bảo không người dùng nào có file .netrc
6.2.15|Đảm bảo không người dùng nào có file .rhosts
+46
View File
@@ -0,0 +1,46 @@
import argparse
import os
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
def decrypt_file(encrypted_file_path, output_file_path=None):
key_Mes = "fb8MH7yIuVUeCp5W4S9cKFtsHaxXIP/zvkO36wNNcO4="
key = base64.b64decode(key_Mes.encode("ascii"))
with open(encrypted_file_path, 'rb') as f:
encrypted_data = f.read()
cipher = Cipher(
algorithms.AES(key),
modes.ECB()
)
decryptor = cipher.decryptor()
padded_data = decryptor.update(encrypted_data) + decryptor.finalize()
# Remove PKCS7 padding
unpadder = padding.PKCS7(128).unpadder()
data = unpadder.update(padded_data) + unpadder.finalize()
if output_file_path is None:
output_file_path = encrypted_file_path.replace('.enc', '.dec')
with open(output_file_path, 'wb') as output_file:
output_file.write(data)
print(f"Decrypted to: {output_file_path}")
def main():
parser = argparse.ArgumentParser(description='Decrypt file')
parser.add_argument('-p', '--path', help='Path to encrypted file', required=True)
parser.add_argument('-o', '--out_file', help='Output file path', default=None)
args = parser.parse_args()
return args
if __name__ == '__main__':
args = main()
decrypt_file(args.path, args.out_file)
Binary file not shown.
+62
View File
@@ -0,0 +1,62 @@
import argparse
import os
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes, padding
def genSecretKey(key, salt):
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
info=None
)
secret_key = hkdf.derive(key)
return secret_key
def encrypt_file(file_path, encrypted_file_path=None):
file_name = os.path.basename(file_path)
key_Mes = "fb8MH7yIuVUeCp5W4S9cKFtsHaxXIP/zvkO36wNNcO4="
key = base64.b64decode(key_Mes.encode("ascii"))
with open(file_path, 'rb') as f:
data = f.read()
padder = padding.PKCS7(128).padder()
padded_data = padder.update(data)
padded_data += padder.finalize()
cipher = Cipher(
algorithms.AES(key),
modes.ECB()
)
encryptor = cipher.encryptor()
ct = encryptor.update(padded_data) + encryptor.finalize()
if encrypted_file_path is None:
encrypted_file_path = f"{file_name}.enc"
with open(encrypted_file_path, 'wb') as encrypted_file:
encrypted_file.write(ct)
def main():
# Parse Arguments
parser = argparse.ArgumentParser(description='Encrypt file')
parser.add_argument('-p', '--path', help='Path to file', required=True)
parser.add_argument('-o', '--out_file', help='Write to file', default=None)
args = parser.parse_args()
return args
if __name__ == '__main__':
args = main()
file_path = args.path
if args.out_file is not None:
encrypted_file_path = args.out_file
encrypt_file(file_path, encrypted_file_path)
else:
encrypt_file(file_path)
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,466 @@
============================================================================
THÔNG TIN HỆ THỐNG
============================================================================
Script Version: 2.0.2
--- Thông tin cơ bản ---
Operating System: Ubuntu 24.04.4 LTS
Kernel Version: 6.8.0-124-generic
Architecture: x86_64
Hostname: antt-ksc01
FQDN: antt-ksc01.vascloud.vnpt.vn
IP Address: 10.144.82.37
All IP Addresses: 10.144.82.37
Audit Time: 2026-07-16 16:14:20
Timezone: Asia/Ho_Chi_Minh
Uptime: up 1 week, 1 day, 5 hours, 41 minutes
--- Thông tin CPU ---
CPU Model: Intel(R) Xeon(R) Gold 5220R CPU @ 2.20GHz
CPU Cores: 16
CPU Architecture: x86_64
--- Thông tin Memory ---
Total Memory: 15Gi
Used Memory: 1.5Gi
Free Memory: 7.9Gi
Swap Total: 15Gi
--- Thông tin Disk ---
Disk Usage:
/ 16G used of 482G (4%)
/ 16G used of 482G (4%)
/ 16G used of 482G (4%)
/tmp 0 used of 7.8G (0%)
--- Thông tin Network Interfaces ---
Primary Interface: ens160
MAC Address: 00:50:56:9e:6d:4a
Default Gateway: 10.144.82.33
DNS Servers: 127.0.0.53
--- Thông tin bổ sung ---
AppArmor Status: Enabled
UFW Status: Status: active
Last Boot: 2026-07-08 10:33
Current Users: 3
Load Average: 0.76 0.40 0.50
Ubuntu Version Detected: 24.04
============================================================================
IPv6 Status: DISABLED (kernel support not available)
############################################################################
{"1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem" : "PASSED"}
{"1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem" : "PASSED"}
{"1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem" : "PASSED"}
{"1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem" : "PASSED"}
{"1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem" : "PASSED"}
{"1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem" : "PASSED"}
{"1.1.1.7. Cấu hình vô hiệu hoá udf filesystem" : "PASSED"}
{"1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp" : "PASSED"}
{"1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp" : "PASSED"}
{"1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /tmp. Ví dụ:
# tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0
# Thực hiện các lệnh sau để mount phân vùng /tmp và cập nhật cấu hình fstab:
# mount /tmp
# mount -o remount /tmp
-------------------
######################################
{"1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp" : "PASSED"}
{"1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp" : "PASSED"}
{"1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /var/tmp. Ví dụ:
# tmpfs /var/tmp tmpfs defaults,nodev,nosuid,noexec 0 0
# Thực hiện các lệnh sau để mount phân vùng /var/tmp và cập nhật cấu hình fstab:
# mount /var/tmp
# mount -o remount /var/tmp
-------------------
######################################
{"1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home" : "PASSED"}
{"1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /home. Ví dụ:
# <device> /home <fstype> defaults,nodev,nosuid 0 0
# Thực hiện các lệnh sau để cập nhật cấu hình fstab:
# mount -o remount /home
-------------------
######################################
{"1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm" : "PASSED"}
{"1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm" : "PASSED"}
{"1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /dev/shm. Ví dụ:
# tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0
# Thực hiện các lệnh sau để mount phân vùng /dev/shm và cập nhật cấu hình fstab:
# mount /dev/shm
# mount -o remount /dev/shm
-------------------
######################################
{"1.1.6. Cấu hình sticky bit cho tất cả các thư mục dùng chung" : "PASSED"}
{"2.2.2. Cấu hình vô hiệu hoá autofs services" : "PASSED"}
{"1.1.8. Cấu hình vô hiệu hoá usb storage" : "PASSED"}
{"1.2.1. Kiểm tra cài đặt AIDE" : "PASSED"}
{"1.2.2. Cấu hình kiểm tra tính toàn vẹn của filesystem" : "PASSED"}
{"1.3.1. Phân quyền đối với file cấu hình bootloader" : "PASSED"}
{"1.3.2. Cấu hình xác thực khi truy cập single user mode" : "PASSED"}
{"1.3.3. Cấu hình xác thực khi truy cập single user mode" : "PASSED"}
{"1.4.1. Cấu hình kích hoạt ASLR (address space layout randomization)" : "PASSED"}
{"1.4.2. Cấu hình vô hiệu hoá prelink" : "PASSED"}
{"1.4.3. Cấu hình vô hiệu hoá core dump" : "PASSED"}
{"1.5.1. Kiểm soát nội dung motd (Message Of The Day)" : "PASSED"}
{"1.5.2. Kiểm soát nội dung thông báo khi đăng nhập" : "PASSED"}
{"1.5.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa" : "PASSED"}
{"1.5.4. Cấu hình phân quyền đối với file /etc/motd" : "PASSED"}
######################################
{"1.5.5. Cấu hình phân quyền đối với file /etc/issue" : "PASSED"}
{"1.5.6. Cấu hình phân quyền đối với file /etc/issue.net" : "PASSED"}
{"1.5.7. Kiểm soát nội dung thông báo khi truy cập GNOME" : "PASSED"}
{"2.1.1. Cấu hình sử dụng chrony" : "PASSED"}
{"2.1.2. Cấu hình sử dụng NTP" : "PASSED"}
######################################
{"2.2.1. Cấu hình vô hiệu hoá xinetd services" : "PASSED"}
----------[PASSED]----------
#dpkg -l | grep xinetd
----------[PASSED]----------
#systemctl is-enabled xinetd.service
not-found
----------[PASSED]----------
#systemctl is-active xinetd.service
inactive
----------LOG----------
#systemctl is-enabled xinetd.service
not-found
#systemctl is-active xinetd.service
inactive
{"2.2.3. Cấu hình vô hiệu hoá X window server services" : "PASSED"}
{"2.2.4. Cấu hình vô hiệu hoá avahi daemon services" : "PASSED"}
{"2.2.5. Cấu hình vô hiệu hoá cups services" : "PASSED"}
{"2.2.6. Cấu hình vô hiệu hoá dhcp server services" : "PASSED"}
{"2.2.7. Cấu hình vô hiệu hoá ldap server services" : "PASSED"}
{"2.2.6. Cấu hình vô hiệu hoá NFS" : "PASSED"}
{"2.2.8. Cấu hình vô hiệu hoá dns server services" : "PASSED"}
######################################
{"2.2.9. Cấu hình vô hiệu hoá dnsmasq services" : "PASSED"}
----------[PASSED]----------
#grep -E "\s[7-9].[0-9]" /etc/os-release
----------[PASSED]----------
#dpkg-query -l dnsmasq
----------[PASSED]----------
#systemctl is-enabled dnsmasq.service
not-found
----------[PASSED]----------
#systemctl is-active dnsmasq.service
inactive
----------LOG----------
PRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.4 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
{"2.2.10. Cấu hình vô hiệu hoá ftp server services" : "PASSED"}
{"2.2.12. Cấu hình vô hiệu hoá web server services" : "PASSED"}
######################################
{"2.2.11. Cấu hình vô hiệu hoá tftp server services" : "PASSED"}
----------[PASSED]----------
#grep -E "\s[7-9].[0-9]" /etc/os-release
----------[PASSED]----------
#dpkg -l | grep tftpd-hpa
----------[PASSED]----------
#systemctl is-enabled tftp.socket
not-found
----------[PASSED]----------
#systemctl is-enabled tftpd-hpa.service
not-found
----------[PASSED]----------
#systemctl is-active tftp.socket
inactive
----------[PASSED]----------
#systemctl is-active tftpd-hpa.service
inactive
----------LOG----------
{"2.2.13. Cấu hình vô hiệu hoá imap and pop3 server services" : "PASSED"}
{"2.2.14. Cấu hình vô hiệu hoá samba file server services" : "PASSED"}
{"2.2.15. Cấu hình vô hiệu hoá web proxy server services" : "PASSED"}
{"2.2.16. Cấu hình vô hiệu hoá snmp services" : "PASSED"}
{"2.2.14. Cấu hình vô hiệu hoá telnetd" : "PASSED"}
{"2.2.15. Cấu hình vô hiệu hoá rsh-server" : "PASSED"}
{"2.2.18. Cấu hình mail transfer agents sang chế độ local-only" : "PASSED"}
######################################
{"2.2.17. Cấu hình vô hiệu hoá nis server services" : "PASSED"}
----------[PASSED]----------
#dpkg -l | grep ypserv
----------[PASSED]----------
#systemctl is-enabled ypserv.service
not-found
----------[PASSED]----------
#systemctl is-active ypserv.service
inactive
----------LOG----------
#systemctl is-enabled ypserv.service
not-found
#systemctl is-active ypserv.service
inactive
######################################
{"2.2.19. Cấu hình vô hiệu hoá network file system services" : "PASSED"}
----------[PASSED]----------
#dpkg -l | grep nfs-kernel-server
----------[PASSED]----------
#systemctl is-enabled nfs-server.service
not-found
----------[PASSED]----------
#systemctl is-active nfs-server.service
inactive
----------LOG----------
#systemctl is-enabled nfs-server.service
not-found
#systemctl is-active nfs-server.service
inactive
{"2.2.20. Cấu hình vô hiệu hoá rsync services" : "PASSED"}
{"2.3.1. Cấu hình vô hiệu hoá nis client" : "PASSED"}
{"2.3.2. Cấu hình vô hiệu hoá rsh client" : "PASSED"}
{"2.3.3. Cấu hình vô hiệu hoá talk client" : "PASSED"}
{"2.3.4. Cấu hình vô hiệu hoá telnet client" : "PASSED"}
{"2.3.5. Cấu hình vô hiệu hoá ldap client" : "PASSED"}
{"2.3.6. Cấu hình vô hiệu hoá rpc" : "PASSED"}
{"2.3.7. Cấu hình vô hiệu hoá ftp client" : "PASSED"}
----------[PASSED]----------
#grep -E "\s[7-9].[0-9]" /etc/os-release
----------[PASSED]----------
#dpkg -l | grep ftp
ii openssh-sftp-server 1:9.6p1-3ubuntu13.18 amd64 secure shell (SSH) sftp server module, for SFTP access from remote machines
ii tnftp 20230507-2build3 amd64 enhanced ftp client
----------LOG----------
######################################
{"3.1.1. Cấu hình vô hiệu hoá IP forwarding" : "PASSED"}
######################################
{"3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)" : "PASSED"}
######################################
{"3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước" : "PASSED"}
########## STDERR BEGIN ##########
/bin/bash: line 2: f: command not found
########## STDERR END ##########
######################################
{"3.2.2. Cấu hình từ chối các ICMP redirect message" : "PASSED"}
######################################
{"3.2.3. Cấu hình từ chối các secure ICMP redirect message" : "PASSED"}
######################################
{"3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast" : "PASSED"}
######################################
{"3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ" : "PASSED"}
######################################
{"3.2.6. Cấu hình Reverse Path Filtering" : "PASSED"}
######################################
{"3.3.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước (Source Routed Packet Acceptance)" : "PASSED"}
{"3.3.2. Cấu hình từ chối các ICMP redirect message" : "PASSED"}
{"3.3.3. Cấu hình từ chối các secure ICMP redirect message" : "PASSED"}
{"3.3.4. Cấu hình từ chối các gói tin ICMP request broadcast" : "PASSED"}
{"3.3.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ" : "PASSED"}
{"3.3.6. Cấu hình Reverse Path Filtering" : "PASSED"}
{"3.2.7. Cấu hình TCP SYN Cookies" : "PASSED"}
{"3.3.8. Cấu hình từ chối IPv6 router advertisements" : "PASSED"}
{"3.4.1.1. Cấu hình kích hoạt ufw" : "PASSED"}
{"3.4.2.1. Cấu hình kích hoạt Iptables" : "PASSED"}
{"3.4.1.2. Cấu hình vô hiệu hoá iptables-persistent, nftables khi sử dụng ufw" : "PASSED"}
{"3.4.1.3. Cấu hình ufw loopback traffic" : "PASSED"}
{"3.4.1.4. Cấu hình ufw rule cho tất cả các port và protocol đang mở" : "PASSED"}
######################################
# Các rule UFW hiện tại:
-------------------
Status: active
To Action From
-- ------ ----
[ 1] Anywhere on lo ALLOW IN Anywhere
[ 2] Anywhere ALLOW OUT Anywhere on lo (out)
[ 3] Anywhere DENY IN 127.0.0.0/8
[ 4] 22/tcp ALLOW IN Anywhere
[ 5] 53 ALLOW OUT Anywhere (out)
[ 6] 80/tcp ALLOW OUT Anywhere (out)
[ 7] 443/tcp ALLOW OUT Anywhere (out)
[ 8] 123/udp ALLOW OUT Anywhere (out)
[ 9] 11371/tcp ALLOW OUT Anywhere (out)
[10] Anywhere (v6) on lo ALLOW IN Anywhere (v6)
[11] Anywhere (v6) ALLOW OUT Anywhere (v6) on lo (out)
[12] Anywhere (v6) DENY IN ::1
[13] 22/tcp (v6) ALLOW IN Anywhere (v6)
[14] 53 (v6) ALLOW OUT Anywhere (v6) (out)
[15] 80/tcp (v6) ALLOW OUT Anywhere (v6) (out)
[16] 443/tcp (v6) ALLOW OUT Anywhere (v6) (out)
[17] 123/udp (v6) ALLOW OUT Anywhere (v6) (out)
[18] 11371/tcp (v6) ALLOW OUT Anywhere (v6) (out)
-------------------
# Inbound rules (ALLOW):
Anywhere on lo ALLOW Anywhere
22/tcp ALLOW Anywhere
Anywhere (v6) on lo ALLOW Anywhere (v6)
22/tcp (v6) ALLOW Anywhere (v6)
-------------------
# Outbound rules (ALLOW OUT):
Anywhere ALLOW OUT Anywhere on lo
53 ALLOW OUT Anywhere
80/tcp ALLOW OUT Anywhere
443/tcp ALLOW OUT Anywhere
123/udp ALLOW OUT Anywhere
11371/tcp ALLOW OUT Anywhere
Anywhere (v6) ALLOW OUT Anywhere (v6) on lo
53 (v6) ALLOW OUT Anywhere (v6)
80/tcp (v6) ALLOW OUT Anywhere (v6)
443/tcp (v6) ALLOW OUT Anywhere (v6)
123/udp (v6) ALLOW OUT Anywhere (v6)
11371/tcp (v6) ALLOW OUT Anywhere (v6)
-------------------
# IPv6 rules:
Anywhere (v6) on lo ALLOW Anywhere (v6)
Anywhere (v6) DENY ::1
22/tcp (v6) ALLOW Anywhere (v6)
Anywhere (v6) ALLOW OUT Anywhere (v6) on lo
53 (v6) ALLOW OUT Anywhere (v6)
80/tcp (v6) ALLOW OUT Anywhere (v6)
443/tcp (v6) ALLOW OUT Anywhere (v6)
123/udp (v6) ALLOW OUT Anywhere (v6)
11371/tcp (v6) ALLOW OUT Anywhere (v6)
######################################
{"3.4.1.5. Cấu hình chính sách từ chối mặc định cho ufw" : "PASSED"}
{"3.4.2.2. Cấu hình vô hiệu hoá ufw, nftables khi sử dụng iptables" : "PASSED"}
{"3.4.2.3. Cấu hình iptables loopback traffic" : "PASSED"}
{"3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở" : "PASSED"}
{"3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables" : "PASSED"}
{"4.1.1.1. Cấu hình kích hoạt rsyslog service" : "PASSED"}
{"4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog" : "PASSED"}
{"4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung" : "FAILED"}
######################################
# Chỉnh sửa file /etc/rsyslog.conf và /etc/rsyslog.d/*.conf và thêm vào 1 trong các dòng sau:
# <files to sent to the remote log server> action(type="omfwd" target="<FQDN or ip of loghost>" port="<port number>" protocol="tcp" action.resumeRetryCount="<number of re-tries>" queue.type="LinkedList" queue.size=<number of messages to queue>") # Hoặc
# *.* @@< FQDN or ip of loghost >
# Thực hiện câu lệnh sau để khởi động lại rsyslog:
# systemctl restart rsyslog
-------------------
#grep -E '^\h*([^#]+\s+)?action\(([^#]+\s+)?\btarget=\?[^#"]+\?\b' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2>/dev/null -ne 0
######################################
######################################
{"4.1.1.4. Phân quyền đối với tất cả các file log" : "PASSED"}
{"4.1.2. Phân quyền đối với tất cả các file log" : "PASSED"}
{"5.1.1. Cấu hình kích hoạt cron daemon" : "PASSED"}
{"5.1.2. Cấu hình phân quyền cho file /etc/crontab" : "PASSED"}
{"5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly" : "PASSED"}
{"5.1.4. Cấu hình phân quyền cho file /etc/cron.daily" : "PASSED"}
{"5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly" : "PASSED"}
{"5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly" : "PASSED"}
{"5.1.7. Cấu hình phân quyền cho file /etc/cron.d" : "PASSED"}
{"5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền" : "PASSED"}
{"5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config" : "PASSED"}
{"5.2.2. Cấu hình phân quyền cho các file SSH private host key" : "PASSED"}
{"5.2.3. Cấu hình phân quyền cho các file SSH public host key" : "PASSED"}
{"5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH" : "PASSED"}
{"5.2.5. Cấu hình LogLevel cho máy chủ SSH" : "PASSED"}
{"5.2.6. Cấu hình sử dụng SSH PAM" : "PASSED"}
{"5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH" : "PASSED"}
{"5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH" : "PASSED"}
{"5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH" : "PASSED"}
{"5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH" : "PASSED"}
{"5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH" : "PASSED"}
{"5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH" : "PASSED"}
{"5.2.13. Cấu hình sử dụng các thuật toán mã hoá được cho phép" : "PASSED"}
{"5.2.14. Cấu hình các thuật toán MAC được cho phép" : "PASSED"}
{"5.2.15. Cấu hình thuật toán trao đổi khoá được cho phép" : "PASSED"}
{"5.2.16. Cấu hình vô hiệu hoá SSH AllowTcpForwarding" : "PASSED"}
{"5.2.17. Cấu hình cảnh báo SSH" : "PASSED"}
{"5.2.18. Cấu hình SSH MaxAuthTries" : "PASSED"}
{"5.2.19. Cấu hình SSH MaxStartups" : "PASSED"}
{"5.2.20. Cấu hình SSH MaxSessions" : "PASSED"}
{"5.2.21. Cấu hình SSH LoginGraceTime" : "PASSED"}
{"5.2.22. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH" : "PASSED"}
{"5.3.1. Cấu hình điều kiện tạo mật khẩu" : "PASSED"}
{"5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại" : "PASSED"}
{"5.3.3. Giới hạn việc sử dụng lại mật khẩu" : "PASSED"}
{"5.3.4. Cấu hình thuật toán hash mật khẩu mạnh" : "FAILED"}
######################################
# Đối với phiên bản 22.04 trở lên:
# Chỉnh sửa file /etc/pam.d/common-password đảm bảo rằng không có bất cứ thuật toán hash nào được cấu hình trong pam_unix.so như dưới đây:
# password [success=1 default=ignore] pam_unix.so remember=5
# Thêm hoặc chỉnh sửa ENCRYPT_METHOD trong file /etc/login.defs như sau:
# ENCRYPT_METHOD yescrypt
# Đối với phiên bản 20.04 trở về trước: Chỉnh sửa file /etc/pam.d/common-password để có tuỳ chọn sha512 cho pam_unix.so như dưới đây:
# password [success=1 default=ignore] pam_unix.so sha512 remember=5
-------------------
#grep -P "^\h*password\h*\[success=1 default=ignore\]\h*pam_unix.so.*sha512" /etc/pam.d/common-password -ne 0
-------------------
#grep -v ^# /etc/pam.d/common-password | grep -E "(yescrypt|md5|bigcrypt|sha256|sha512|blowfish)" -eq 0
password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt
######################################
{"5.4.1.1. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu" : "PASSED"}
{"5.4.1.2. Cấu hình thời gian hết hạn sử dụng mật khẩu" : "PASSED"}
{"5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn" : "PASSED"}
{"5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn" : "PASSED"}
{"5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ" : "PASSED"}
{"5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống" : "PASSED"}
{"5.4.3. Cấu hình group mặc định của tài khoản root" : "PASSED"}
{"5.4.4. Cấu hình user umask mặc định" : "PASSED"}
{"5.4.5. Cấu hình shell timeout mặc định" : "PASSED"}
{"5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su" : "PASSED"}
{"6.1.1. Cấu hình phân quyền cho file /etc/passwd" : "PASSED"}
{"6.1.2. Cấu hình phân quyền cho file /etc/shadow" : "PASSED"}
{"6.1.3. Cấu hình phân quyền cho file /etc/group" : "PASSED"}
{"6.1.4. Cấu hình phân quyền cho file /etc/gshadow" : "PASSED"}
{"6.1.5. Cấu hình phân quyền cho file /etc/passwd-" : "PASSED"}
{"6.1.6. Cấu hình phân quyền cho file /etc/shadow-" : "PASSED"}
{"6.1.7. Cấu hình phân quyền cho file /etc/group-" : "PASSED"}
{"6.1.8. Cấu hình phân quyền cho file /etc/gshadow-" : "PASSED"}
{"6.1.9. Đảm bảo không có file world-writable tồn tại" : "PASSED"}
{"6.1.10. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại" : "PASSED"}
{"6.1.11. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại" : "PASSED"}
{"6.2.1. Cấu hình tài khoản trong /etc/passwd sử dụng shadowed passwords" : "PASSED"}
{"6.2.2. Đảm bảo trường mật khẩu không để trống" : "FAILED"}
######################################
# Nếu có tài khoản nào trong file /etc/shadow không có mật khẩu, thực hiện câu lệnh sau để khoá tài khoản đến khi xác định được nguyên nhân tài khoản đó không có mật khẩu:
# passwd -l <username>
# Đồng thời, kiểm tra tài khoản đó được đăng nhập hay chưa và tìm hiểu xem tài khoản đó được sử dụng với mục đích gì để nếu nó cần phải bị xóa.
-------------------
#awk -F: '$5==90 && $6==7 {print}' /etc/shadow | awk -F: ' $2=="!" || $2=="" || $2=="!!"{print $1 " " $2}' -eq 0
ldnobody !
######################################
{"6.2.3. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group" : "PASSED"}
{"6.2.4. Đảm bảo shadow group rỗng" : "PASSED"}
{"6.2.5. Đảm bảo UID không bị lặp" : "PASSED"}
{"6.2.6. Đảm bảo GID không bị lặp" : "PASSED"}
{"6.2.7. Đảm bảo tên người dùng không bị lặp" : "PASSED"}
{"6.2.8. Đảm bảo tên group không bị lặp" : "PASSED"}
{"6.2.9. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root" : "PASSED"}
{"6.2.10. Đảm bảo root là tài khoản duy nhất có UID là 0" : "PASSED"}
{"6.2.11. Đảm bảo mọi người dùng đều tồn tại thư mục home" : "PASSED"}
{"6.2.12. Đảm bảo người dùng sở hữu thư mục home của chính họ" : "PASSED"}
{"6.2.13. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao" : "PASSED"}
{"6.2.14. Đảm bảo không người dùng nào có file .netrc" : "PASSED"}
{"6.2.15. Đảm bảo không người dùng nào có file .forward" : "PASSED"}
{"6.2.16. Đảm bảo không người dùng nào có file .rhosts" : "PASSED"}
{"6.2.17. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other" : "PASSED"}
@@ -0,0 +1,464 @@
============================================================================
THÔNG TIN HỆ THỐNG
============================================================================
Script Version: 2.0.2
--- Thông tin cơ bản ---
Operating System: Ubuntu 24.04.4 LTS
Kernel Version: 6.8.0-124-generic
Architecture: x86_64
Hostname: antt-ksc01
FQDN: antt-ksc01.vascloud.vnpt.vn
IP Address: 10.144.82.37
All IP Addresses: 10.144.82.37
Audit Time: 2026-07-16 14:18:53
Timezone: Asia/Ho_Chi_Minh
Uptime: up 1 week, 1 day, 3 hours, 45 minutes
--- Thông tin CPU ---
CPU Model: Intel(R) Xeon(R) Gold 5220R CPU @ 2.20GHz
CPU Cores: 16
CPU Architecture: x86_64
--- Thông tin Memory ---
Total Memory: 15Gi
Used Memory: 1.5Gi
Free Memory: 8.5Gi
Swap Total: 15Gi
--- Thông tin Disk ---
Disk Usage:
/ 15G used of 482G (4%)
/ 15G used of 482G (4%)
/ 15G used of 482G (4%)
/tmp 0 used of 7.8G (0%)
--- Thông tin Network Interfaces ---
Primary Interface: ens160
MAC Address: 00:50:56:9e:6d:4a
Default Gateway: 10.144.82.33
DNS Servers: 127.0.0.53
--- Thông tin bổ sung ---
AppArmor Status: Enabled
UFW Status: Status: active
Last Boot: 2026-07-08 10:33
Current Users: 3
Load Average: 0.20 0.09 0.08
Ubuntu Version Detected: 24.04
============================================================================
IPv6 Status: DISABLED (kernel support not available)
############################################################################
{"1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem" : "PASSED"}
{"1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem" : "PASSED"}
{"1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem" : "PASSED"}
{"1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem" : "PASSED"}
{"1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem" : "PASSED"}
{"1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem" : "PASSED"}
{"1.1.1.7. Cấu hình vô hiệu hoá udf filesystem" : "PASSED"}
{"1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp" : "PASSED"}
{"1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp" : "PASSED"}
{"1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /tmp. Ví dụ:
# tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0
# Thực hiện các lệnh sau để mount phân vùng /tmp và cập nhật cấu hình fstab:
# mount /tmp
# mount -o remount /tmp
-------------------
######################################
{"1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp" : "PASSED"}
{"1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp" : "PASSED"}
{"1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /var/tmp. Ví dụ:
# tmpfs /var/tmp tmpfs defaults,nodev,nosuid,noexec 0 0
# Thực hiện các lệnh sau để mount phân vùng /var/tmp và cập nhật cấu hình fstab:
# mount /var/tmp
# mount -o remount /var/tmp
-------------------
######################################
{"1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home" : "PASSED"}
{"1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /home. Ví dụ:
# <device> /home <fstype> defaults,nodev,nosuid 0 0
# Thực hiện các lệnh sau để cập nhật cấu hình fstab:
# mount -o remount /home
-------------------
######################################
{"1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm" : "PASSED"}
{"1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm" : "PASSED"}
{"1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm" : "PASSED"}
-------------------
# Chỉnh sửa file /etc/fstab và thêm tùy chọn nodev, nosuid, noexec vào trường thứ 4 trong cấu hình của phân vùng /dev/shm. Ví dụ:
# tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0
# Thực hiện các lệnh sau để mount phân vùng /dev/shm và cập nhật cấu hình fstab:
# mount /dev/shm
# mount -o remount /dev/shm
-------------------
######################################
{"1.1.6. Cấu hình sticky bit cho tất cả các thư mục dùng chung" : "PASSED"}
{"2.2.2. Cấu hình vô hiệu hoá autofs services" : "PASSED"}
{"1.1.8. Cấu hình vô hiệu hoá usb storage" : "PASSED"}
{"1.2.1. Kiểm tra cài đặt AIDE" : "PASSED"}
{"1.2.2. Cấu hình kiểm tra tính toàn vẹn của filesystem" : "PASSED"}
{"1.3.1. Phân quyền đối với file cấu hình bootloader" : "PASSED"}
{"1.3.2. Cấu hình xác thực khi truy cập single user mode" : "PASSED"}
{"1.3.3. Cấu hình xác thực khi truy cập single user mode" : "PASSED"}
{"1.4.1. Cấu hình kích hoạt ASLR (address space layout randomization)" : "PASSED"}
{"1.4.2. Cấu hình vô hiệu hoá prelink" : "PASSED"}
{"1.4.3. Cấu hình vô hiệu hoá core dump" : "PASSED"}
{"1.5.1. Kiểm soát nội dung motd (Message Of The Day)" : "PASSED"}
{"1.5.2. Kiểm soát nội dung thông báo khi đăng nhập" : "PASSED"}
{"1.5.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa" : "PASSED"}
{"1.5.4. Cấu hình phân quyền đối với file /etc/motd" : "PASSED"}
######################################
{"1.5.5. Cấu hình phân quyền đối với file /etc/issue" : "PASSED"}
{"1.5.6. Cấu hình phân quyền đối với file /etc/issue.net" : "PASSED"}
{"1.5.7. Kiểm soát nội dung thông báo khi truy cập GNOME" : "PASSED"}
{"2.1.1. Cấu hình sử dụng chrony" : "PASSED"}
{"2.1.2. Cấu hình sử dụng NTP" : "PASSED"}
######################################
{"2.2.1. Cấu hình vô hiệu hoá xinetd services" : "PASSED"}
----------[PASSED]----------
#dpkg -l | grep xinetd
----------[PASSED]----------
#systemctl is-enabled xinetd.service
not-found
----------[PASSED]----------
#systemctl is-active xinetd.service
inactive
----------LOG----------
#systemctl is-enabled xinetd.service
not-found
#systemctl is-active xinetd.service
inactive
{"2.2.3. Cấu hình vô hiệu hoá X window server services" : "PASSED"}
{"2.2.4. Cấu hình vô hiệu hoá avahi daemon services" : "PASSED"}
{"2.2.5. Cấu hình vô hiệu hoá cups services" : "PASSED"}
{"2.2.6. Cấu hình vô hiệu hoá dhcp server services" : "PASSED"}
{"2.2.7. Cấu hình vô hiệu hoá ldap server services" : "PASSED"}
{"2.2.6. Cấu hình vô hiệu hoá NFS" : "PASSED"}
{"2.2.8. Cấu hình vô hiệu hoá dns server services" : "PASSED"}
######################################
{"2.2.9. Cấu hình vô hiệu hoá dnsmasq services" : "PASSED"}
----------[PASSED]----------
#grep -E "\s[7-9].[0-9]" /etc/os-release
----------[PASSED]----------
#dpkg-query -l dnsmasq
----------[PASSED]----------
#systemctl is-enabled dnsmasq.service
not-found
----------[PASSED]----------
#systemctl is-active dnsmasq.service
inactive
----------LOG----------
PRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.4 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
{"2.2.10. Cấu hình vô hiệu hoá ftp server services" : "PASSED"}
{"2.2.12. Cấu hình vô hiệu hoá web server services" : "PASSED"}
######################################
{"2.2.11. Cấu hình vô hiệu hoá tftp server services" : "PASSED"}
----------[PASSED]----------
#grep -E "\s[7-9].[0-9]" /etc/os-release
----------[PASSED]----------
#dpkg -l | grep tftpd-hpa
----------[PASSED]----------
#systemctl is-enabled tftp.socket
not-found
----------[PASSED]----------
#systemctl is-enabled tftpd-hpa.service
not-found
----------[PASSED]----------
#systemctl is-active tftp.socket
inactive
----------[PASSED]----------
#systemctl is-active tftpd-hpa.service
inactive
----------LOG----------
{"2.2.13. Cấu hình vô hiệu hoá imap and pop3 server services" : "PASSED"}
{"2.2.14. Cấu hình vô hiệu hoá samba file server services" : "PASSED"}
{"2.2.15. Cấu hình vô hiệu hoá web proxy server services" : "PASSED"}
{"2.2.16. Cấu hình vô hiệu hoá snmp services" : "PASSED"}
{"2.2.14. Cấu hình vô hiệu hoá telnetd" : "PASSED"}
{"2.2.15. Cấu hình vô hiệu hoá rsh-server" : "PASSED"}
{"2.2.18. Cấu hình mail transfer agents sang chế độ local-only" : "PASSED"}
######################################
{"2.2.17. Cấu hình vô hiệu hoá nis server services" : "PASSED"}
----------[PASSED]----------
#dpkg -l | grep ypserv
----------[PASSED]----------
#systemctl is-enabled ypserv.service
not-found
----------[PASSED]----------
#systemctl is-active ypserv.service
inactive
----------LOG----------
#systemctl is-enabled ypserv.service
not-found
#systemctl is-active ypserv.service
inactive
######################################
{"2.2.19. Cấu hình vô hiệu hoá network file system services" : "PASSED"}
----------[PASSED]----------
#dpkg -l | grep nfs-kernel-server
----------[PASSED]----------
#systemctl is-enabled nfs-server.service
not-found
----------[PASSED]----------
#systemctl is-active nfs-server.service
inactive
----------LOG----------
#systemctl is-enabled nfs-server.service
not-found
#systemctl is-active nfs-server.service
inactive
{"2.2.20. Cấu hình vô hiệu hoá rsync services" : "PASSED"}
{"2.3.1. Cấu hình vô hiệu hoá nis client" : "PASSED"}
{"2.3.2. Cấu hình vô hiệu hoá rsh client" : "PASSED"}
{"2.3.3. Cấu hình vô hiệu hoá talk client" : "PASSED"}
{"2.3.4. Cấu hình vô hiệu hoá telnet client" : "PASSED"}
{"2.3.5. Cấu hình vô hiệu hoá ldap client" : "PASSED"}
{"2.3.6. Cấu hình vô hiệu hoá rpc" : "PASSED"}
{"2.3.7. Cấu hình vô hiệu hoá ftp client" : "PASSED"}
----------[PASSED]----------
#grep -E "\s[7-9].[0-9]" /etc/os-release
----------[PASSED]----------
#dpkg -l | grep ftp
ii openssh-sftp-server 1:9.6p1-3ubuntu13.16 amd64 secure shell (SSH) sftp server module, for SFTP access from remote machines
ii tnftp 20230507-2build3 amd64 enhanced ftp client
----------LOG----------
######################################
{"3.1.1. Cấu hình vô hiệu hoá IP forwarding" : "PASSED"}
######################################
{"3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)" : "PASSED"}
######################################
{"3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước" : "PASSED"}
######################################
{"3.2.2. Cấu hình từ chối các ICMP redirect message" : "PASSED"}
######################################
{"3.2.3. Cấu hình từ chối các secure ICMP redirect message" : "PASSED"}
######################################
{"3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast" : "PASSED"}
######################################
{"3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ" : "PASSED"}
######################################
{"3.2.6. Cấu hình Reverse Path Filtering" : "PASSED"}
######################################
{"3.3.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước (Source Routed Packet Acceptance)" : "PASSED"}
{"3.3.2. Cấu hình từ chối các ICMP redirect message" : "PASSED"}
{"3.3.3. Cấu hình từ chối các secure ICMP redirect message" : "PASSED"}
{"3.3.4. Cấu hình từ chối các gói tin ICMP request broadcast" : "PASSED"}
{"3.3.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ" : "PASSED"}
{"3.3.6. Cấu hình Reverse Path Filtering" : "PASSED"}
{"3.2.7. Cấu hình TCP SYN Cookies" : "PASSED"}
{"3.3.8. Cấu hình từ chối IPv6 router advertisements" : "PASSED"}
{"3.4.1.1. Cấu hình kích hoạt ufw" : "PASSED"}
{"3.4.2.1. Cấu hình kích hoạt Iptables" : "PASSED"}
{"3.4.1.2. Cấu hình vô hiệu hoá iptables-persistent, nftables khi sử dụng ufw" : "PASSED"}
{"3.4.1.3. Cấu hình ufw loopback traffic" : "PASSED"}
{"3.4.1.4. Cấu hình ufw rule cho tất cả các port và protocol đang mở" : "PASSED"}
######################################
# Các rule UFW hiện tại:
-------------------
Status: active
To Action From
-- ------ ----
[ 1] Anywhere on lo ALLOW IN Anywhere
[ 2] Anywhere ALLOW OUT Anywhere on lo (out)
[ 3] Anywhere DENY IN 127.0.0.0/8
[ 4] 22/tcp ALLOW IN Anywhere
[ 5] 53 ALLOW OUT Anywhere (out)
[ 6] 80/tcp ALLOW OUT Anywhere (out)
[ 7] 443/tcp ALLOW OUT Anywhere (out)
[ 8] 123/udp ALLOW OUT Anywhere (out)
[ 9] Anywhere (v6) on lo ALLOW IN Anywhere (v6)
[10] Anywhere (v6) ALLOW OUT Anywhere (v6) on lo (out)
[11] Anywhere (v6) DENY IN ::1
[12] 22/tcp (v6) ALLOW IN Anywhere (v6)
[13] 53 (v6) ALLOW OUT Anywhere (v6) (out)
[14] 80/tcp (v6) ALLOW OUT Anywhere (v6) (out)
[15] 443/tcp (v6) ALLOW OUT Anywhere (v6) (out)
[16] 123/udp (v6) ALLOW OUT Anywhere (v6) (out)
-------------------
# Inbound rules (ALLOW):
Anywhere on lo ALLOW Anywhere
22/tcp ALLOW Anywhere
Anywhere (v6) on lo ALLOW Anywhere (v6)
22/tcp (v6) ALLOW Anywhere (v6)
-------------------
# Outbound rules (ALLOW OUT):
Anywhere ALLOW OUT Anywhere on lo
53 ALLOW OUT Anywhere
80/tcp ALLOW OUT Anywhere
443/tcp ALLOW OUT Anywhere
123/udp ALLOW OUT Anywhere
Anywhere (v6) ALLOW OUT Anywhere (v6) on lo
53 (v6) ALLOW OUT Anywhere (v6)
80/tcp (v6) ALLOW OUT Anywhere (v6)
443/tcp (v6) ALLOW OUT Anywhere (v6)
123/udp (v6) ALLOW OUT Anywhere (v6)
-------------------
# IPv6 rules:
Anywhere (v6) on lo ALLOW Anywhere (v6)
Anywhere (v6) DENY ::1
22/tcp (v6) ALLOW Anywhere (v6)
Anywhere (v6) ALLOW OUT Anywhere (v6) on lo
53 (v6) ALLOW OUT Anywhere (v6)
80/tcp (v6) ALLOW OUT Anywhere (v6)
443/tcp (v6) ALLOW OUT Anywhere (v6)
123/udp (v6) ALLOW OUT Anywhere (v6)
######################################
{"3.4.1.5. Cấu hình chính sách từ chối mặc định cho ufw" : "PASSED"}
{"3.4.2.2. Cấu hình vô hiệu hoá ufw, nftables khi sử dụng iptables" : "PASSED"}
{"3.4.2.3. Cấu hình iptables loopback traffic" : "PASSED"}
{"3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở" : "PASSED"}
{"3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables" : "PASSED"}
{"4.1.1.1. Cấu hình kích hoạt rsyslog service" : "PASSED"}
{"4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog" : "PASSED"}
{"4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung" : "FAILED"}
######################################
# Chỉnh sửa file /etc/rsyslog.conf và /etc/rsyslog.d/*.conf và thêm vào 1 trong các dòng sau:
# <files to sent to the remote log server> action(type="omfwd" target="<FQDN or ip of loghost>" port="<port number>" protocol="tcp" action.resumeRetryCount="<number of re-tries>" queue.type="LinkedList" queue.size=<number of messages to queue>") # Hoặc
# *.* @@< FQDN or ip of loghost >
# Thực hiện câu lệnh sau để khởi động lại rsyslog:
# systemctl restart rsyslog
-------------------
#grep -E '^\h*([^#]+\s+)?action\(([^#]+\s+)?\btarget=\?[^#"]+\?\b' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2>/dev/null -ne 0
######################################
######################################
{"4.1.1.4. Phân quyền đối với tất cả các file log" : "PASSED"}
{"4.1.2. Phân quyền đối với tất cả các file log" : "PASSED"}
{"5.1.1. Cấu hình kích hoạt cron daemon" : "PASSED"}
{"5.1.2. Cấu hình phân quyền cho file /etc/crontab" : "PASSED"}
{"5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly" : "PASSED"}
{"5.1.4. Cấu hình phân quyền cho file /etc/cron.daily" : "PASSED"}
{"5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly" : "PASSED"}
{"5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly" : "PASSED"}
{"5.1.7. Cấu hình phân quyền cho file /etc/cron.d" : "PASSED"}
{"5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền" : "PASSED"}
{"5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config" : "PASSED"}
{"5.2.2. Cấu hình phân quyền cho các file SSH private host key" : "PASSED"}
{"5.2.3. Cấu hình phân quyền cho các file SSH public host key" : "PASSED"}
{"5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH" : "PASSED"}
{"5.2.5. Cấu hình LogLevel cho máy chủ SSH" : "PASSED"}
{"5.2.6. Cấu hình sử dụng SSH PAM" : "PASSED"}
{"5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH" : "PASSED"}
{"5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH" : "PASSED"}
{"5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH" : "PASSED"}
{"5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH" : "PASSED"}
{"5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH" : "PASSED"}
{"5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH" : "PASSED"}
{"5.2.13. Cấu hình sử dụng các thuật toán mã hoá được cho phép" : "PASSED"}
{"5.2.14. Cấu hình các thuật toán MAC được cho phép" : "PASSED"}
{"5.2.15. Cấu hình thuật toán trao đổi khoá được cho phép" : "PASSED"}
{"5.2.16. Cấu hình vô hiệu hoá SSH AllowTcpForwarding" : "PASSED"}
{"5.2.17. Cấu hình cảnh báo SSH" : "PASSED"}
{"5.2.18. Cấu hình SSH MaxAuthTries" : "PASSED"}
{"5.2.19. Cấu hình SSH MaxStartups" : "PASSED"}
{"5.2.20. Cấu hình SSH MaxSessions" : "PASSED"}
{"5.2.21. Cấu hình SSH LoginGraceTime" : "PASSED"}
{"5.2.22. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH" : "PASSED"}
{"5.3.1. Cấu hình điều kiện tạo mật khẩu" : "PASSED"}
{"5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại" : "PASSED"}
{"5.3.3. Giới hạn việc sử dụng lại mật khẩu" : "PASSED"}
{"5.3.4. Cấu hình thuật toán hash mật khẩu mạnh" : "FAILED"}
######################################
# Đối với phiên bản 22.04 trở lên:
# Chỉnh sửa file /etc/pam.d/common-password đảm bảo rằng không có bất cứ thuật toán hash nào được cấu hình trong pam_unix.so như dưới đây:
# password [success=1 default=ignore] pam_unix.so remember=5
# Thêm hoặc chỉnh sửa ENCRYPT_METHOD trong file /etc/login.defs như sau:
# ENCRYPT_METHOD yescrypt
# Đối với phiên bản 20.04 trở về trước: Chỉnh sửa file /etc/pam.d/common-password để có tuỳ chọn sha512 cho pam_unix.so như dưới đây:
# password [success=1 default=ignore] pam_unix.so sha512 remember=5
-------------------
#grep -P "^\h*password\h*\[success=1 default=ignore\]\h*pam_unix.so.*sha512" /etc/pam.d/common-password -ne 0
-------------------
#grep -v ^# /etc/pam.d/common-password | grep -E "(yescrypt|md5|bigcrypt|sha256|sha512|blowfish)" -eq 0
password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt
######################################
{"5.4.1.1. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu" : "PASSED"}
{"5.4.1.2. Cấu hình thời gian hết hạn sử dụng mật khẩu" : "PASSED"}
{"5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn" : "PASSED"}
{"5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn" : "PASSED"}
{"5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ" : "PASSED"}
{"5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống" : "PASSED"}
{"5.4.3. Cấu hình group mặc định của tài khoản root" : "PASSED"}
{"5.4.4. Cấu hình user umask mặc định" : "PASSED"}
{"5.4.5. Cấu hình shell timeout mặc định" : "PASSED"}
{"5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su" : "PASSED"}
{"6.1.1. Cấu hình phân quyền cho file /etc/passwd" : "PASSED"}
{"6.1.2. Cấu hình phân quyền cho file /etc/shadow" : "PASSED"}
{"6.1.3. Cấu hình phân quyền cho file /etc/group" : "PASSED"}
{"6.1.4. Cấu hình phân quyền cho file /etc/gshadow" : "PASSED"}
{"6.1.5. Cấu hình phân quyền cho file /etc/passwd-" : "PASSED"}
{"6.1.6. Cấu hình phân quyền cho file /etc/shadow-" : "PASSED"}
{"6.1.7. Cấu hình phân quyền cho file /etc/group-" : "PASSED"}
{"6.1.8. Cấu hình phân quyền cho file /etc/gshadow-" : "PASSED"}
{"6.1.9. Đảm bảo không có file world-writable tồn tại" : "PASSED"}
{"6.1.10. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại" : "PASSED"}
{"6.1.11. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại" : "PASSED"}
{"6.2.1. Cấu hình tài khoản trong /etc/passwd sử dụng shadowed passwords" : "PASSED"}
{"6.2.2. Đảm bảo trường mật khẩu không để trống" : "PASSED"}
{"6.2.3. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group" : "PASSED"}
{"6.2.4. Đảm bảo shadow group rỗng" : "PASSED"}
{"6.2.5. Đảm bảo UID không bị lặp" : "PASSED"}
{"6.2.6. Đảm bảo GID không bị lặp" : "PASSED"}
{"6.2.7. Đảm bảo tên người dùng không bị lặp" : "PASSED"}
{"6.2.8. Đảm bảo tên group không bị lặp" : "PASSED"}
{"6.2.9. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root" : "FAILED"}
######################################
# Thực hiện đoạn script sau để kiểm tra tính toàn vẹn cho môi trường PATH của root:
# RPCV="$(sudo -Hiu root env 2>/dev/null | grep '^PATH=' | cut -d= -f2)"; echo "$RPCV" | grep -q "::" && echo "root's path contains a empty directory (::)"; echo "$RPCV" | grep -q ":$" && echo "root's path contains a trailing (:)" ; for x in $(echo "$RPCV" | tr ":" " "); do if [ -d "$x" ]; then ls -ldH "$x" | awk '$9 == "." {print "PATH contains current working directory (.)"} $3 != "root" {print $9, "is not owned by root"} substr($1,6,1) != "-" {print $9, "is group writable"} substr($1,9,1) != "-" {print $9, "is world writable"}'; else echo "$x is not a directory"; fi; done
# Sửa chữa hoặc lý giải kết quả tìm được.
-------------------
#RPCV="$(sudo -Hiu root env 2>/dev/null | grep '^PATH=' | cut -d= -f2)"; echo "$RPCV" | grep -q "::" && echo "root's path contains a empty directory (::)"; echo "$RPCV" | grep -q ":$" && echo "root's path contains a trailing (:)" ; for x in $(echo "$RPCV" | tr ":" " "); do if [ -d "$x" ]; then ls -ldH "$x" | awk '$9 == "." {print "PATH contains current working directory (.)"} $3 != "root" {print $9, "is not owned by root"} substr($1,6,1) != "-" {print $9, "is group writable"} substr($1,9,1) != "-" {print $9, "is world writable"}'; else echo "$x is not a directory"; fi; done | grep -v "/root/bin" -eq 0
/snap/bin is not a directory
######################################
{"6.2.10. Đảm bảo root là tài khoản duy nhất có UID là 0" : "PASSED"}
{"6.2.11. Đảm bảo mọi người dùng đều tồn tại thư mục home" : "PASSED"}
{"6.2.12. Đảm bảo người dùng sở hữu thư mục home của chính họ" : "PASSED"}
{"6.2.13. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao" : "FAILED"}
######################################
# Thực hiện đoạn script sau để đặt quyền cho thư mục home của tất cả người dùng là 750:
# awk -F: '($1\!~/(halt|sync|shutdown|nfsnobody)/ && $7\!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7\!~/(\/usr)?\/bin\/false(\/)?$/) {print $6}' /etc/passwd | while read -r dir; do if [ -d "$dir" ]; then dirperm=$(stat -L -c "%A" "$dir"); if [ "$(echo "$dirperm" | cut -c6)" != "-" ] || [ "$(echo "$dirperm" | cut -c8)" != "-" ] || [ "$(echo "$dirperm" | cut -c9)" != "-" ] || [ "$(echo "$dirperm" | cut -c10)" != "-" ]; then chmod g-w,o-rwx "$dir"; fi; fi; done
-------------------
#awk -F: '($1\!~/(halt|sync|shutdown|nfsnobody)/ && $7\!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7\!~/(\/usr)?\/bin\/false(\/)?$/) {print $1 " " $6}' /etc/passwd | while read -r user dir; do if [ ! -d "$dir" ]; then echo "User: \"$user\" home directory: \"$dir\" doesn't exist"; else dirperm=$(stat -L -c "%A" "$dir"); if [ "$(echo "$dirperm" | cut -c6)" != "-" ] || [ "$(echo "$dirperm" | cut -c8)" != "-" ] || [ "$(echo "$dirperm" | cut -c9)" != "-" ] || [ "$(echo "$dirperm" | cut -c10)" != "-" ]; then echo "User: \"$user\" home directory: \"$dir\" has permissions: \"$(stat -L -c "%a" "$dir")\""; fi; fi; done -eq 0
User: "cicd_to2" home directory: "/home/cicd_to2" has permissions: "755"
User: "landesk" home directory: "/opt/landesk" has permissions: "755"
######################################
{"6.2.14. Đảm bảo không người dùng nào có file .netrc" : "PASSED"}
{"6.2.15. Đảm bảo không người dùng nào có file .forward" : "PASSED"}
{"6.2.16. Đảm bảo không người dùng nào có file .rhosts" : "PASSED"}
{"6.2.17. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other" : "PASSED"}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+60
View File
@@ -0,0 +1,60 @@
#!/bin/bash
# Script chẩn đoán và kiểm tra chi tiết điều kiện AIDE (1.3.1 & 1.3.2)
echo "=========================================================="
echo " KIỂM TRA CHẨN ĐOÁN CHI TIẾT AIDE"
echo "=========================================================="
echo "Thời gian: $(date)"
echo "Người dùng chạy script: $(whoami)"
echo ""
echo "--- [BƯỚC 1] Kiểm tra gói phần mềm AIDE (Điều kiện 1.3.1) ---"
echo "1.1 Kiểm tra bằng lệnh 'rpm -q aide':"
rpm -q aide 2>&1 | sed 's/^/ -> /'
if rpm -q aide >/dev/null 2>&1 || rpm -qa | grep -qi "^aide"; then
echo " => [PASSED] Gói AIDE đã được cài đặt."
else
echo " => [FAILED] Gói AIDE chưa được cài đặt."
fi
echo ""
echo "--- [BƯỚC 2] Kiểm tra lịch chạy định kỳ (Điều kiện 1.3.2) ---"
echo "2.1 Kiểm tra 'crontab -l' của user hiện tại ($(whoami)):"
crontab -l 2>/dev/null | grep -v "^#" | sed 's/^/ -> /'
if crontab -l 2>/dev/null | grep -Eq '^\s*[^#].*\baide\b.*--check'; then
echo " => [PASSED] Tìm thấy lệnh chạy AIDE trong crontab hiện tại!"
else
echo " => [KHÔNG TÌM THẤY] Không khớp lệnh aide --check trong crontab -l."
fi
echo ""
echo "2.2 Kiểm tra trong các file hệ thống /etc/crontab và /etc/cron* và /var/spool/cron:"
grep -rnE '^\s*[^#].*\baide\b' /etc/cron* /var/spool/cron 2>/dev/null | sed 's/^/ -> /'
if grep -rsEq '^\s*[^#].*\baide\b.*--check' /etc/cron* /var/spool/cron 2>/dev/null; then
echo " => [PASSED] Tìm thấy lệnh chạy AIDE trong các file cron hệ thống!"
else
echo " => [KHÔNG TÌM THẤY] Không có lệnh aide --check trong /etc/cron* hoặc /var/spool/cron."
fi
echo ""
echo "2.3 Kiểm tra systemd timer cho AIDE:"
systemctl list-timers --all 2>/dev/null | grep -i aide | sed 's/^/ -> /'
if systemctl is-enabled aidecheck.timer >/dev/null 2>&1 || systemctl is-enabled aide-check.timer >/dev/null 2>&1; then
echo " => [PASSED] Tìm thấy systemd timer cho AIDE được kích hoạt!"
else
echo " => [KHÔNG TÌM THẤY] Không có systemd timer aidecheck."
fi
echo ""
echo "=========================================================="
echo "--- TỔNG KẾT ĐÁNH GIÁ 1.3.2 ---"
if (crontab -l 2>/dev/null | grep -Eq '^\s*[^#].*\baide\b.*--check') || \
grep -rsEq '^\s*[^#].*\baide\b.*--check' /etc/cron* /var/spool/cron 2>/dev/null || \
systemctl is-enabled aidecheck.timer 2>/dev/null | grep -q "^enabled" || \
systemctl is-enabled aide-check.timer 2>/dev/null | grep -q "^enabled"; then
echo "=> KẾT QUẢ CUỐI CÙNG: PASSED (Đủ điều kiện 1.3.2)"
else
echo "=> KẾT QUẢ CUỐI CÙNG: FAILED (Chưa thỏa mãn điều kiện 1.3.2)"
fi
echo "=========================================================="
@@ -0,0 +1,79 @@
#!/bin/bash
echo "=========================================================="
echo " TEST SCRIPT: KIỂM TRA LỖI FIREWALL DEFAULT DENY "
echo "=========================================================="
echo "[1] Trạng thái của firewalld theo systemctl:"
raw_status=$(systemctl is-active firewalld 2>&1)
echo " -> Output trả về: [$raw_status]"
FIREWALLD_ACTIVE=0
if echo "$raw_status" | grep -q "^active"; then
FIREWALLD_ACTIVE=1
echo " -> Đánh giá: FIREWALLD_ACTIVE = 1 (Đã nhận diện đang chạy)"
else
echo " -> Đánh giá: FIREWALLD_ACTIVE = 0 (Không nhận diện được firewalld qua systemctl)"
fi
echo "----------------------------------------------------------"
echo "[2] Đọc các active zone từ firewall-cmd:"
active_zones=$(firewall-cmd --list-all-zones 2>/dev/null | grep "active")
if [ -z "$active_zones" ]; then
echo " -> KHÔNG TÌM THẤY BẤT KỲ ACTIVE ZONE NÀO! (Hoặc firewall-cmd bị lỗi)"
else
echo " -> Các zone đang active tìm thấy:"
echo "$active_zones" | while read -r line; do
echo " - $line"
done
fi
echo "----------------------------------------------------------"
echo "[3] Phân tích chi tiết qua awk (chế độ DEBUG):"
fw_default_deny=$(firewall-cmd --list-all-zones 2>/dev/null | awk '
BEGIN {
print " [AWK] Bắt đầu đọc output từ firewall-cmd..." > "/dev/stderr"
bad=0
}
/\(active\)/ {
in_active=1;
print " [AWK] >> Vào active zone: " $0 > "/dev/stderr"
next
}
/^[^ \t\r\n]/ && !/\(active\)/ {
if (in_active == 1) {
print " [AWK] << Thoát active zone vì gặp dòng: " $0 > "/dev/stderr"
}
in_active=0
}
in_active && /target:/ {
t = $2
gsub(/%%/, "", t)
print " [AWK] -- Bắt được target: [" t "]" > "/dev/stderr"
if (t != "DROP" && t != "REJECT") {
print " [AWK] -- [!] PHÁT HIỆN VI PHẠM: [" t "] không phải là DROP hay REJECT" > "/dev/stderr"
bad=1
} else {
print " [AWK] -- [v] ĐẠT: [" t "] hợp lệ" > "/dev/stderr"
}
}
END {
print " [AWK] Kết thúc phân tích. Giá trị biến bad = " bad > "/dev/stderr"
print (bad ? "0" : "1")
}
')
echo "----------------------------------------------------------"
echo "[4] TỔNG HỢP KẾT QUẢ:"
echo " -> Giá trị biến fw_default_deny: [$fw_default_deny]"
if [ "$FIREWALLD_ACTIVE" -eq 1 ]; then
if [ "$fw_default_deny" = "1" ]; then
echo " -> KẾT QUẢ CUỐI CÙNG: PASSED (Đạt chuẩn)"
else
echo " -> KẾT QUẢ CUỐI CÙNG: FAILED (Vi phạm)"
fi
else
echo " -> KẾT QUẢ CUỐI CÙNG: FAILED (Bị fail ngay từ bước check firewalld active)"
fi
echo "=========================================================="
+286
View File
@@ -0,0 +1,286 @@
"""
Windows Audit Hardening Tool - v2.0
Usage: AuditTool.exe -p audit_cis_windows.ps1.enc
AuditTool.exe (uses bundled .enc file)
Build: python -m PyInstaller --onefile --console -n AuditTool ^
--add-data "audit_cis_windows.ps1.enc;." ^
windows_audit.py
Environment: Python 3.8+ (3.8 for Windows Server 2012 compatibility)
"""
import argparse
import base64
import os
import socket
import subprocess
import sys
import tempfile
import traceback
from Crypto.Cipher import PKCS1_OAEP, AES
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import unpad
from colorama import Fore, init as colorama_init
from unidecode import unidecode
# ----------------------------------------------------------
# Globals
# ----------------------------------------------------------
colorama_init(strip=False, autoreset=True)
HOSTNAME = socket.gethostname()
try:
IP_ADDR = socket.gethostbyname(HOSTNAME)
except Exception:
IP_ADDR = "127.0.0.1"
AES_KEY_B64 = "fb8MH7yIuVUeCp5W4S9cKFtsHaxXIP/zvkO36wNNcO4="
BUNDLED_ENC = "audit_cis_windows.ps1.enc"
PUBLIC_KEY_FILE = "public_key.pem"
BANNER = r"""
_ _ _____ _____ _______ _ _ _____ _____ ______ _ _ _____ _ _ _____
/\ | | | | __ \_ _|__ __| | | | | /\ | __ \| __ \| ____| \ | |_ _| \ | |/ ____|
/ \ | | | | | | || | | | ______ | |__| | / \ | |__) | | | | |__ | \| | | | | \| | | __
/ /\ \| | | | | | || | | | |______| | __ | / /\ \ | _ /| | | | __| | . ` | | | | . ` | | |_ |
/ ____ \ |__| | |__| || |_ | | | | | |/ ____ \| | \ \| |__| | |____| |\ |_| |_| |\ | |__| |
/_/ \_\____/|_____/_____| |_| |_| |_/_/ \_\_| \_\_____/|______|_| \_|_____|_| \_|\_____|
"""
# ----------------------------------------------------------
# Path resolution (supports PyInstaller bundle)
# ----------------------------------------------------------
def resource_path(relative_path):
"""Get absolute path to resource, works for dev and PyInstaller."""
if getattr(sys, "frozen", False):
base = sys._MEIPASS
else:
base = os.path.dirname(os.path.abspath(__file__))
return os.path.join(base, relative_path)
def resolve_enc_path(user_path=None):
"""
Resolve the .enc file path.
Priority: user-supplied arg > bundled file > same-dir file.
Returns absolute path or None.
"""
if user_path:
if os.path.isfile(user_path):
return os.path.abspath(user_path)
print(Fore.YELLOW + "[WARNING] Provided path not found: {}".format(user_path) + Fore.RESET)
# Try PyInstaller bundled location
bundled = resource_path(BUNDLED_ENC)
if os.path.isfile(bundled):
return bundled
# Try same directory
same_dir = os.path.join(os.getcwd(), BUNDLED_ENC)
if os.path.isfile(same_dir):
return same_dir
return None
def resolve_public_key():
"""Find public_key.pem - bundled, same dir, or current dir."""
for loc in [
resource_path(PUBLIC_KEY_FILE),
os.path.join(os.getcwd(), PUBLIC_KEY_FILE),
]:
if os.path.isfile(loc):
return loc
return None
# ----------------------------------------------------------
# Crypto helpers
# ----------------------------------------------------------
def decrypt_aes(file_path, key_b64):
"""Decrypt an AES-ECB (PKCS7 padded) encrypted file."""
key = base64.b64decode(key_b64)
with open(file_path, "rb") as fh:
ct = fh.read()
cipher = AES.new(key, AES.MODE_ECB)
padded = cipher.decrypt(ct)
data = unpad(padded, AES.block_size, style="pkcs7")
return data.decode("utf-8")
def encrypt_output_rsa(content):
"""Encrypt output with RSA-OAEP; fall back to plaintext if no key."""
pk_path = resolve_public_key()
if pk_path is None:
return "PLAINTEXT:" + content
try:
pub_key = RSA.import_key(open(pk_path, "rb").read())
cipher = PKCS1_OAEP.new(pub_key)
raw = content.encode("utf-8")
block_size = 190
ciphertext = b""
for i in range(0, len(raw), block_size):
ciphertext += cipher.encrypt(raw[i : i + block_size])
return base64.b64encode(ciphertext).decode("utf-8")
except Exception as e:
print(Fore.YELLOW + "[WARNING] RSA encrypt failed: {}".format(e) + Fore.RESET)
return "PLAINTEXT:" + content
# ----------------------------------------------------------
# PowerShell runner
# ----------------------------------------------------------
def run_powershell_script(script_content, timeout_sec=600):
"""
Write script to temp .ps1 file, execute via 'powershell -File',
return (stdout, stderr, returncode).
"""
tmp_path = None
try:
fd, tmp_path = tempfile.mkstemp(suffix=".ps1", prefix="audit_")
with os.fdopen(fd, "w", encoding="utf-8") as fh:
fh.write(script_content)
proc = subprocess.run(
[
"powershell.exe",
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-File", tmp_path,
],
capture_output=True,
text=True,
timeout=timeout_sec,
encoding="utf-8",
errors="replace",
)
return proc.stdout, proc.stderr, proc.returncode
except subprocess.TimeoutExpired:
return "", "PowerShell execution timed out ({}s)".format(timeout_sec), -1
except Exception:
return "", traceback.format_exc(), -1
finally:
if tmp_path and os.path.exists(tmp_path):
try:
os.remove(tmp_path)
except Exception:
pass
# ----------------------------------------------------------
# Output parsing
# ----------------------------------------------------------
def extract_audit_info(output):
"""Extract hostname + timestamp from audit output lines."""
hostname = HOSTNAME
timestamp = "unknown"
for line in output.splitlines():
if line.startswith("Hostname:"):
val = line.replace("Hostname:", "").strip()
hostname = val if val else HOSTNAME
elif line.startswith("Time:"):
val = line.replace("Time:", "").strip()
timestamp = val.replace("-", "_").replace(":", "_").replace(" ", "-") if val else "unknown"
return hostname, timestamp
def count_pass_fail(output):
"""Count PASSED/FAILED from JSON lines."""
passed = failed = 0
for line in output.splitlines():
line = line.strip()
if line.startswith("{") and line.endswith("}"):
if '"PASSED"' in line or "'PASSED'" in line:
passed += 1
elif '"FAILED"' in line or "'FAILED'" in line:
failed += 1
return passed, failed
# ----------------------------------------------------------
# Main audit flow
# ----------------------------------------------------------
def run_audit(enc_path=None):
"""Decrypt .enc, run PowerShell audit, encrypt+save results."""
print(Fore.BLUE + BANNER + Fore.RESET)
print(Fore.RED + "Running Audit Hardening v2.0" + Fore.RESET)
print(" Hostname : {}".format(HOSTNAME))
print(" IP : {}".format(IP_ADDR))
print("-" * 70)
# Step 0 Resolve input file
enc_path = resolve_enc_path(enc_path)
if enc_path is None:
print(Fore.RED + "ERROR: No .enc file found.")
print(" Provide path: AuditTool.exe -p audit_cis_windows.ps1.enc")
print(" Or place {} in the same directory.".format(BUNDLED_ENC) + Fore.RESET)
return
print(" Source : {}".format(enc_path))
# Step 1 Decrypt
print(" [1/4] Decrypting...")
try:
ps_content = decrypt_aes(enc_path, AES_KEY_B64)
except Exception as e:
print(Fore.RED + " FAILED: {}".format(e) + Fore.RESET)
return
print(" [1/4] OK - {} bytes".format(len(ps_content)))
# Step 2 Execute PowerShell
print(" [2/4] Running PowerShell...")
stdout, stderr, rc = run_powershell_script(ps_content)
if rc != 0:
print(Fore.YELLOW + " [2/4] PowerShell rc={}: {}".format(rc, (stderr or "")[:200]) + Fore.RESET)
else:
print(" [2/4] OK - {} output lines".format(len(stdout.splitlines())))
# Step 3 Combine
full_output = stdout
if stderr:
full_output += "\n[STDERR]\n" + stderr
if not full_output.strip():
print(Fore.RED + "ERROR: No output from PowerShell" + Fore.RESET)
return
passed, failed = count_pass_fail(full_output)
print(" [3/4] Audit: {} PASSED / {} FAILED".format(passed, failed))
# Step 4 Encrypt & save
hostname_out, timestamp = extract_audit_info(stdout)
out_filename = "{}_{}.txt.enc".format(hostname_out, timestamp)
print(" [4/4] Encrypting -> {}".format(out_filename))
encrypted = encrypt_output_rsa(full_output)
with open(out_filename, "w", encoding="utf-8") as fh:
fh.write(encrypted)
if os.path.isfile(out_filename):
print(Fore.GREEN + "=" * 70 + Fore.RESET)
print(Fore.GREEN + " SUCCESS: {} | {} PASS / {} FAIL".format(
out_filename, passed, failed) + Fore.RESET)
print(Fore.GREEN + "=" * 70 + Fore.RESET)
else:
print(Fore.RED + " FAILED: Could not write output file" + Fore.RESET)
# ----------------------------------------------------------
# CLI
# ----------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="Audit Hardening v2.0")
parser.add_argument(
"-p", "--path",
help="Path to encrypted .ps1.enc file (optional if bundled or in same dir)",
default=None,
)
return parser.parse_args()
if __name__ == "__main__":
args = main()
run_audit(args.path)
BIN
View File
Binary file not shown.
+38
View File
@@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['windows_audit.py'],
pathex=[],
binaries=[],
datas=[('audit_cis_windows.ps1', '.')],
hiddenimports=['Crypto.Cipher', 'Crypto.PublicKey', 'Crypto.Util.Padding'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='AuditTool',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+442
View File
@@ -0,0 +1,442 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import base64, os, socket, subprocess, tempfile, sys, binascii
import re
from datetime import datetime
# ---- Compatibility for CentOS 6 (Py2.6/2.7) ----
# Safe print (UTF-8, hỗ trợ stream=file)
def _p(msg, color=None, stream=None, **kwargs):
# Back-compat cho calls kiểu file=...
if stream is None and 'file' in kwargs:
stream = kwargs['file']
if stream is None:
stream = sys.stdout
try:
unicode # Py2 check
b = msg.encode('utf-8') if isinstance(msg, unicode) else msg
except NameError:
b = msg
try:
if color:
stream.write(color)
stream.write(b)
if color:
try:
stream.write(Fore.RESET)
except Exception:
pass
stream.write("\n")
except Exception:
try:
stream.write((u'' + msg).encode('utf-8') + "\n")
except Exception:
sys.stdout.write((u'' + msg).encode('utf-8') + "\n")
# optparse (có sẵn trên Py2.6)
try:
from optparse import OptionParser
except Exception:
OptionParser = None # fallback rất cũ
# Color handling (tùy chọn)
try:
from colorama import Fore, init as colorama_init
colorama_init()
except Exception:
class _NoColor(object):
def __getattr__(self, name): return ''
Fore = _NoColor()
BUNDLED_SCRIPT = "audit_cis_centos6.sh"
def resource_path(relative_path):
if getattr(sys, "frozen", False):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path)
def resolve_script_path(user_path=None):
if user_path and os.path.isfile(user_path):
return os.path.abspath(user_path)
bundled = resource_path(BUNDLED_SCRIPT)
if os.path.isfile(bundled):
return bundled
same_dir = os.path.join(os.getcwd(), BUNDLED_SCRIPT)
if os.path.isfile(same_dir):
return same_dir
return None
def detect_os_name():
"""
Trả về chuỗi tên HĐH ngắn gọn.
Ưu tiên /etc/*-release; fallback sang uname -srm.
"""
paths = [
'/etc/centos-release',
'/etc/redhat-release',
'/etc/os-release', # có trên bản mới hơn
'/etc/lsb-release', # có thể chứa DISTRIB_DESCRIPTION=
]
for p in paths:
try:
if os.path.isfile(p):
data = open(p, 'rb').read()
try:
text = data.decode('utf-8', 'ignore')
except Exception:
text = data
# /etc/lsb-release
if 'DISTRIB_DESCRIPTION=' in text:
for line in text.splitlines():
if line.startswith('DISTRIB_DESCRIPTION='):
val = line.split('=',1)[1].strip().strip('"')
return val
# các file *release khác: dùng dòng đầu
first = text.splitlines()[0].strip()
if first:
return first
except Exception:
pass
# Fallback: uname
try:
out = subprocess.Popen("uname -srm", shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
try:
return out.decode('utf-8','ignore').strip()
except Exception:
return out.strip()
except Exception:
return 'Unknown-OS'
try:
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
except Exception:
hostname = 'unknown-host'
IPAddr = '127.0.0.1'
cwd = os.getcwd()
def pkcs7_unpad(data, block_size=16):
if not data:
return data
pad_len = ord(data[-1]) if isinstance(data[-1], str) else data[-1]
if pad_len < 1 or pad_len > block_size:
# Defensive: return as-is to avoid exception storms in Py2 envs
return data
return data[:-pad_len]
def write_content(content, use_oaep=True):
"""
Hybrid AES-256-CBC + RSA encryption using OpenSSL CLI.
Only 1 RSA operation for the AES key; bulk data encrypted with fast AES.
Output: HYBRID_V1:<b64_enc_key>:<b64_iv>:<b64_ciphertext>
"""
import binascii
pubkey_path = os.path.join(os.getcwd(), 'public_key.pem')
if not os.path.isfile(pubkey_path):
raise RuntimeError("public_key.pem khong ton tai tai: %s" % pubkey_path)
try:
unicode
if isinstance(content, unicode):
message = content.encode('utf-8')
else:
message = content
except NameError:
if isinstance(content, str):
message = content.encode('utf-8')
else:
message = content
aes_key = os.urandom(32)
iv = os.urandom(16)
fd_in, path_in = tempfile.mkstemp(prefix='aes_in_', dir='/tmp')
fd_out, path_out = tempfile.mkstemp(prefix='aes_out_', dir='/tmp')
os.close(fd_in)
os.close(fd_out)
try:
with open(path_in, 'wb') as f:
f.write(message)
key_hex = binascii.hexlify(aes_key)
iv_hex = binascii.hexlify(iv)
cmd_aes = [
'/usr/bin/openssl', 'enc', '-aes-256-cbc',
'-K', key_hex, '-iv', iv_hex,
'-in', path_in, '-out', path_out
]
p = subprocess.Popen(cmd_aes, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
raise RuntimeError("OpenSSL AES encrypt error (rc=%d): %s" % (p.returncode, err))
with open(path_out, 'rb') as f:
ciphertext = f.read()
finally:
try: os.remove(path_in)
except: pass
try: os.remove(path_out)
except: pass
fd_key_in, path_key_in = tempfile.mkstemp(prefix='rsa_key_in_', dir='/tmp')
fd_key_out, path_key_out = tempfile.mkstemp(prefix='rsa_key_out_', dir='/tmp')
os.close(fd_key_in)
os.close(fd_key_out)
try:
with open(path_key_in, 'wb') as f:
f.write(aes_key)
cmd_rsa = [
'/usr/bin/openssl', 'rsautl', '-encrypt',
'-pubin', '-inkey', pubkey_path,
'-in', path_key_in, '-out', path_key_out
]
if use_oaep:
cmd_rsa.insert(3, '-oaep')
else:
cmd_rsa.insert(3, '-pkcs')
p = subprocess.Popen(cmd_rsa, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if p.returncode != 0:
raise RuntimeError("OpenSSL rsautl error (rc=%d): %s" % (p.returncode, err))
with open(path_key_out, 'rb') as f:
enc_key = f.read()
finally:
try: os.remove(path_key_in)
except: pass
try: os.remove(path_key_out)
except: pass
b64_enc_key = base64.b64encode(enc_key)
b64_iv = base64.b64encode(iv)
b64_ct = base64.b64encode(ciphertext)
return b"HYBRID_V1:" + b64_enc_key + b":" + b64_iv + b":" + b64_ct
def _key_b64_to_hex(key_b64):
key = base64.b64decode(key_b64) # 16/24/32 bytes
try:
# Py2 cách cũ
return key.encode('hex')
except Exception:
# fallback portable
return binascii.b2a_hex(key)
def _key_b64_to_hex_and_cipher(key_b64):
"""
Base64 -> bytes -> (hex_key, cipher_name) theo độ dài key:
16B -> aes-128-ecb, 24B -> aes-192-ecb, 32B -> aes-256-ecb
"""
key = base64.b64decode(key_b64)
klen = len(key)
if klen == 16:
cipher = 'aes-128-ecb'
elif klen == 24:
cipher = 'aes-192-ecb'
elif klen == 32:
cipher = 'aes-256-ecb'
else:
raise RuntimeError("Độ dài key không hợp lệ: %d bytes (cần 16/24/32)" % klen)
# Py2: trả về hex dạng str
try:
hexkey = key.encode('hex')
except Exception:
hexkey = binascii.b2a_hex(key)
return hexkey, cipher
def run_bash(script_bytes):
"""Run bash script passed as BYTES via stdin; returns stdout bytes (Py2-safe)."""
if isinstance(script_bytes, unicode):
script_bytes = script_bytes.encode('utf-8')
p = subprocess.Popen("/bin/bash -s", shell=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate(script_bytes)
if p.returncode != 0:
# Ghi stderr vào cuối output để tiện debug nhưng không làm hỏng bytes
out = (out or b"") + b"\n===== STDERR =====\n" + (err or b"")
return out
ANSI_RE = re.compile(r'\x1b\[[0-9;]*[A-Za-z]')
def strip_ansi(s):
try:
# Py2: s có thể là bytes; cứ để bytes, regex vẫn xử được
return ANSI_RE.sub('', s)
except Exception:
return s
def safe_slug(s, maxlen=80):
# Chuyển sang ASCII-safe cho tên file: thay khoảng trắng/ký tự lạ bằng _
if isinstance(s, unicode):
s = s.encode('utf-8')
# bỏ ANSI, rồi thay ký tự không an toàn
s = strip_ansi(s)
s = re.sub(r'[^\w\.-]+', '_', s) # chỉ giữ a-zA-Z0-9_ . -
s = s.strip('_')
if len(s) > maxlen:
s = s[:maxlen]
return s
def extract_host_time(text):
"""
Tìm Hostname Time bằng regex, không phụ thuộc thứ tự dòng.
Kỳ vọng trong output dạng:
Hostname: myhost
Time: 2025-11-06 13:00:00
"""
t = strip_ansi(text)
# Tách dòng để tìm
lines = t.splitlines()
hostname_out, time_out = None, None
# Regex linh hoạt (bỏ qua hoa/thường, khoảng trắng)
re_host = re.compile(r'^\s*Hostname:\s*(\S+)\s*$', re.I)
re_time = re.compile(r'^\s*Time:\s*(.+?)\s*$', re.I)
for line in lines:
if hostname_out is None:
m = re_host.match(line)
if m:
hostname_out = m.group(1)
if time_out is None:
m = re_time.match(line)
if m:
time_out = m.group(1)
if hostname_out and time_out:
break
if not hostname_out:
# fallback an toàn
try:
hostname_out = socket.gethostname()
except Exception:
hostname_out = 'unknown-host'
if not time_out:
# fallback: now
try:
time_out = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
except Exception:
time_out = 'unknown-time'
# Chuẩn hoá
hostname_out = safe_slug(hostname_out, maxlen=80)
# format lại time sang safe filename
time_safe = time_out.replace('/', '-').replace('\\', '-').replace(':', '_').replace(' ', '-')
time_safe = safe_slug(time_safe, maxlen=80)
return hostname_out, time_safe
def run_audit(file_path=None):
# Banner
print(Fore.BLUE + """
_ _ _____ _____ _______ _ _ _____ _____ ______ _ _ _____ _ _ _____
/\\ | | | | __ \\_ _|__ __| | | | | /\\ | __ \\| __ \\| ____| \\ | |_ _| \\ | |/ ____|
/ \\ | | | | | | || | | | ______ | |__| | / \\ | |__) | | | | |__ | \\| | | | | \\| | | __
/ /\\ \\| | | | | | || | | | |______| | __ | / /\\ \\ | _ /| | | | __| | . ` | | | | . ` | | |_ |
/ ____ \\ |__| | |__| || |_ | | | | | |/ ____ \\| | \\ \\| |__| | |____| |\\ |_| |_| |\\ | |__| |
/_/ \\_\\____/|_____/_____| |_| |_| |_/_/ \\_\\_| \\_\\_____/|______|_| \\_|_____|_| \\_|\\_____|
""" + Fore.RESET)
print(Fore.RED + "Running Audit Hardening..." + Fore.RESET)
script_path = resolve_script_path(file_path)
if script_path is None:
_p(u"ERROR: No audit script found. Use -p <script.sh> or bundle the script.", getattr(Fore, 'RED', None))
return
_p(u" Script: %s" % script_path)
print(" [1/3] Reading script...")
with open(script_path, 'r') as f:
script_content = f.read()
content_u = script_content
script_parts = content_u.split(
"##################################################################################################################")
output = ""
for part in script_parts:
# Chuẩn hoá: part_bytes là bytes UTF-8; so sánh shebang ở dạng bytes
try:
unicode
if isinstance(part, unicode):
part_bytes = part.encode('utf-8')
else:
part_bytes = part
except NameError:
part_bytes = part # (không dùng trên Py3 ở đây)
if b"#!/bin/bash" not in part_bytes:
bash_src = b"#!/bin/bash\n" + part_bytes
else:
bash_src = part_bytes
out = run_bash(bash_src) # out là bytes
try:
output += out.decode('utf-8', 'ignore')
except Exception:
output += out # worst-case, giữ nguyên bytes
# Extract hostname/time lines from the produced output (keep logic as original)
hostname_out, time_generate = extract_host_time(output)
os_name_raw = detect_os_name()
os_name = safe_slug(os_name_raw, maxlen=60) # ASCII-safe
file_encrypt_name = '%s_%s_%s.txt.enc' % (hostname_out, os_name, time_generate)
enc_b64 = write_content(output)
with open(file_encrypt_name, 'wb') as f:
# enc_b64 is bytes in Py2
f.write(enc_b64)
if is_file_exist(file_encrypt_name):
_p(u"THÀNH CÔNG - FILE ENCRYPT %s" % file_encrypt_name, getattr(Fore, 'GREEN', None))
else:
_p(u"THẤT BẠI!!!", getattr(Fore, 'RED', None))
def run_ubuntu_audit(file_path=None):
old_file_path = '%s.txt' % hostname
if is_file_exist(old_file_path):
try:
os.remove(old_file_path)
except Exception:
pass
run_audit(file_path)
def parse_options():
if not OptionParser:
raise SystemExit("[ERROR] optparse not available. Please use Python 2.6/2.7.")
parser = OptionParser(usage="usage: %prog [-p PATH_TO_SCRIPT]")
parser.add_option("-p", "--path", dest="path",
help="Path to audit script (optional if bundled)", metavar="FILE", action="store", default=None)
(options, args) = parser.parse_args()
return options
if __name__ == '__main__':
import sys
opts = parse_options()
run_ubuntu_audit(opts.path)
File diff suppressed because it is too large Load Diff
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
@echo off
REM ============================================================
REM Build AuditTool.exe for Windows Server 2012+
REM Requires: Python 3.8+, pip
REM ============================================================
echo [1/3] Installing dependencies...
python -m pip install pycryptodome colorama unidecode pyinstaller
if %errorlevel% neq 0 (
echo ERROR: pip install failed. Check Python installation.
pause
exit /b 1
)
echo [2/3] Copying PowerShell audit script...
copy /Y ..\audit_check_script\audit_cis_windows.ps1 audit_cis_windows.ps1
if %errorlevel% neq 0 (
echo ERROR: audit_cis_windows.ps1 not found at ..\audit_check_script\
pause
exit /b 1
)
echo [3/3] Building AuditTool.exe with PyInstaller...
python -m PyInstaller --onefile --console --name AuditTool ^
--add-data "audit_cis_windows.ps1;." ^
--hidden-import Crypto.Cipher ^
--hidden-import Crypto.PublicKey ^
--hidden-import Crypto.Util.Padding ^
windows_audit.py
if %errorlevel% neq 0 (
echo ERROR: PyInstaller build failed
pause
exit /b 1
)
echo.
echo ========================================
echo Build complete!
echo Output: dist\AuditTool.exe
echo.
echo Deploy to Windows Server:
echo 1. Copy dist\AuditTool.exe to target server
echo 2. Copy keys\public_key.pem to same folder as AuditTool.exe
echo 3. Run: AuditTool.exe
echo ========================================
pause
+114
View File
@@ -0,0 +1,114 @@
#!/bin/bash
# ============================================================
# Build Linux audit binaries with PyInstaller
# Run this on the TARGET OS version:
# - Ubuntu binary → build on Ubuntu 20.04+
# - CentOS 7 binary → build on CentOS 7
# - CentOS 6 binary → build on CentOS 6 (Python 2.6+)
# - Oracle binary → build on Oracle Linux 7+
#
# Usage: bash build_all.sh [ubuntu|centos|oracle|centos6|all]
# ============================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
CHECK_SCRIPT_DIR="${PARENT_DIR}/audit_check_script"
DIST_DIR="${SCRIPT_DIR}/dist"
mkdir -p "${DIST_DIR}"
build_ubuntu() {
echo "=== Building Ubuntu Audit Tool ==="
cp "${CHECK_SCRIPT_DIR}/audit_cis_ubuntu_v202.sh" "${SCRIPT_DIR}/"
pip install pycryptodome cryptography colorama unidecode pyinstaller
pyinstaller --onefile --console --name ubuntu_audit \
--add-data "audit_cis_ubuntu_v202.sh:." \
--hidden-import colorama \
--hidden-import unidecode \
--hidden-import Crypto.Cipher \
--hidden-import Crypto.PublicKey \
--hidden-import Crypto.Util.Padding \
--hidden-import cryptography \
--hidden-import cryptography.hazmat.primitives.ciphers \
--hidden-import cryptography.hazmat.primitives.padding \
ubuntu_audit_v2.py
echo " -> ${DIST_DIR}/ubuntu_audit"
}
build_centos() {
echo "=== Building CentOS/RHEL Audit Tool ==="
cp "${CHECK_SCRIPT_DIR}/audit_cis_centos_v202.sh" "${SCRIPT_DIR}/"
pip install pycryptodome cryptography colorama unidecode pyinstaller
pyinstaller --onefile --console --name centos_rhel_audit \
--add-data "audit_cis_centos_v202.sh:." \
--hidden-import colorama \
--hidden-import unidecode \
--hidden-import Crypto.Cipher \
--hidden-import Crypto.PublicKey \
--hidden-import Crypto.Util.Padding \
--hidden-import cryptography \
--hidden-import cryptography.hazmat.primitives.ciphers \
--hidden-import cryptography.hazmat.primitives.padding \
centos_rhel_audit_v2.py
echo " -> ${DIST_DIR}/centos_rhel_audit"
}
build_oracle() {
echo "=== Building Oracle Linux Audit Tool ==="
cp "${CHECK_SCRIPT_DIR}/audit_cis_centos_v202.sh" "${SCRIPT_DIR}/"
pip install pycryptodome cryptography colorama unidecode pyinstaller
pyinstaller --onefile --console --name oracle_linux_audit \
--add-data "audit_cis_centos_v202.sh:." \
--hidden-import colorama \
--hidden-import unidecode \
--hidden-import Crypto.Cipher \
--hidden-import Crypto.PublicKey \
--hidden-import Crypto.Util.Padding \
--hidden-import cryptography \
--hidden-import cryptography.hazmat.primitives.ciphers \
--hidden-import cryptography.hazmat.primitives.padding \
oracle_linux_audit_v2.py
echo " -> ${DIST_DIR}/oracle_linux_audit"
}
build_centos6() {
echo "=== Building CentOS 6 Audit Tool ==="
cp "${CHECK_SCRIPT_DIR}/audit_cis_centos6.sh" "${SCRIPT_DIR}/"
pip install pyinstaller
pyinstaller --onefile --console --name centos6_audit \
--add-data "audit_cis_centos6.sh:." \
audit_centos6.py
echo " -> ${DIST_DIR}/centos6_audit"
}
build_all() {
build_ubuntu
build_centos
build_oracle
build_centos6
}
case "${1:-all}" in
ubuntu) build_ubuntu ;;
centos) build_centos ;;
oracle) build_oracle ;;
centos6) build_centos6 ;;
all) build_all ;;
*)
echo "Usage: bash build_all.sh [ubuntu|centos|oracle|centos6|all]"
exit 1
;;
esac
echo ""
echo "========================================"
echo "Build complete! Output: ${DIST_DIR}/"
echo ""
echo "Deploy to target server:"
echo " 1. Copy the binary from dist/"
echo " 2. Copy public_key.pem to same folder"
echo " 3. Run: ./<binary> (script is bundled, no -p needed)"
echo " Or: ./<binary> -p custom_script.sh"
echo "========================================"
+42
View File
@@ -0,0 +1,42 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec for CentOS 6 Audit Tool (Python 2.6+)
# Build: pyinstaller centos6_audit.spec
block_cipher = None
a = Analysis(
['audit_centos6.py'],
pathex=[],
binaries=[],
datas=[('audit_cis_centos6.sh', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='centos6_audit',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+48
View File
@@ -0,0 +1,48 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec for CentOS/RHEL Audit Tool
# Build: pyinstaller centos_rhel_audit.spec
block_cipher = None
a = Analysis(
['centos_rhel_audit_v2.py'],
pathex=[],
binaries=[],
datas=[('audit_cis_centos_v202.sh', '.')],
hiddenimports=[
'colorama',
'unidecode',
'Crypto', 'Crypto.Cipher', 'Crypto.PublicKey', 'Crypto.Util.Padding',
'cryptography', 'cryptography.hazmat', 'cryptography.hazmat.primitives',
'cryptography.hazmat.primitives.ciphers', 'cryptography.hazmat.primitives.padding',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='centos_rhel_audit',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+253
View File
@@ -0,0 +1,253 @@
import argparse
import base64
import os
import socket
import subprocess
import re
import sys
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from colorama import Fore
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
cwd = os.getcwd()
BUNDLED_SCRIPT = "audit_cis_centos_v202.sh"
def resource_path(relative_path):
if getattr(sys, "frozen", False):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path)
def resolve_script_path(user_path=None):
if user_path and os.path.isfile(user_path):
return os.path.abspath(user_path)
bundled = resource_path(BUNDLED_SCRIPT)
if os.path.isfile(bundled):
return bundled
same_dir = os.path.join(os.getcwd(), BUNDLED_SCRIPT)
if os.path.isfile(same_dir):
return same_dir
return None
def print_progress(current, total):
if total == 0:
return
bar_len = 40 # độ dài thanh
filled = int(bar_len * current / total)
bar = '' * filled + '-' * (bar_len - filled)
percent = int(current * 100 / total)
sys.stdout.write(f'\rĐang xử lý... [{bar}] {percent}%')
sys.stdout.flush()
# Khi xong hết thì xuống dòng mới cho đẹp
if current == total:
sys.stdout.write('\n')
sys.stdout.flush()
def get_os_tag():
"""Trả về nhãn OS dạng 'ubuntu_22_04' hoặc 'centos_7', ..."""
try:
if os.path.isfile("/etc/os-release"):
name = ""
version = ""
with open("/etc/os-release") as f:
for line in f:
if line.startswith("NAME=") and not name:
name = line.split("=", 1)[1].strip().strip('"').lower()
elif line.startswith("VERSION_ID=") and not version:
version = line.split("=", 1)[1].strip().strip('"').lower()
tag = f"{name}_{version}" if version else name
# chuẩn hoá: thay khoảng trắng và ký tự lạ
tag = re.sub(r"[^a-z0-9]+", "_", tag).strip("_")
if tag:
return tag
except Exception:
pass
try:
if os.path.isfile("/etc/redhat-release"):
txt = open("/etc/redhat-release").read().strip().lower()
# ví dụ: "centos linux release 7.9.2009 (core)"
# lấy vendor + major.minor
m = re.search(r"(centos|red hat|rhel|rocky|almalinux).*?release\s+([0-9]+(?:\.[0-9]+)?)", txt)
if m:
vendor = m.group(1).replace(" ", "")
ver = m.group(2).replace(".", "_")
return f"{vendor}_{ver}"
# fallback rút gọn
tag = re.sub(r"[^a-z0-9]+", "_", txt).strip("_")
if tag:
return tag
except Exception:
pass
try:
import platform
sysname = platform.system().lower()
release = platform.release().lower()
tag = f"{sysname}_{release}"
tag = re.sub(r"[^a-z0-9]+", "_", tag).strip("_")
return tag or "unknown_os"
except Exception:
return "unknown_os"
def write_content(content):
message = content.encode('utf-8')
aes_key = os.urandom(32)
iv = os.urandom(16)
padder = padding.PKCS7(128).padder()
padded_data = padder.update(message) + padder.finalize()
cipher_aes = Cipher(algorithms.AES(aes_key), modes.CBC(iv))
encryptor = cipher_aes.encryptor()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
public_key = RSA.import_key(open('public_key.pem').read())
cipher_rsa = PKCS1_OAEP.new(public_key)
enc_key = cipher_rsa.encrypt(aes_key)
b64_enc_key = base64.b64encode(enc_key).decode('utf-8')
b64_iv = base64.b64encode(iv).decode('utf-8')
b64_ct = base64.b64encode(ciphertext).decode('utf-8')
return f"HYBRID_V1:{b64_enc_key}:{b64_iv}:{b64_ct}"
def is_file_exist(path):
isFile = os.path.isfile(path)
if isFile:
return True
else:
return False
def run_bash(command):
process = subprocess.Popen(
['/bin/bash', '-c', command],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
rc = process.returncode
out = stdout.decode(errors="ignore")
err = stderr.decode(errors="ignore")
# Luôn luôn ghép stderr (nếu có) vào log để không mất thông tin
if err.strip():
out += "\n########## STDERR BEGIN ##########\n"
out += err
out += "\n########## STDERR END ##########\n"
# Trả về tuple: (output, stderr, return_code)
return out, err, rc
def run_audit(file_path):
print(Fore.BLUE + """
_ _ _____ _____ _______ _ _ _____ _____ ______ _ _ _____ _ _ _____
/\ | | | | __ \_ _|__ __| | | | | /\ | __ \| __ \| ____| \ | |_ _| \ | |/ ____|
/ \ | | | | | | || | | | ______ | |__| | / \ | |__) | | | | |__ | \| | | | | \| | | __
/ /\ \| | | | | | || | | | |______| | __ | / /\ \ | _ /| | | | __| | . ` | | | | . ` | | |_ |
/ ____ \ |__| | |__| || |_ | | | | | |/ ____ \| | \ \| |__| | |____| |\ |_| |_| |\ | |__| |
/_/ \_\____/|_____/_____| |_| |_| |_/_/ \_\_| \_\_____/|______|_| \_|_____|_| \_|\_____|
""" + Fore.RESET)
print(Fore.RED + "Running Audit Hardening..." + Fore.RESET)
script_path = resolve_script_path(file_path)
if script_path is None:
print(Fore.RED + "ERROR: No audit script found. Use -p <script.sh> or bundle the script." + Fore.RESET)
return
print(f" Script: {script_path}")
print(" [1/3] Reading script...")
with open(script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
script = script_content.split(
"##################################################################################################################")
# Lọc bỏ các block rỗng trước
script_blocks = [block.strip() for block in script if block.strip()]
total_blocks = len(script_blocks)
output = ""
errors = [] # Lưu lỗi để hiển thị sau khi loading xong
for idx, i in enumerate(script_blocks, 1):
# Hiển thị progress bar
print_progress(idx, total_blocks)
if "#!/bin/bash" not in i:
result, err, rc = run_bash("#!/bin/bash\n{0}".format(i))
else:
result, err, rc = run_bash(i)
# Lưu lỗi nếu có (exit code != 0)
if rc != 0 and err.strip():
errors.append(f"[Block {idx}] {err.strip().split(chr(10))[0]}")
# Nếu lệnh lỗi và run_bash trả về None thì bỏ qua
if result is None:
continue
output += result
# Hiển thị các lỗi sau khi loading xong
if errors:
print(Fore.YELLOW + f"\n⚠ Có {len(errors)} cảnh báo:" + Fore.RESET)
for e in errors:
print(Fore.YELLOW + f"{e}" + Fore.RESET)
# Dùng regex để tìm Hostname và Audit Time trong output
hostname_match = re.search(r"Hostname:\s*(\S+)", output)
time_match = re.search(r"Audit Time:\s*(.+)", output)
hostname = hostname_match.group(1) if hostname_match else "unknown_host"
time_generate = time_match.group(1).strip().replace("-", "_").replace(":", "_").replace(" ", "-") if time_match else "unknown_time"
os_tag = get_os_tag()
file_encrypt_name = f"{hostname}_{os_tag}_{time_generate}.txt.enc"
# file_encrypt_name = '{}_{}.txt.enc'.format(hostname, time_generate)
encrypt_result = write_content(output)
with open(file_encrypt_name, 'w') as f:
f.write(encrypt_result)
if is_file_exist(file_encrypt_name):
print(Fore.GREEN + "THÀNH CÔNG - FILE ENCRYPT {}".format(file_encrypt_name) + Fore.RESET)
else:
print(Fore.RED + "THẤT BẠI RỒI THỬ LẠI NHÁ !!!" + Fore.RESET)
def run_ubuntu_audit(file_path=None):
old_file_path = '{}.txt'.format(hostname)
old_file = is_file_exist(old_file_path)
if old_file:
os.remove(old_file_path)
run_audit(file_path)
def main():
# Parse Arguments
parser = argparse.ArgumentParser(description='Audit Hardening')
parser.add_argument('-p', '--path', help='Path to audit script (optional if bundled)', default=None)
args = parser.parse_args()
return args
if __name__ == '__main__':
args = main()
run_ubuntu_audit(args.path)
+48
View File
@@ -0,0 +1,48 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec for Oracle Linux Audit Tool
# Build: pyinstaller oracle_linux_audit.spec
block_cipher = None
a = Analysis(
['oracle_linux_audit_v2.py'],
pathex=[],
binaries=[],
datas=[('audit_cis_centos_v202.sh', '.')],
hiddenimports=[
'colorama',
'unidecode',
'Crypto', 'Crypto.Cipher', 'Crypto.PublicKey', 'Crypto.Util.Padding',
'cryptography', 'cryptography.hazmat', 'cryptography.hazmat.primitives',
'cryptography.hazmat.primitives.ciphers', 'cryptography.hazmat.primitives.padding',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='oracle_linux_audit',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+272
View File
@@ -0,0 +1,272 @@
import argparse
import base64
import os
import socket
import subprocess
import re
import sys
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from colorama import Fore
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
cwd = os.getcwd()
BUNDLED_SCRIPT = "audit_cis_centos_v202.sh"
def resource_path(relative_path):
if getattr(sys, "frozen", False):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path)
def resolve_script_path(user_path=None):
if user_path and os.path.isfile(user_path):
return os.path.abspath(user_path)
bundled = resource_path(BUNDLED_SCRIPT)
if os.path.isfile(bundled):
return bundled
same_dir = os.path.join(os.getcwd(), BUNDLED_SCRIPT)
if os.path.isfile(same_dir):
return same_dir
return None
def print_progress(current, total):
if total == 0:
return
bar_len = 40 # độ dài thanh
filled = int(bar_len * current / total)
bar = '' * filled + '-' * (bar_len - filled)
percent = int(current * 100 / total)
sys.stdout.write(f'\rĐang xử lý... [{bar}] {percent}%')
sys.stdout.flush()
# Khi xong hết thì xuống dòng mới cho đẹp
if current == total:
sys.stdout.write('\n')
sys.stdout.flush()
def get_os_tag():
"""
Trả về nhãn OS dạng 'oracle_linux_8_9', 'rhel_7', 'centos_7_9', 'ubuntu_22_04', ...
Ưu tiên /etc/os-release; fallback /etc/oracle-release hoặc /etc/redhat-release; cuối cùng uname.
"""
# 1) /etc/os-release (chuẩn mới trên hầu hết distro)
try:
if os.path.isfile("/etc/os-release"):
name = ""
version = ""
with open("/etc/os-release") as f:
for line in f:
if line.startswith("NAME=") and not name:
name = line.split("=", 1)[1].strip().strip('"').lower()
elif line.startswith("VERSION_ID=") and not version:
version = line.split("=", 1)[1].strip().strip('"').lower()
tag = f"{name}_{version}" if version else name
tag = re.sub(r"[^a-z0-9]+", "_", tag).strip("_")
if tag:
return tag
except Exception:
pass
# 2) Oracle Linux đời cũ
try:
if os.path.isfile("/etc/oracle-release"):
txt = open("/etc/oracle-release").read().strip().lower()
# ví dụ: "oracle linux server release 8.9"
m = re.search(r"(oracle)\s+linux.*?release\s+([0-9]+(?:\.[0-9]+)?)", txt)
if m:
vendor = "oracle_linux"
ver = m.group(2).replace(".", "_")
return f"{vendor}_{ver}"
tag = re.sub(r"[^a-z0-9]+", "_", txt).strip("_")
if tag:
return tag
except Exception:
pass
# 3) RHEL/CentOS/Alma/Rocky đời cũ
try:
if os.path.isfile("/etc/redhat-release"):
txt = open("/etc/redhat-release").read().strip().lower()
# ví dụ: "centos linux release 7.9.2009 (core)"
m = re.search(r"(centos|red hat|rhel|rocky|almalinux).*?release\s+([0-9]+(?:\.[0-9]+)?)", txt)
if m:
vendor = m.group(1).replace(" ", "")
ver = m.group(2).replace(".", "_")
return f"{vendor}_{ver}"
tag = re.sub(r"[^a-z0-9]+", "_", txt).strip("_")
if tag:
return tag
except Exception:
pass
# 4) uname (fallback cuối)
try:
import platform
sysname = platform.system().lower()
release = platform.release().lower()
tag = re.sub(r"[^a-z0-9]+", "_", f"{sysname}_{release}").strip("_")
return tag or "unknown_os"
except Exception:
return "unknown_os"
def write_content(content):
message = content.encode('utf-8')
aes_key = os.urandom(32)
iv = os.urandom(16)
padder = padding.PKCS7(128).padder()
padded_data = padder.update(message) + padder.finalize()
cipher_aes = Cipher(algorithms.AES(aes_key), modes.CBC(iv))
encryptor = cipher_aes.encryptor()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
public_key = RSA.import_key(open('public_key.pem').read())
cipher_rsa = PKCS1_OAEP.new(public_key)
enc_key = cipher_rsa.encrypt(aes_key)
b64_enc_key = base64.b64encode(enc_key).decode('utf-8')
b64_iv = base64.b64encode(iv).decode('utf-8')
b64_ct = base64.b64encode(ciphertext).decode('utf-8')
return f"HYBRID_V1:{b64_enc_key}:{b64_iv}:{b64_ct}"
def is_file_exist(path):
isFile = os.path.isfile(path)
if isFile:
return True
else:
return False
def run_bash(command):
process = subprocess.Popen(
['/bin/bash', '-c', command],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
rc = process.returncode
out = stdout.decode(errors="ignore")
err = stderr.decode(errors="ignore")
# Luôn luôn ghép stderr (nếu có) vào log để không mất thông tin
if err.strip():
out += "\n########## STDERR BEGIN ##########\n"
out += err
out += "\n########## STDERR END ##########\n"
# Trả về tuple: (output, stderr, return_code)
return out, err, rc
def run_audit(file_path=None):
print(Fore.BLUE + """
_ _ _____ _____ _______ _ _ _____ _____ ______ _ _ _____ _ _ _____
/\ | | | | __ \_ _|__ __| | | | | /\ | __ \| __ \| ____| \ | |_ _| \ | |/ ____|
/ \ | | | | | | || | | | ______ | |__| | / \ | |__) | | | | |__ | \| | | | | \| | | __
/ /\ \| | | | | | || | | | |______| | __ | / /\ \ | _ /| | | | __| | . ` | | | | . ` | | |_ |
/ ____ \ |__| | |__| || |_ | | | | | |/ ____ \| | \ \| |__| | |____| |\ |_| |_| |\ | |__| |
/_/ \_\____/|_____/_____| |_| |_| |_/_/ \_\_| \_\_____/|______|_| \_|_____|_| \_|\_____|
""" + Fore.RESET)
print(Fore.RED + "Running Audit Hardening..." + Fore.RESET)
script_path = resolve_script_path(file_path)
if script_path is None:
print(Fore.RED + "ERROR: No audit script found. Use -p <script.sh> or bundle the script." + Fore.RESET)
return
print(f" Script: {script_path}")
print(" [1/3] Reading script...")
with open(script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
script = script_content.split(
"##################################################################################################################")
# Lọc bỏ các block rỗng trước
script_blocks = [block.strip() for block in script if block.strip()]
total_blocks = len(script_blocks)
output = ""
errors = [] # Lưu lỗi để hiển thị sau khi loading xong
for idx, i in enumerate(script_blocks, 1):
# Hiển thị progress bar
print_progress(idx, total_blocks)
if "#!/bin/bash" not in i:
result, err, rc = run_bash("#!/bin/bash\n{0}".format(i))
else:
result, err, rc = run_bash(i)
# Lưu lỗi nếu có (exit code != 0)
if rc != 0 and err.strip():
errors.append(f"[Block {idx}] {err.strip().split(chr(10))[0]}")
# Nếu lệnh lỗi và run_bash trả về None thì bỏ qua
if result is None:
continue
output += result
# Hiển thị các lỗi sau khi loading xong
if errors:
print(Fore.YELLOW + f"\n⚠ Có {len(errors)} cảnh báo:" + Fore.RESET)
for e in errors:
print(Fore.YELLOW + f"{e}" + Fore.RESET)
# Dùng regex để tìm Hostname và Audit Time trong output
hostname_match = re.search(r"Hostname:\s*(\S+)", output)
time_match = re.search(r"Audit Time:\s*(.+)", output)
hostname = hostname_match.group(1) if hostname_match else "unknown_host"
time_generate = time_match.group(1).strip().replace("-", "_").replace(":", "_").replace(" ", "-") if time_match else "unknown_time"
os_tag = get_os_tag()
file_encrypt_name = f"{hostname}_{os_tag}_{time_generate}.txt.enc"
# file_encrypt_name = '{}_{}.txt.enc'.format(hostname, time_generate)
encrypt_result = write_content(output)
with open(file_encrypt_name, 'w') as f:
f.write(encrypt_result)
if is_file_exist(file_encrypt_name):
print(Fore.GREEN + "THÀNH CÔNG - FILE ENCRYPT {}".format(file_encrypt_name) + Fore.RESET)
else:
print(Fore.RED + "THẤT BẠI RỒI THỬ LẠI NHÁ !!!" + Fore.RESET)
def run_os_audit(file_path=None):
old_file_path = '{}.txt'.format(hostname)
old_file = is_file_exist(old_file_path)
if old_file:
os.remove(old_file_path)
run_audit(file_path)
def main():
# Parse Arguments
parser = argparse.ArgumentParser(description='Audit Hardening')
parser.add_argument('-p', '--path', help='Path to audit script (optional if bundled)', default=None)
args = parser.parse_args()
return args
if __name__ == '__main__':
args = main()
run_os_audit(args.path)
+12
View File
@@ -0,0 +1,12 @@
# Windows Audit Python Dependencies
# Target: Python 3.8 (Windows Server 2012 compatible)
#
# Setup with conda:
# conda create -n audit python=3.8 -y
# conda activate audit
# pip install -r requirements.txt
pycryptodome>=3.15,<4
colorama>=0.4
unidecode>=1.3
pyinstaller>=5.0,<6
+48
View File
@@ -0,0 +1,48 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec for Ubuntu Audit Tool
# Build: pyinstaller ubuntu_audit.spec
block_cipher = None
a = Analysis(
['ubuntu_audit_v2.py'],
pathex=[],
binaries=[],
datas=[('audit_cis_ubuntu_v202.sh', '.')],
hiddenimports=[
'colorama',
'unidecode',
'Crypto', 'Crypto.Cipher', 'Crypto.PublicKey', 'Crypto.Util.Padding',
'cryptography', 'cryptography.hazmat', 'cryptography.hazmat.primitives',
'cryptography.hazmat.primitives.ciphers', 'cryptography.hazmat.primitives.padding',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='ubuntu_audit',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+252
View File
@@ -0,0 +1,252 @@
import argparse
import base64
import os
import socket
import subprocess
import re
import sys
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from colorama import Fore
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
cwd = os.getcwd()
BUNDLED_SCRIPT = "audit_cis_ubuntu_v202.sh"
def resource_path(relative_path):
if getattr(sys, "frozen", False):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path)
def resolve_script_path(user_path=None):
if user_path and os.path.isfile(user_path):
return os.path.abspath(user_path)
bundled = resource_path(BUNDLED_SCRIPT)
if os.path.isfile(bundled):
return bundled
same_dir = os.path.join(os.getcwd(), BUNDLED_SCRIPT)
if os.path.isfile(same_dir):
return same_dir
return None
def print_progress(current, total):
if total == 0:
return
bar_len = 40 # độ dài thanh
filled = int(bar_len * current / total)
bar = '' * filled + '-' * (bar_len - filled)
percent = int(current * 100 / total)
sys.stdout.write(f'\rĐang xử lý... [{bar}] {percent}%')
sys.stdout.flush()
# Khi xong hết thì xuống dòng mới cho đẹp
if current == total:
sys.stdout.write('\n')
sys.stdout.flush()
def get_os_tag():
"""Trả về nhãn OS dạng 'ubuntu_22_04' hoặc 'centos_7', ..."""
try:
if os.path.isfile("/etc/os-release"):
name = ""
version = ""
with open("/etc/os-release") as f:
for line in f:
if line.startswith("NAME=") and not name:
name = line.split("=", 1)[1].strip().strip('"').lower()
elif line.startswith("VERSION_ID=") and not version:
version = line.split("=", 1)[1].strip().strip('"').lower()
tag = f"{name}_{version}" if version else name
# chuẩn hoá: thay khoảng trắng và ký tự lạ
tag = re.sub(r"[^a-z0-9]+", "_", tag).strip("_")
if tag:
return tag
except Exception:
pass
try:
if os.path.isfile("/etc/redhat-release"):
txt = open("/etc/redhat-release").read().strip().lower()
# ví dụ: "centos linux release 7.9.2009 (core)"
# lấy vendor + major.minor
m = re.search(r"(centos|red hat|rhel|rocky|almalinux).*?release\s+([0-9]+(?:\.[0-9]+)?)", txt)
if m:
vendor = m.group(1).replace(" ", "")
ver = m.group(2).replace(".", "_")
return f"{vendor}_{ver}"
# fallback rút gọn
tag = re.sub(r"[^a-z0-9]+", "_", txt).strip("_")
if tag:
return tag
except Exception:
pass
try:
import platform
sysname = platform.system().lower()
release = platform.release().lower()
tag = f"{sysname}_{release}"
tag = re.sub(r"[^a-z0-9]+", "_", tag).strip("_")
return tag or "unknown_os"
except Exception:
return "unknown_os"
def write_content(content):
message = content.encode('utf-8')
aes_key = os.urandom(32)
iv = os.urandom(16)
padder = padding.PKCS7(128).padder()
padded_data = padder.update(message) + padder.finalize()
cipher_aes = Cipher(algorithms.AES(aes_key), modes.CBC(iv))
encryptor = cipher_aes.encryptor()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
public_key = RSA.import_key(open('public_key.pem').read())
cipher_rsa = PKCS1_OAEP.new(public_key)
enc_key = cipher_rsa.encrypt(aes_key)
b64_enc_key = base64.b64encode(enc_key).decode('utf-8')
b64_iv = base64.b64encode(iv).decode('utf-8')
b64_ct = base64.b64encode(ciphertext).decode('utf-8')
return f"HYBRID_V1:{b64_enc_key}:{b64_iv}:{b64_ct}"
def is_file_exist(path):
isFile = os.path.isfile(path)
if isFile:
return True
else:
return False
def run_bash(command):
process = subprocess.Popen(
['/bin/bash', '-c', command],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate()
rc = process.returncode
out = stdout.decode(errors="ignore")
err = stderr.decode(errors="ignore")
# Luôn luôn ghép stderr (nếu có) vào log để không mất thông tin
if err.strip():
out += "\n########## STDERR BEGIN ##########\n"
out += err
out += "\n########## STDERR END ##########\n"
# Trả về tuple: (output, stderr, return_code)
return out, err, rc
def run_audit(file_path=None):
print(Fore.BLUE + """
_ _ _____ _____ _______ _ _ _____ _____ ______ _ _ _____ _ _ _____
/\ | | | | __ \_ _|__ __| | | | | /\ | __ \| __ \| ____| \ | |_ _| \ | |/ ____|
/ \ | | | | | | || | | | ______ | |__| | / \ | |__) | | | | |__ | \| | | | | \| | | __
/ /\ \| | | | | | || | | | |______| | __ | / /\ \ | _ /| | | | __| | . ` | | | | . ` | | |_ |
/ ____ \ |__| | |__| || |_ | | | | | |/ ____ \| | \ \| |__| | |____| |\ |_| |_| |\ | |__| |
/_/ \_\____/|_____/_____| |_| |_| |_/_/ \_\_| \_\_____/|______|_| \_|_____|_| \_|\_____|
""" + Fore.RESET)
print(Fore.RED + "Running Audit Hardening..." + Fore.RESET)
script_path = resolve_script_path(file_path)
if script_path is None:
print(Fore.RED + "ERROR: No audit script found. Use -p <script.sh> or bundle the script." + Fore.RESET)
return
print(f" Script: {script_path}")
print(" [1/3] Reading script...")
with open(script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
script = script_content.split(
"##################################################################################################################")
# Lọc bỏ các block rỗng trước
script_blocks = [block.strip() for block in script if block.strip()]
total_blocks = len(script_blocks)
output = ""
errors = [] # Lưu lỗi để hiển thị sau khi loading xong
for idx, i in enumerate(script_blocks, 1):
# Hiển thị progress bar
print_progress(idx, total_blocks)
if "#!/bin/bash" not in i:
result, err, rc = run_bash("#!/bin/bash\n{0}".format(i))
else:
result, err, rc = run_bash(i)
# Lưu lỗi nếu có (exit code != 0)
if rc != 0 and err.strip():
errors.append(f"[Block {idx}] {err.strip().split(chr(10))[0]}")
# Nếu lệnh lỗi và run_bash trả về None thì bỏ qua
if result is None:
continue
output += result
# Hiển thị các lỗi sau khi loading xong
if errors:
print(Fore.YELLOW + f"\n⚠ Có {len(errors)} cảnh báo:" + Fore.RESET)
for e in errors:
print(Fore.YELLOW + f"{e}" + Fore.RESET)
# Dùng regex để tìm Hostname và Audit Time trong output
hostname_match = re.search(r"Hostname:\s*(\S+)", output)
time_match = re.search(r"Audit Time:\s*(.+)", output)
hostname = hostname_match.group(1) if hostname_match else "unknown_host"
time_generate = time_match.group(1).strip().replace("-", "_").replace(":", "_").replace(" ", "-") if time_match else "unknown_time"
os_tag = get_os_tag()
file_encrypt_name = f"{hostname}_{os_tag}_{time_generate}.txt.enc"
# file_encrypt_name = '{}_{}.txt.enc'.format(hostname, time_generate)
encrypt_result = write_content(output)
with open(file_encrypt_name, 'w') as f:
f.write(encrypt_result)
if is_file_exist(file_encrypt_name):
print(Fore.GREEN + "THÀNH CÔNG - FILE ENCRYPT {}".format(file_encrypt_name) + Fore.RESET)
else:
print(Fore.RED + "THẤT BẠI RỒI THỬ LẠI NHÁ !!!" + Fore.RESET)
def run_ubuntu_audit(file_path=None):
old_file_path = '{}.txt'.format(hostname)
old_file = is_file_exist(old_file_path)
if old_file:
os.remove(old_file_path)
run_audit(file_path)
def main():
parser = argparse.ArgumentParser(description='Audit Hardening')
parser.add_argument('-p', '--path', help='Path to audit script (optional if bundled)', default=None)
args = parser.parse_args()
return args
if __name__ == '__main__':
args = main()
run_ubuntu_audit(args.path)
+286
View File
@@ -0,0 +1,286 @@
"""
Windows Audit Hardening Tool - v2.0
Usage: AuditTool.exe -p audit_cis_windows.ps1
AuditTool.exe (uses bundled .ps1 file)
Build: python -m PyInstaller --onefile --console -n AuditTool ^
--add-data "audit_cis_windows.ps1;." ^
windows_audit.py
Environment: Python 3.8+ (3.8 for Windows Server 2012 compatibility)
"""
import argparse
import base64
import os
import socket
import subprocess
import sys
import tempfile
import traceback
from Crypto.Cipher import PKCS1_OAEP, AES
from Crypto.PublicKey import RSA
from Crypto.Util.Padding import pad
from colorama import Fore, init as colorama_init
from unidecode import unidecode
# ----------------------------------------------------------
# Globals
# ----------------------------------------------------------
colorama_init(strip=False, autoreset=True)
HOSTNAME = socket.gethostname()
try:
IP_ADDR = socket.gethostbyname(HOSTNAME)
except Exception:
IP_ADDR = "127.0.0.1"
BUNDLED_SCRIPT = "audit_cis_windows.ps1"
PUBLIC_KEY_FILE = "public_key.pem"
BANNER = r"""
_ _ _____ _____ _______ _ _ _____ _____ ______ _ _ _____ _ _ _____
/\ | | | | __ \_ _|__ __| | | | | /\ | __ \| __ \| ____| \ | |_ _| \ | |/ ____|
/ \ | | | | | | || | | | ______ | |__| | / \ | |__) | | | | |__ | \| | | | | \| | | __
/ /\ \| | | | | | || | | | |______| | __ | / /\ \ | _ /| | | | __| | . ` | | | | . ` | | |_ |
/ ____ \ |__| | |__| || |_ | | | | | |/ ____ \| | \ \| |__| | |____| |\ |_| |_| |\ | |__| |
/_/ \_\____/|_____/_____| |_| |_| |_/_/ \_\_| \_\_____/|______|_| \_|_____|_| \_|\_____|
"""
# ----------------------------------------------------------
# Path resolution (supports PyInstaller bundle)
# ----------------------------------------------------------
def resource_path(relative_path):
"""Get absolute path to resource, works for dev and PyInstaller."""
if getattr(sys, "frozen", False):
base = sys._MEIPASS
else:
base = os.path.dirname(os.path.abspath(__file__))
return os.path.join(base, relative_path)
def resolve_script_path(user_path=None):
"""
Resolve the .ps1 script path.
Priority: user-supplied arg > bundled file > same-dir file.
Returns absolute path or None.
"""
if user_path:
if os.path.isfile(user_path):
return os.path.abspath(user_path)
print(Fore.YELLOW + "[WARNING] Provided path not found: {}".format(user_path) + Fore.RESET)
# Try PyInstaller bundled location
bundled = resource_path(BUNDLED_SCRIPT)
if os.path.isfile(bundled):
return bundled
# Try same directory
same_dir = os.path.join(os.getcwd(), BUNDLED_SCRIPT)
if os.path.isfile(same_dir):
return same_dir
return None
def resolve_public_key():
"""Find public_key.pem - bundled, same dir, or current dir."""
for loc in [
resource_path(PUBLIC_KEY_FILE),
os.path.join(os.getcwd(), PUBLIC_KEY_FILE),
]:
if os.path.isfile(loc):
return loc
return None
# ----------------------------------------------------------
# Crypto helpers
# ----------------------------------------------------------
def encrypt_output_rsa(content):
"""Encrypt output with Hybrid AES-256-CBC + RSA (HYBRID_V1 format)."""
pk_path = resolve_public_key()
if pk_path is None:
return "PLAINTEXT:" + content
try:
raw = content.encode("utf-8")
aes_key = os.urandom(32)
iv = os.urandom(16)
padded = pad(raw, AES.block_size, style="pkcs7")
cipher_aes = AES.new(aes_key, AES.MODE_CBC, iv)
ciphertext = cipher_aes.encrypt(padded)
pub_key = RSA.import_key(open(pk_path, "rb").read())
cipher_rsa = PKCS1_OAEP.new(pub_key)
enc_key = cipher_rsa.encrypt(aes_key)
b64_enc_key = base64.b64encode(enc_key).decode("utf-8")
b64_iv = base64.b64encode(iv).decode("utf-8")
b64_ct = base64.b64encode(ciphertext).decode("utf-8")
return f"HYBRID_V1:{b64_enc_key}:{b64_iv}:{b64_ct}"
except Exception as e:
print(Fore.YELLOW + "[WARNING] RSA encrypt failed: {}".format(e) + Fore.RESET)
return "PLAINTEXT:" + content
# ----------------------------------------------------------
# PowerShell runner
# ----------------------------------------------------------
def run_powershell_script(script_content, timeout_sec=600):
"""
Write script to temp .ps1 file, execute via 'powershell -File',
return (stdout, stderr, returncode).
Handles PowerShell's UTF-16LE output encoding correctly.
"""
tmp_path = None
try:
fd, tmp_path = tempfile.mkstemp(suffix=".ps1", prefix="audit_")
with os.fdopen(fd, "w", encoding="utf-8-sig") as fh:
fh.write(script_content)
proc = subprocess.run(
[
"powershell.exe",
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-File", tmp_path,
],
capture_output=True,
timeout=timeout_sec,
)
# PowerShell outputs UTF-16LE by default
stdout = proc.stdout.decode("utf-16-le", errors="replace") if proc.stdout else ""
stderr = proc.stderr.decode("utf-16-le", errors="replace") if proc.stderr else ""
return stdout, stderr, proc.returncode
except subprocess.TimeoutExpired:
return "", "PowerShell execution timed out ({}s)".format(timeout_sec), -1
except Exception:
return "", traceback.format_exc(), -1
finally:
if tmp_path and os.path.exists(tmp_path):
try:
os.remove(tmp_path)
except Exception:
pass
# ----------------------------------------------------------
# Output parsing
# ----------------------------------------------------------
def extract_audit_info(output):
"""Extract hostname + timestamp from audit output lines."""
hostname = HOSTNAME
timestamp = "unknown"
for line in output.splitlines():
if line.startswith("Hostname:"):
val = line.replace("Hostname:", "").strip()
hostname = val if val else HOSTNAME
elif line.startswith("Time:"):
val = line.replace("Time:", "").strip()
timestamp = val.replace("-", "_").replace(":", "_").replace(" ", "-") if val else "unknown"
return hostname, timestamp
def count_pass_fail(output):
"""Count PASSED/FAILED from JSON lines."""
passed = failed = 0
for line in output.splitlines():
line = line.strip()
if line.startswith("{") and line.endswith("}"):
if '"PASSED"' in line or "'PASSED'" in line:
passed += 1
elif '"FAILED"' in line or "'FAILED'" in line:
failed += 1
return passed, failed
# ----------------------------------------------------------
# Main audit flow
# ----------------------------------------------------------
def run_audit(script_path=None):
"""Read .ps1, run PowerShell audit, encrypt+save results."""
print(Fore.BLUE + BANNER + Fore.RESET)
print(Fore.RED + "Running Audit Hardening v2.0" + Fore.RESET)
print(" Hostname : {}".format(HOSTNAME))
print(" IP : {}".format(IP_ADDR))
print("-" * 70)
# Step 0 Resolve input script
script_path = resolve_script_path(script_path)
if script_path is None:
print(Fore.RED + "ERROR: No .ps1 file found.")
print(" Provide path: AuditTool.exe -p audit_cis_windows.ps1")
print(" Or place {} in the same directory.".format(BUNDLED_SCRIPT) + Fore.RESET)
return
print(" Source : {}".format(script_path))
# Step 1 Read PowerShell script
print(" [1/4] Reading script...")
try:
with open(script_path, "r", encoding="utf-8") as fh:
ps_content = fh.read()
except Exception as e:
print(Fore.RED + " FAILED: {}".format(e) + Fore.RESET)
return
print(" [1/4] OK - {} bytes".format(len(ps_content)))
# Step 2 Execute PowerShell
print(" [2/4] Running PowerShell...")
stdout, stderr, rc = run_powershell_script(ps_content)
if rc != 0:
print(Fore.YELLOW + " [2/4] PowerShell rc={}: {}".format(rc, (stderr or "")[:200]) + Fore.RESET)
else:
print(" [2/4] OK - {} output lines".format(len(stdout.splitlines())))
# Step 3 Combine
full_output = stdout
if stderr:
full_output += "\n[STDERR]\n" + stderr
if not full_output.strip():
print(Fore.RED + "ERROR: No output from PowerShell" + Fore.RESET)
return
passed, failed = count_pass_fail(full_output)
print(" [3/4] Audit: {} PASSED / {} FAILED".format(passed, failed))
# Step 4 Encrypt & save
hostname_out, timestamp = extract_audit_info(stdout)
out_filename = "{}_{}.txt.enc".format(hostname_out, timestamp)
print(" [4/4] Encrypting -> {}".format(out_filename))
encrypted = encrypt_output_rsa(full_output)
with open(out_filename, "w", encoding="utf-8") as fh:
fh.write(encrypted)
if os.path.isfile(out_filename):
print(Fore.GREEN + "=" * 70 + Fore.RESET)
print(Fore.GREEN + " SUCCESS: {} | {} PASS / {} FAIL".format(
out_filename, passed, failed) + Fore.RESET)
print(Fore.GREEN + "=" * 70 + Fore.RESET)
else:
print(Fore.RED + " FAILED: Could not write output file" + Fore.RESET)
# ----------------------------------------------------------
# CLI
# ----------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="Audit Hardening v2.0")
parser.add_argument(
"-p", "--path",
help="Path to PowerShell .ps1 script (optional if bundled or in same dir)",
default=None,
)
return parser.parse_args()
if __name__ == "__main__":
args = main()
run_audit(args.path)
+1
View File
@@ -0,0 +1 @@
parent{% endif %}'">👥 Qu?n lý Ngu?i dùng<
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+595
View File
@@ -0,0 +1,595 @@
{
"data": [
{
"4": "1. Thiết lập ban đầu"
},
{
"5": "1.1. Cấu hình filesystem"
},
{
"6": "1.1.1. Cấu hình vô hiệu hoá các filesystem không sử dụng"
},
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.1.8. Cấu hình vô hiệu hoá usb-storage filesystem"
},
{
"15": "1.1.2. Cấu hình phân vùng /tmp"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"19": "1.1.3. Cấu hình phân vùng /var/tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"23": "1.1.4. Cấu hình phân vùng /home"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"26": "1.1.5. Cấu hình phân vùng /dev/shm"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"30": "1.2. Cấu hình cập nhật phần mềm"
},
{
"31": "1.2.1. Cấu hình kích hoạt gpgcheck"
},
{
"32": "1.3. Kiểm tra tính toàn vẹn của filesystem"
},
{
"33": "1.3.1. Kiểm tra cài đặt AIDE"
},
{
"34": "1.3.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"35": "1.4. Cấu hình khởi động an toàn"
},
{
"36": "1.4.1. Phân quyền đối với file cấu hình bootloader"
},
{
"37": "1.4.2. Cấu hình xác thực khi truy cập rescue mode"
},
{
"38": "1.4.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"39": "1.4.4. Cấu hình vô hiệu hoá interactive boot"
},
{
"40": "1.5. Additional Process Hardening"
},
{
"41": "1.5.1. Cấu hình vô hiệu hoá core dump"
},
{
"42": "1.5.2. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"43": "1.5.3. Cấu hình vô hiệu hoá prelink"
},
{
"44": "1.6. Kiểm soát nội dung cảnh báo"
},
{
"45": "1.6.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"46": "1.6.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"47": "1.6.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"48": "1.6.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"49": "1.6.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"50": "1.6.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"51": "1.6.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"52": "2. Service"
},
{
"53": "2.1. Cấu hình Time Synchronization"
},
{
"54": "2.1.1. Cấu hình sử dụng chrony"
},
{
"55": "2.1.2. Cấu hình sử dụng NTP"
},
{
"56": "2.2. Các Service với mục đích riêng biệt"
},
{
"57": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"58": "2.2.2. Cấu hình vô hiệu hoá chargen services"
},
{
"59": "2.2.3. Cấu hình vô hiệu hoá daytime services"
},
{
"60": "2.2.4. Cấu hình vô hiệu hoá discard services"
},
{
"61": "2.2.5. Cấu hình vô hiệu hoá echo services"
},
{
"62": "2.2.6. Cấu hình vô hiệu hoá time services"
},
{
"63": "2.2.7. Cấu hình vô hiệu hoá rsh server"
},
{
"64": "2.2.8. Cấu hình vô hiệu hoá talk server"
},
{
"65": "2.2.9. Cấu hình vô hiệu hoá autofs services"
},
{
"66": "2.2.10. Cấu hình vô hiệu hoá X window server services"
},
{
"67": "2.2.11. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"68": "2.2.12. Cấu hình vô hiệu hoá cups services"
},
{
"69": "2.2.13. Cấu hình vô hiệu hoá dhcp server services"
},
{
"70": "2.2.14. Cấu hình vô hiệu hoá ldap server services"
},
{
"71": "2.2.15. Cấu hình vô hiệu hoá dns server services"
},
{
"72": "2.2.16. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"73": "2.2.17. Cấu hình vô hiệu hoá ftp server services"
},
{
"74": "2.2.18. Cấu hình vô hiệu hoá tftp server services"
},
{
"75": "2.2.19. Cấu hình vô hiệu hoá web server services"
},
{
"76": "2.2.20. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"77": "2.2.21. Cấu hình vô hiệu hoá samba file server services"
},
{
"78": "2.2.22. Cấu hình vô hiệu hoá web proxy server services"
},
{
"79": "2.2.23. Cấu hình vô hiệu hoá snmp services"
},
{
"80": "2.2.24. Cấu hình vô hiệu hoá nis server services"
},
{
"81": "2.2.25. Cấu hình vô hiệu hoá telnet server services"
},
{
"82": "2.2.26. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"83": "2.2.27. Cấu hình vô hiệu hoá network file system services"
},
{
"84": "2.2.28. Cấu hình vô hiệu hoá rpcbind services"
},
{
"85": "2.2.29. Cấu hình vô hiệu hoá rsync services"
},
{
"86": "2.3. Service Clients"
},
{
"87": "2.3.1. Cấu hình vô hiệu hoá NIS Client"
},
{
"88": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"89": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"90": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"91": "2.3.5. Cấu hình vô hiệu hoá LDAP client"
},
{
"92": "2.3.6. Cấu hình vô hiệu hoá ftp client"
},
{
"93": "2.3.7. Cấu hình vô hiệu hoá tftp client"
},
{
"94": "3. Cấu hình mạng"
},
{
"95": "3.1. Tham số cấu hình mạng (Host Only)"
},
{
"96": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"97": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"98": "3.2. Tham số cấu hình mạng (Host và Router)"
},
{
"99": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"100": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"101": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"102": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"103": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"104": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"105": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"106": "3.4. Cấu hình Firewall"
},
{
"107": "3.4.1. Cấu hình firewalld"
},
{
"108": "3.4.1.1. Cấu hình kích hoạt firewalld"
},
{
"109": "3.4.1.3. Cấu hình firewalld rule cho tất cả các port và protocol đang mở"
},
{
"110": "3.4.1.4. Cấu hình chính sách từ chối mặc định cho firewalld"
},
{
"111": "3.4.2. Iptables"
},
{
"112": "3.4.2.1. Cấu hình kích hoạt Iptables"
},
{
"113": "3.4.2.3. Cấu hình iptables loopback traffic"
},
{
"114": "3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"115": "3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"116": "4. Logging và Auditing"
},
{
"117": "4.1. Cấu hình logging"
},
{
"118": "4.1.1. Cấu hình rsyslog"
},
{
"119": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"120": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"121": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"122": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"123": "5. Cấu hình truy cập, xác thực và ủy quyền"
},
{
"124": "5.1. Cấu hình cron"
},
{
"125": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"126": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"127": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"128": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"129": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"130": "5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly"
},
{
"131": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"132": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền"
},
{
"133": "5.2. Cấu hình máy chủ SSH"
},
{
"134": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"135": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"136": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"137": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"138": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"139": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"140": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"141": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"142": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"143": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"144": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"145": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"146": "5.2.13. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"147": "5.2.14. Cấu hình cảnh báo SSH"
},
{
"148": "5.2.15. Cấu hình SSH MaxAuthTries"
},
{
"149": "5.2.16. Cấu hình SSH MaxStartups"
},
{
"150": "5.2.17. Cấu hình SSH MaxSessions"
},
{
"151": "5.2.18. Cấu hình SSH LoginGraceTime"
},
{
"152": "5.2.19. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"153": "5.2.20. Cấu hình các thuật toán MAC được cho phép"
},
{
"154": "5.3. Cấu hình PAM"
},
{
"155": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"156": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"157": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"158": "5.3.4. Cấu hình thuật toán hash mật khẩu sang SHA-512"
},
{
"159": "5.4. Cấu hình tài khoản người dùng và môi trường"
},
{
"160": "5.4.1. Cấu hình mật khẩu người dùng"
},
{
"161": "5.4.1.1. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"162": "5.4.1.2. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"163": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"164": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"165": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"166": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"167": "5.4.3. Cấu hình shell timeout mặc định"
},
{
"168": "5.4.4. Cấu hình group mặc định của tài khoản root"
},
{
"169": "5.4.5. Cấu hình user umask mặc định"
},
{
"170": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"171": "6. System Maintenance"
},
{
"172": "6.1. Quyền của file hệ thống"
},
{
"173": "6.1.1. Cấu hình sticky bit cho tất cả các thư mục dùng chung"
},
{
"174": "6.1.2. Cấu hình phân quyền cho file /etc/passwd"
},
{
"175": "6.1.3. Cấu hình phân quyền cho file /etc/shadow"
},
{
"176": "6.1.4. Cấu hình phân quyền cho file /etc/group"
},
{
"177": "6.1.5. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"178": "6.1.6. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"179": "6.1.7. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"180": "6.1.8. Cấu hình phân quyền cho file /etc/group-"
},
{
"181": "6.1.9. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"182": "6.1.10. Đảm bảo không có file world-writable tồn tại"
},
{
"183": "6.1.11. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"184": "6.1.12. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"185": "6.2. Thiết lập cho người dùng và nhóm"
},
{
"186": "6.2.1. Đảm bảo trường mật khẩu không để trống"
},
{
"187": "6.2.2. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"188": "6.2.3. Đảm bảo UID không bị lặp"
},
{
"189": "6.2.4. Đảm bảo GID không bị lặp"
},
{
"190": "6.2.5. Đảm bảo tên người dùng không bị lặp"
},
{
"191": "6.2.6. Đảm bảo tên group không bị lặp"
},
{
"192": "6.2.7. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"193": "6.2.8. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"194": "6.2.9. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"195": "6.2.10. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"196": "6.2.11. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"197": "6.2.12. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
},
{
"198": "6.2.13. Đảm bảo không người dùng nào có file .forward"
},
{
"199": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"200": "6.2.15. Đảm bảo không người dùng nào có file .rhosts"
}
]
}
+484
View File
@@ -0,0 +1,484 @@
{
"data": [
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.1.8. Cấu hình vô hiệu hoá usb storage"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"31": "1.2.1. Cấu hình kích hoạt gpgcheck"
},
{
"33": "1.3.1. Kiểm tra cài đặt AIDE"
},
{
"34": "1.3.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"36": "1.4.1. Phân quyền đối với file cấu hình bootloader"
},
{
"37": "1.4.2. Cấu hình mật khẩu cho bootloader"
},
{
"38": "1.4.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"39": "1.4.4. Cấu hình vô hiệu hoá interactive boot"
},
{
"41": "1.5.1. Cấu hình vô hiệu hoá core dump"
},
{
"42": "1.5.2. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"43": "1.5.3. Cấu hình vô hiệu hoá prelink"
},
{
"45": "1.6.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"46": "1.6.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"47": "1.6.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"48": "1.6.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"49": "1.6.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"50": "1.6.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"51": "1.6.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"54": "2.1.1. Cấu hình sử dụng chrony"
},
{
"55": "2.1.2. Cấu hình sử dụng ntp"
},
{
"57": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"58": "2.2.2. Cấu hình vô hiệu hoá chargen services"
},
{
"59": "2.2.3. Cấu hình vô hiệu hoá daytime services"
},
{
"60": "2.2.4. Cấu hình vô hiệu hoá discard services"
},
{
"61": "2.2.5. Cấu hình vô hiệu hoá echo services"
},
{
"62": "2.2.6. Cấu hình vô hiệu hoá time services"
},
{
"63": "2.2.7. Cấu hình vô hiệu hoá rsh server"
},
{
"64": "2.2.8. Cấu hình vô hiệu hoá talk server"
},
{
"65": "2.2.9. Cấu hình vô hiệu hoá autofs services"
},
{
"66": "2.2.10. Cấu hình vô hiệu hoá X window server services"
},
{
"67": "2.2.11. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"68": "2.2.12. Cấu hình vô hiệu hoá cups services"
},
{
"69": "2.2.13. Cấu hình vô hiệu hoá dhcp server services"
},
{
"70": "2.2.14. Cấu hình vô hiệu hoá ldap server services"
},
{
"71": "2.2.15. Cấu hình vô hiệu hoá dns server services"
},
{
"72": "2.2.16. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"73": "2.2.17. Cấu hình vô hiệu hoá ftp server services"
},
{
"74": "2.2.18. Cấu hình vô hiệu hoá tftp server services"
},
{
"75": "2.2.19. Cấu hình vô hiệu hoá web server services"
},
{
"76": "2.2.20. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"77": "2.2.21. Cấu hình vô hiệu hoá samba file server services"
},
{
"78": "2.2.22. Cấu hình vô hiệu hoá web proxy server services"
},
{
"79": "2.2.23. Cấu hình vô hiệu hoá snmp services"
},
{
"80": "2.2.24. Cấu hình vô hiệu hoá nis server services"
},
{
"81": "2.2.25. Cấu hình vô hiệu hoá telnet server services"
},
{
"82": "2.2.26. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"83": "2.2.27. Cấu hình vô hiệu hoá network file system services"
},
{
"84": "2.2.28. Cấu hình vô hiệu hoá rpcbind services"
},
{
"85": "2.2.29. Cấu hình vô hiệu hoá rsync services"
},
{
"87": "2.3.1. Cấu hình vô hiệu hoá nis client"
},
{
"88": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"89": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"90": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"91": "2.3.5. Cấu hình vô hiệu hoá ldap client"
},
{
"92": "2.3.6. Cấu hình vô hiệu hoá ftp client"
},
{
"93": "2.3.7. Cấu hình vô hiệu hoá tftp client"
},
{
"96": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"97": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"99": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"100": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"101": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"102": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"103": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"104": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"105": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"108": "3.3.1.1. Cấu hình kích hoạt Iptables"
},
{
"109": "3.3.1.2. Cấu hình iptables loopback traffic"
},
{
"110": "3.3.1.3. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"111": "3.3.1.4. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"115": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"116": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"117": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"118": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"121": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"122": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"123": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"124": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"125": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"126": "5.1.6. Cấu hình phân quyền cho file /etc/cron.monthly"
},
{
"127": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"128": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được uỷ quyền"
},
{
"130": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"131": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"132": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"133": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"134": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"135": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"136": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"137": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"138": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"139": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"140": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"141": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"142": "5.2.13. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"143": "5.2.14. Cấu hình cảnh báo SSH"
},
{
"144": "5.2.15. Cấu hình SSH MaxAuthTries"
},
{
"145": "5.2.16. Cấu hình SSH MaxStartups"
},
{
"146": "5.2.17. Cấu hình SSH MaxSessions"
},
{
"147": "5.2.18. Cấu hình SSH LoginGraceTime"
},
{
"148": "5.2.19. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"149": "5.2.20. Cấu hình các thuật toán MAC được cho phép"
},
{
"151": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"152": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"153": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"154": "5.3.4. Cấu hình thuật toán hash mật khẩu sang SHA-512"
},
{
"157": "5.4.1.1. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"158": "5.4.1.2. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"159": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"160": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"161": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"162": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"163": "5.4.3. Cấu hình shell timeout mặc định"
},
{
"164": "5.4.4. Cấu hình group mặc định của tài khoản root"
},
{
"165": "5.4.5. Cấu hình user umask mặc định"
},
{
"166": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"169": "6.1.1. Cấu hình sticky bit cho tất cả các thư mục dùng chung"
},
{
"170": "6.1.2. Cấu hình phân quyền cho file /etc/passwd"
},
{
"171": "6.1.3. Cấu hình phân quyền cho file /etc/shadow"
},
{
"172": "6.1.4. Cấu hình phân quyền cho file /etc/group"
},
{
"173": "6.1.5. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"174": "6.1.6. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"175": "6.1.7. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"176": "6.1.8. Cấu hình phân quyền cho file /etc/group-"
},
{
"177": "6.1.9. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"178": "6.1.10. Đảm bảo không có file world-writable tồn tại"
},
{
"179": "6.1.11. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"180": "6.1.12. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"182": "6.2.1. Đảm bảo trường mật khẩu không để trống"
},
{
"183": "6.2.2. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"184": "6.2.3. Đảm bảo UID không bị lặp"
},
{
"185": "6.2.4. Đảm bảo GID không bị lặp"
},
{
"186": "6.2.5. Đảm bảo tên người dùng không bị lặp"
},
{
"187": "6.2.6. Đảm bảo tên group không bị lặp"
},
{
"188": "6.2.7. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"189": "6.2.8. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"190": "6.2.9. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"191": "6.2.10. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"192": "6.2.11. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"193": "6.2.12. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
},
{
"194": "6.2.13. Đảm bảo không người dùng nào có file .forward"
},
{
"195": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"196": "6.2.15. Đảm bảo không người dùng nào có file .rhosts"
}
]
}
+595
View File
@@ -0,0 +1,595 @@
{
"data": [
{
"": "1. Thiết lập ban đầu"
},
{
"": "1.1. Cấu hình filesystem"
},
{
"": "1.1.1. Cấu hình vô hiệu hoá các filesystem không sử dụng"
},
{
"7": "1.1.1.1. Cấu hình vô hiệu hoá cramfs filesystem"
},
{
"8": "1.1.1.2. Cấu hình vô hiệu hoá freevxfs filesystem"
},
{
"9": "1.1.1.3. Cấu hình vô hiệu hoá hfs filesystem"
},
{
"10": "1.1.1.4. Cấu hình vô hiệu hoá hfsplus filesystem"
},
{
"11": "1.1.1.5. Cấu hình vô hiệu hoá jffs2 filesystem"
},
{
"12": "1.1.1.6. Cấu hình vô hiệu hoá squashfs filesystem"
},
{
"13": "1.1.1.7. Cấu hình vô hiệu hoá udf filesystem"
},
{
"14": "1.1.1.8. Cấu hình vô hiệu hoá usb-storage filesystem"
},
{
"15": "1.1.2. Cấu hình phân vùng /tmp"
},
{
"16": "1.1.2.1. Cấu hình tuỳ chọn nodev cho phân vùng /tmp"
},
{
"17": "1.1.2.2. Cấu hình tuỳ chọn nosuid cho phân vùng /tmp"
},
{
"18": "1.1.2.3. Cấu hình tuỳ chọn noexec cho phân vùng /tmp"
},
{
"19": "1.1.3. Cấu hình phân vùng /var/tmp"
},
{
"20": "1.1.3.1. Cấu hình tuỳ chọn nodev cho phân vùng /var/tmp"
},
{
"21": "1.1.3.2. Cấu hình tuỳ chọn nosuid cho phân vùng /var/tmp"
},
{
"22": "1.1.3.3. Cấu hình tuỳ chọn noexec cho phân vùng /var/tmp"
},
{
"23": "1.1.4. Cấu hình phân vùng /home"
},
{
"24": "1.1.4.1. Cấu hình tuỳ chọn nodev cho phân vùng /home"
},
{
"25": "1.1.4.2. Cấu hình tuỳ chọn nosuid cho phân vùng /home"
},
{
"26": "1.1.5. Cấu hình phân vùng /dev/shm"
},
{
"27": "1.1.5.1. Cấu hình tuỳ chọn nodev cho phân vùng /dev/shm"
},
{
"28": "1.1.5.2. Cấu hình tuỳ chọn nosuid cho phân vùng /dev/shm"
},
{
"29": "1.1.5.3. Cấu hình tuỳ chọn noexec cho phân vùng /dev/shm"
},
{
"30": "1.2. Cấu hình cập nhật phần mềm"
},
{
"31": "1.2.1. Cấu hình kích hoạt gpgcheck"
},
{
"32": "1.3. Kiểm tra tính toàn vẹn của filesystem"
},
{
"33": "1.3.1. Kiểm tra cài đặt AIDE"
},
{
"34": "1.3.2. Cấu hình kiểm tra tính toàn vẹn của filesystem"
},
{
"35": "1.4. Cấu hình khởi động an toàn"
},
{
"36": "1.4.1. Phân quyền đối với file cấu hình bootloader"
},
{
"37": "1.4.2. Cấu hình xác thực khi truy cập rescue mode"
},
{
"38": "1.4.3. Cấu hình xác thực khi truy cập single user mode"
},
{
"39": "1.4.4. Cấu hình vô hiệu hoá interactive boot"
},
{
"40": "1.5. Additional Process Hardening"
},
{
"41": "1.5.1. Cấu hình vô hiệu hoá core dump"
},
{
"42": "1.5.2. Cấu hình kích hoạt ASLR (address space layout randomization)"
},
{
"43": "1.5.3. Cấu hình vô hiệu hoá prelink"
},
{
"44": "1.6. Kiểm soát nội dung cảnh báo"
},
{
"45": "1.6.1. Kiểm soát nội dung motd (Message Of The Day)"
},
{
"46": "1.6.2. Kiểm soát nội dung thông báo khi đăng nhập"
},
{
"47": "1.6.3. Kiểm soát nội dung thông báo khi đăng nhập từ xa"
},
{
"48": "1.6.4. Cấu hình phân quyền đối với file /etc/motd"
},
{
"49": "1.6.5. Cấu hình phân quyền đối với file /etc/issue"
},
{
"50": "1.6.6. Cấu hình phân quyền đối với file /etc/issue.net"
},
{
"51": "1.6.7. Kiểm soát nội dung thông báo khi truy cập GNOME"
},
{
"52": "2. Service"
},
{
"53": "2.1. Cấu hình Time Synchronization"
},
{
"54": "2.1.1. Cấu hình sử dụng chrony"
},
{
"55": "2.1.2. Cấu hình sử dụng NTP"
},
{
"56": "2.2. Các Service với mục đích riêng biệt"
},
{
"57": "2.2.1. Cấu hình vô hiệu hoá xinetd services"
},
{
"58": "2.2.2. Cấu hình vô hiệu hoá chargen services"
},
{
"59": "2.2.3. Cấu hình vô hiệu hoá daytime services"
},
{
"60": "2.2.4. Cấu hình vô hiệu hoá discard services"
},
{
"61": "2.2.5. Cấu hình vô hiệu hoá echo services"
},
{
"62": "2.2.6. Cấu hình vô hiệu hoá time services"
},
{
"63": "2.2.7. Cấu hình vô hiệu hoá rsh server"
},
{
"64": "2.2.8. Cấu hình vô hiệu hoá talk server"
},
{
"65": "2.2.9. Cấu hình vô hiệu hoá autofs services"
},
{
"66": "2.2.10. Cấu hình vô hiệu hoá X window server services"
},
{
"67": "2.2.11. Cấu hình vô hiệu hoá avahi daemon services"
},
{
"68": "2.2.12. Cấu hình vô hiệu hoá cups services"
},
{
"69": "2.2.13. Cấu hình vô hiệu hoá dhcp server services"
},
{
"70": "2.2.14. Cấu hình vô hiệu hoá ldap server services"
},
{
"71": "2.2.15. Cấu hình vô hiệu hoá dns server services"
},
{
"72": "2.2.16. Cấu hình vô hiệu hoá dnsmasq services"
},
{
"73": "2.2.17. Cấu hình vô hiệu hoá ftp server services"
},
{
"74": "2.2.18. Cấu hình vô hiệu hoá tftp server services"
},
{
"75": "2.2.19. Cấu hình vô hiệu hoá web server services"
},
{
"76": "2.2.20. Cấu hình vô hiệu hoá imap and pop3 server services"
},
{
"77": "2.2.21. Cấu hình vô hiệu hoá samba file server services"
},
{
"78": "2.2.22. Cấu hình vô hiệu hoá web proxy server services"
},
{
"79": "2.2.23. Cấu hình vô hiệu hoá snmp services"
},
{
"80": "2.2.24. Cấu hình vô hiệu hoá nis server services"
},
{
"81": "2.2.25. Cấu hình vô hiệu hoá telnet server services"
},
{
"82": "2.2.26. Cấu hình mail transfer agents sang chế độ local-only"
},
{
"83": "2.2.27. Cấu hình vô hiệu hoá network file system services"
},
{
"84": "2.2.28. Cấu hình vô hiệu hoá rpcbind services"
},
{
"85": "2.2.29. Cấu hình vô hiệu hoá rsync services"
},
{
"86": "2.3. Service Clients"
},
{
"87": "2.3.1. Cấu hình vô hiệu hoá NIS Client"
},
{
"88": "2.3.2. Cấu hình vô hiệu hoá rsh client"
},
{
"89": "2.3.3. Cấu hình vô hiệu hoá talk client"
},
{
"90": "2.3.4. Cấu hình vô hiệu hoá telnet client"
},
{
"91": "Cấu hình vô hiệu hoá LDAP client"
},
{
"92": "2.3.6. Cấu hình vô hiệu hoá ftp client"
},
{
"93": "2.3.7. Cấu hình vô hiệu hoá tftp client"
},
{
"94": "3. Cấu hình mạng"
},
{
"95": "3.1. Tham số cấu hình mạng (Host Only)"
},
{
"96": "3.1.1. Cấu hình vô hiệu hoá IP forwarding"
},
{
"97": "3.1.2. Cấu hình vô hiệu hoá tính năng chuyển hướng gói tin (packet redirect)"
},
{
"98": "3.2. Tham số cấu hình mạng (Host và Router)"
},
{
"99": "3.2.1. Cấu hình từ chối các gói tin với nguồn được định tuyến trước"
},
{
"100": "3.2.2. Cấu hình từ chối các ICMP redirect message"
},
{
"101": "3.2.3. Cấu hình từ chối các secure ICMP redirect message"
},
{
"102": "3.2.4. Cấu hình từ chối các gói tin ICMP request broadcast"
},
{
"103": "3.2.5. Cấu hình bỏ qua phản hồi ICMP không hợp lệ"
},
{
"104": "3.2.6. Cấu hình Reverse Path Filtering"
},
{
"105": "3.2.7. Cấu hình TCP SYN Cookies"
},
{
"106": "3.4. Cấu hình Firewall"
},
{
"107": "3.4.1. Cấu hình firewalld"
},
{
"108": "3.4.1.1. Cấu hình kích hoạt firewalld"
},
{
"109": "3.4.1.3. Cấu hình firewalld rule cho tất cả các port và protocol đang mở"
},
{
"110": "3.4.1.4. Cấu hình chính sách từ chối mặc định cho firewalld"
},
{
"111": "3.4.2. Iptables"
},
{
"112": "3.4.2.1. Cấu hình kích hoạt Iptables"
},
{
"113": "3.4.2.3. Cấu hình iptables loopback traffic"
},
{
"114": "3.4.2.4. Cấu hình iptables rule cho tất cả các port và protocol đang mở"
},
{
"115": "3.4.2.5. Cấu hình chính sách từ chối mặc định cho iptables"
},
{
"116": "4. Logging và Auditing"
},
{
"117": "4.1. Cấu hình logging"
},
{
"118": "4.1.1. Cấu hình rsyslog"
},
{
"119": "4.1.1.1. Cấu hình kích hoạt rsyslog service"
},
{
"120": "4.1.1.2. Phân quyền đối với file log sinh ra từ rsyslog"
},
{
"121": "4.1.1.3. Cấu hình lưu trữ log sinh ra từ rsyslog tập trung"
},
{
"122": "4.1.1.4. Phân quyền đối với tất cả các file log"
},
{
"123": "5. Cấu hình truy cập, xác thực và ủy quyền"
},
{
"124": "5.1. Cấu hình cron"
},
{
"125": "5.1.1. Cấu hình kích hoạt cron daemon"
},
{
"126": "5.1.2. Cấu hình phân quyền cho file /etc/crontab"
},
{
"127": "5.1.3. Cấu hình phân quyền cho file /etc/cron.hourly"
},
{
"128": "5.1.4. Cấu hình phân quyền cho file /etc/cron.daily"
},
{
"129": "5.1.5. Cấu hình phân quyền cho file /etc/cron.weekly"
},
{
"130": "5.1.6. Cấu hình phân quyền cho của file /etc/cron.monthly"
},
{
"131": "5.1.7. Cấu hình phân quyền cho file /etc/cron.d"
},
{
"132": "5.1.8. Cấu hình at/cron hạn chế chỉ cho người dùng được ủy quyền"
},
{
"133": "5.2. Cấu hình máy chủ SSH"
},
{
"134": "5.2.1. Cấu hình phân quyền cho file /etc/ssh/sshd_config"
},
{
"135": "5.2.2. Cấu hình phân quyền cho các file SSH private host key"
},
{
"136": "5.2.3. Cấu hình phân quyền cho các file SSH public host key"
},
{
"137": "5.2.4. Cấu hình giới hạn truy cập cho máy chủ SSH"
},
{
"138": "5.2.5. Cấu hình LogLevel cho máy chủ SSH"
},
{
"139": "5.2.6. Cấu hình sử dụng SSH PAM"
},
{
"140": "5.2.7. Cấu hình vô hiệu hoá đăng nhập bằng root cho máy chủ SSH"
},
{
"141": "5.2.8. Cấu hình vô hiệu hoá HostbasedAuthentication cho máy chủ SSH"
},
{
"142": "5.2.9. Cấu hình vô hiệu hoá PermitEmptyPasswords cho máy chủ SSH"
},
{
"143": "5.2.10. Cấu hình vô hiệu hoá PermitUserEnviroment cho máy chủ SSH"
},
{
"144": "5.2.11. Cấu hình vô hiệu hoá IgnoreRhosts cho máy chủ SSH"
},
{
"145": "5.2.12. Cấu hình vô hiệu hoá X11 Forwarding cho máy chủ SSH"
},
{
"146": "5.2.13. Cấu hình vô hiệu hoá SSH AllowTcpForwarding"
},
{
"147": "5.2.14. Cấu hình cảnh báo SSH"
},
{
"148": "5.2.15. Cấu hình SSH MaxAuthTries"
},
{
"149": "5.2.16. Cấu hình SSH MaxStartups"
},
{
"150": "5.2.17. Cấu hình SSH MaxSessions"
},
{
"151": "5.2.18. Cấu hình SSH LoginGraceTime"
},
{
"152": "5.2.19. Cấu hình khoảng thời gian chờ không hoạt động cho máy chủ SSH"
},
{
"153": "5.2.20. Cấu hình các thuật toán MAC được cho phép"
},
{
"154": "5.3. Cấu hình PAM"
},
{
"155": "5.3.1. Cấu hình điều kiện tạo mật khẩu"
},
{
"156": "5.3.2. Cấu hình khoá truy cập do nhiều lần nhập mật khẩu thất bại"
},
{
"157": "5.3.3. Giới hạn việc sử dụng lại mật khẩu"
},
{
"158": "5.3.4. Cấu hình thuật toán hash mật khẩu sang SHA-512"
},
{
"159": "5.4. Cấu hình tài khoản người dùng và môi trường"
},
{
"160": "5.4.1. Cấu hình mật khẩu người dùng"
},
{
"161": "5.4.1.1. Cấu hình thời gian hết hạn sử dụng mật khẩu"
},
{
"162": "5.4.1.2. Cấu hình thời gian tối thiểu giữa những lần thay đổi mật khẩu"
},
{
"163": "5.4.1.3. Cấu hình thời gian cảnh báo mật khẩu hết hạn"
},
{
"164": "5.4.1.4. Cấu hình thời gian khoá tài khoản không thay mật khẩu sau khi hết hạn"
},
{
"165": "5.4.1.5. Đảm bảo thời gian thay đổi mật khẩu lần cuối hợp lệ"
},
{
"166": "5.4.2. Cấu hình vô hiệu hoá đăng nhập bằng tài khoản hệ thống"
},
{
"167": "5.4.3. Cấu hình shell timeout mặc định"
},
{
"168": "5.4.4. Cấu hình group mặc định của tài khoản root"
},
{
"169": "5.4.5. Cấu hình user umask mặc định"
},
{
"170": "5.4.6. Cấu hình hạn chế truy cập cho câu lệnh su"
},
{
"171": "6. System Maintenance"
},
{
"172": "6.1. Quyền của file hệ thống"
},
{
"173": "6.1.1. Cấu hình sticky bit cho tất cả các thư mục dùng chung"
},
{
"174": "6.1.2. Cấu hình phân quyền cho file /etc/passwd"
},
{
"175": "6.1.3. Cấu hình phân quyền cho file /etc/shadow"
},
{
"176": "6.1.4. Cấu hình phân quyền cho file /etc/group"
},
{
"177": "6.1.5. Cấu hình phân quyền cho file /etc/gshadow"
},
{
"178": "6.1.6. Cấu hình phân quyền cho file /etc/passwd-"
},
{
"179": "6.1.7. Cấu hình phân quyền cho file /etc/shadow-"
},
{
"180": "6.1.8. Cấu hình phân quyền cho file /etc/group-"
},
{
"181": "6.1.9. Cấu hình phân quyền cho file /etc/gshadow-"
},
{
"182": "6.1.10. Đảm bảo không có file world-writable tồn tại"
},
{
"183": "6.1.11. Đảm bảo các file hoặc thư mục không có chủ sở hữu không tồn tại"
},
{
"184": "6.1.12. Đảm bảo các file hoặc thư mục không có nhóm không tồn tại"
},
{
"185": "6.2. Thiết lập cho người dùng và nhóm"
},
{
"186": "6.2.1. Đảm bảo trường mật khẩu không để trống"
},
{
"187": "6.2.2. Đảm bảo mọi nhóm trong file /etc/passwd tồn tại trong file /etc/group"
},
{
"188": "6.2.3. Đảm bảo UID không bị lặp"
},
{
"189": "6.2.4. Đảm bảo GID không bị lặp"
},
{
"190": "6.2.5. Đảm bảo tên người dùng không bị lặp"
},
{
"191": "6.2.6. Đảm bảo tên group không bị lặp"
},
{
"192": "6.2.7. Đảm bảo tính toàn vẹn cho biến môi trường PATH của root"
},
{
"193": "6.2.8. Đảm bảo root là tài khoản duy nhất có UID là 0"
},
{
"194": "6.2.9. Đảm bảo mọi người dùng đều tồn tại thư mục home"
},
{
"195": "6.2.10. Đảm bảo người dùng sở hữu thư mục home của chính họ"
},
{
"196": "6.2.11. Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao"
},
{
"197": "6.2.12. Đảm bảo các file dot của người dùng không cấp quyền write cho group hoặc other"
},
{
"198": "6.2.13. Đảm bảo không người dùng nào có file .forward"
},
{
"199": "6.2.14. Đảm bảo không người dùng nào có file .netrc"
},
{
"200": "6.2.15. Đảm bảo không người dùng nào có file .rhosts"
}
]
}

Some files were not shown because too many files have changed in this diff Show More