Files
audit-web/audit_run_script/oracle_linux_audit_v2.py
T
2026-08-26 14:11:37 +07:00

273 lines
9.3 KiB
Python

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)