From 4732714188279cb8cbaf52ce473519a03648c1d2 Mon Sep 17 00:00:00 2001 From: Florian Date: Fri, 21 Feb 2025 09:24:33 +0100 Subject: [PATCH 1/2] R67 et R69 --- AnalyseConfiguration/Reference_moyen.yaml | 22 +- .../Thematiques/GestionAcces.py | 99 +++++++-- .../Thematiques/Utilisateurs.py | 201 ++++++++++++------ .../RapportAnalyse/gestion_acces_moyen.yml | 183 ++++++++++++---- .../RapportAnalyse/services_moyen.yml | 4 +- .../RapportAnalyse/system_moyen.yml | 2 +- .../RapportAnalyse/users_moyen.yml | 111 ++++++++++ .../RapportAnalyse/utilisateurs_moyen.yml | 90 +++++--- 8 files changed, 560 insertions(+), 152 deletions(-) create mode 100644 GenerationRapport/RapportAnalyse/users_moyen.yml diff --git a/AnalyseConfiguration/Reference_moyen.yaml b/AnalyseConfiguration/Reference_moyen.yaml index fc60088..17a2f7a 100644 --- a/AnalyseConfiguration/Reference_moyen.yaml +++ b/AnalyseConfiguration/Reference_moyen.yaml @@ -199,7 +199,6 @@ R74: - "HMS.lxd" - "$myhostname" - R75: description: "Configure a mail alias for service accounts (The function only detects aliases; it is necessary to manually check if the alias is correctly associated with the administrator's email. The detected elements come from the reference file. If none of the expected elements are found, the value of expected_elements will be an empty list. At least one alias is sufficient for the rule to be compliant.)" expected: @@ -207,3 +206,24 @@ R75: - "root" - "postmaster" - "admin" + +R69: + description: "Ensure that NSS is configured securely when using remote user databases. + If using 'sss' (SSSD), 'uses_remote_db' should be 'sss', and 'secure_connection' must be 'TLS_CACERT'. + If using 'ldap', 'uses_remote_db' should be 'ldap', and 'secure_connection' must be 'start_tls' or 'ssl'. + The authentication account ('binddn_user') must be separate from user accounts and formatted as 'cn=service_account,dc=example'. + The account should have limited privileges ('limited_rights' should be 'Yes' (cn=service_account))." + expected: + uses_remote_db: sss + secure_connection: tls + binddn_user: cn=service_account,dc=example,dc=com + limited_rights: Yes + +R67: + description: "Ensure remote authentication via PAM is secured with encryption, additional security modules, and no plaintext password storage." + expected: + detected_pam_modules: "pam_ldap" + security_modules: + pam_faillock: "Enabled" + pam_pwquality: "Enabled" + pam_wheel: "Enabled" diff --git a/AnalyseConfiguration/Thematiques/GestionAcces.py b/AnalyseConfiguration/Thematiques/GestionAcces.py index aacc9ce..ceca38d 100644 --- a/AnalyseConfiguration/Thematiques/GestionAcces.py +++ b/AnalyseConfiguration/Thematiques/GestionAcces.py @@ -16,22 +16,45 @@ def load_reference_yaml(niveau): # Vérification de conformité adaptée pour chaque règle def check_compliance(rule_id, rule_value, reference_data): - """Vérifie la conformité en fonction de la règle donnée.""" - expected_value = reference_data.get(rule_id, {}).get("expected", []) - - if not isinstance(expected_value, list): - expected_value = [] - - compliance_result = { - "rule_id": rule_id, - "status": "Conforme" if not rule_value else "Non conforme", - "appliquer": False if rule_value else True, - "éléments_detectés": rule_value if rule_value else "Aucun", - "éléments_attendus": expected_value - } + """Vérifie la conformité en fonction de la règle donnée et gère le cas particulier de R67.""" + + # Charger les valeurs attendues depuis Reference_Moyen.yaml + expected_value = reference_data.get(rule_id, {}).get("expected", {}) + + if rule_id == "R67": + # Construire la liste des éléments attendus sous le même format que les éléments détectés + expected_list = [f"detected_pam_modules: {expected_value.get('detected_pam_modules', '')}"] + \ + [f"{module}: {status}" for module, status in expected_value.get("security_modules", {}).items()] + + # Vérifier si tous les éléments détectés correspondent exactement aux valeurs attendues + is_compliant = set(rule_value) == set(expected_list) + + compliance_result = { + "rule_id": rule_id, + "status": "Conforme" if is_compliant else "Non conforme", + "appliquer": is_compliant, # Maintenant, appliquer = True si conforme + "éléments_attendus": expected_value, # Toujours afficher les éléments attendus + "éléments_detectés": rule_value if rule_value else [] # Assurer une liste bien formatée + } + else: + # Cas général pour les autres règles + if not isinstance(expected_value, list): + expected_value = [] + + is_compliant = not rule_value # Conforme si rule_value est vide + + compliance_result = { + "rule_id": rule_id, + "status": "Conforme" if is_compliant else "Non conforme", + "appliquer": is_compliant, # Maintenant, appliquer = True si conforme + "éléments_attendus": expected_value if expected_value else "Non spécifié", + "éléments_detectés": rule_value if rule_value else [] # Assurer une liste bien formatée + } return compliance_result + + # Fonction principale pour analyser la gestion des accès def analyse_gestion_acces(serveur, niveau, reference_data=None): """Analyse la gestion des accès et génère un rapport YAML avec conformité.""" @@ -90,6 +113,10 @@ def analyse_gestion_acces(serveur, niveau, reference_data=None): user_private_tmp = get_user_private_tmp(serveur) report["R55"] = check_compliance("R55", user_private_tmp, reference_data) + print("-> Vérification de la sécurisation de l'authentification distante via PAM (R67)") + pam_security = check_pam_security(serveur, reference_data) + report["R67"] = check_compliance("R67", pam_security, reference_data) + # Enregistrement du rapport save_yaml_report(report, f"gestion_acces_{niveau}.yml") @@ -359,6 +386,52 @@ def get_user_private_tmp(serveur): return issues_detected if issues_detected else [] # Retourne une liste des problèmes ou vide si conforme +# R67 - Sécuriser les authentifications distantes par PAM +def check_pam_security(serveur, reference_data): + """Vérifie si l'authentification à distance via PAM est sécurisée (R67).""" + + # Charger les valeurs attendues depuis Reference_Moyen.yaml + expected_values = reference_data.get("R67", {}).get("expected", {}) + + # Vérifier l'utilisation du module d'authentification distant (pam_ldap attendu) + command_pam_auth = "grep -Ei 'pam_ldap' /etc/pam.d/* 2>/dev/null" + stdin, stdout, stderr = serveur.exec_command(command_pam_auth) + detected_pam_entries = stdout.read().decode().strip().split("\n") + + # Si pam_ldap est détecté, l'afficher, sinon "Non trouvé" + detected_pam_module = "pam_ldap" if detected_pam_entries and any("pam_ldap" in line for line in detected_pam_entries) else "Non trouvé" + + # Vérifier la présence des modules de sécurité requis + security_modules = expected_values.get("security_modules", {}) + detected_security_modules = {} + + for module in security_modules.keys(): + command = f"grep -E '{module}' /etc/pam.d/* 2>/dev/null" + stdin, stdout, stderr = serveur.exec_command(command) + detected_status = "Enabled" if stdout.read().decode().strip() else "Non trouvé" + + # Stocker la valeur détectée + detected_security_modules[module] = detected_status + + # Construire les éléments détectés + detected_elements = { + "detected_pam_modules": detected_pam_module, + "security_modules": detected_security_modules + } + + # Construire la liste des éléments détectés (inclut tous les éléments attendus) + detected_list = [] + + # Ajouter les modules PAM LDAP + detected_list.append(f"detected_pam_modules: {detected_elements['detected_pam_modules']}") + + # Ajouter les modules de sécurité PAM + for module, detected_status in detected_elements["security_modules"].items(): + detected_list.append(f"{module}: {detected_status}") + + return detected_list + + # Fonction d'enregistrement des rapports def save_yaml_report(data, output_file): """Enregistre les données d'analyse dans un fichier YAML dans le dossier dédié.""" diff --git a/AnalyseConfiguration/Thematiques/Utilisateurs.py b/AnalyseConfiguration/Thematiques/Utilisateurs.py index 5f1f12e..8cc1276 100644 --- a/AnalyseConfiguration/Thematiques/Utilisateurs.py +++ b/AnalyseConfiguration/Thematiques/Utilisateurs.py @@ -1,60 +1,65 @@ import yaml import os -# Charger les références depuis Reference_min.yaml ou Reference_Moyen.yaml +# Load references from Reference_min.yaml or Reference_Moyen.yaml def load_reference_yaml(niveau): - """Charge le fichier de référence correspondant au niveau choisi (min ou moyen).""" + """Loads the reference file corresponding to the chosen level (min or moyen).""" file_path = f"AnalyseConfiguration/Reference_{niveau}.yaml" try: with open(file_path, "r", encoding="utf-8") as file: reference_data = yaml.safe_load(file) return reference_data or {} except Exception as e: - print(f"Erreur lors du chargement de {file_path} : {e}") + print(f"Error loading {file_path}: {e}") return {} def check_compliance(rule_id, rule_value, reference_data): - """Vérifie la conformité en fonction de la règle donnée.""" + """Checks compliance based on the given rule and includes the rule description in the report.""" + + # Retrieve the rule description + description = reference_data.get(rule_id, {}).get("description", "No description available.") + + # Retrieve expected values from the reference file expected_value = reference_data.get(rule_id, {}).get("expected", {}) - # Comparaison adaptée pour différents types de valeurs attendues + # Compliance check adapted for different types of expected values is_compliant = rule_value == expected_value - # Gérer ce qui est affiché dans "éléments_detectés" - detected_elements = rule_value if rule_value else "Aucun" + # Manage displayed detected elements + detected_elements = rule_value if rule_value else "None" compliance_result = { - "rule_id": rule_id, - "status": "Conforme" if is_compliant else "Non conforme", - "appliquer": is_compliant, # Si conforme, appliquer = True - "éléments_detectés": detected_elements, - "éléments_attendus": expected_value + "description": description, # Add rule description + "status": "Compliant" if is_compliant else "Non-compliant", + "apply": is_compliant, # If compliant, apply = True + "detected_elements": detected_elements, + "expected_elements": expected_value } return compliance_result -# Fonction principale pour analyser les utilisateurs -def analyse_utilisateurs(serveur, niveau, reference_data=None): - """Analyse les utilisateurs et génère un rapport YAML avec conformité.""" +# Main function for analyzing users +def analyse_utilisateurs(server, niveau, reference_data=None): + """Analyzes users and generates a YAML report with compliance details.""" report = {} if reference_data is None: reference_data = load_reference_yaml(niveau) if niveau == "min": - print("-> Aucune règle spécifique pour le niveau minimal en gestion des utilisateurs.") + print("-> No specific rules for the minimal level in user management.") elif niveau == "moyen": - print("-> Vérification de l'expiration des sessions (R32)") - tmout_value = check_tmout(serveur) - logind_conf = check_logind_conf(serveur) + print("-> Checking session expiration (R32)") + tmout_value = check_tmout(server) + logind_conf = check_logind_conf(server) report["R32"] = check_compliance("R32", {"TMOUT": tmout_value, "logind_conf": logind_conf}, reference_data) - print("-> Vérification de la séparation des comptes système et administrateurs (R70)") - local_users = get_local_users(serveur) - system_users = get_system_users(serveur) - admin_users = get_admin_users(serveur) - ldap_users = check_ldap_users(serveur) + print("-> Checking separation of system and administrator accounts (R70)") + local_users = get_local_users(server) + system_users = get_system_users(server) + admin_users = get_admin_users(server) + ldap_users = check_ldap_users(server) report["R70"] = check_compliance("R70", { "local_users": local_users, "system_users": system_users, @@ -62,37 +67,41 @@ def analyse_utilisateurs(serveur, niveau, reference_data=None): "ldap_users": ldap_users }, reference_data) - # Enregistrement du rapport + print("-> Checking security of remote user databases (R69)") + rule_value = check_remote_user_database_security(server, reference_data) # Retrieve detected values + report["R69"] = check_compliance("R69", rule_value, reference_data) # Verify compliance + + # Save the report save_yaml_report(report, f"utilisateurs_{niveau}.yml") - # Calcul du taux de conformité + # Compliance rate calculation total_rules = len(report) - conforming_rules = sum(1 for result in report.values() if result["status"] == "Conforme") if total_rules > 0 else 0 - compliance_percentage = (conforming_rules / total_rules) * 100 if total_rules > 0 else 100 # 100% si pas de règles + conforming_rules = sum(1 for result in report.values() if result["status"] == "Compliant") if total_rules > 0 else 0 + compliance_percentage = (conforming_rules / total_rules) * 100 if total_rules > 0 else 100 # 100% if no rules - print(f"\nTaux de conformité du niveau {niveau.upper()} (Utilisateurs) : {compliance_percentage:.2f}%") + print(f"\nCompliance rate for level {niveau.upper()} (Users): {compliance_percentage:.2f}%") -# R32 - Vérifier l'expiration des sessions et paramètres logind.conf +# R32 - Check session expiration and logind.conf settings def check_tmout(serveur): - """Vérifie la valeur de TMOUT dans /etc/profile et /etc/bash.bashrc.""" + """Checks the TMOUT value in /etc/profile and /etc/bash.bashrc.""" command_tmout = "grep -E '^TMOUT=' /etc/profile /etc/bash.bashrc 2>/dev/null | awk -F= '{print $2}' | sort -u" stdin, stdout, stderr = serveur.exec_command(command_tmout) - # Lire et nettoyer les valeurs + # Read and clean values tmout_values = list(filter(None, stdout.read().decode().strip().split("\n"))) - # Convertir en string pour correspondre à reference_moyen.yaml + # Convert to string to match reference_moyen.yaml try: - return str(int(tmout_values[0].strip())) if tmout_values else "Non défini" + return str(int(tmout_values[0].strip())) if tmout_values else "Not defined" except ValueError: - return "Non défini" + return "Not defined" def check_logind_conf(serveur): - """Vérifie les paramètres de systemd-logind en excluant les lignes commentées.""" + """Checks systemd-logind settings while excluding commented lines.""" logind_settings = { - "IdleAction": "Non défini", - "IdleActionSec": "Non défini", - "RuntimeMaxSec": "Non défini" + "IdleAction": "Not defined", + "IdleActionSec": "Not defined", + "RuntimeMaxSec": "Not defined" } command_logind = "sudo grep -E '^(IdleAction|IdleActionSec|RuntimeMaxSec)=' /etc/systemd/logind.conf | grep -v '^#'" @@ -106,34 +115,34 @@ def check_logind_conf(serveur): if key in logind_settings: logind_settings[key] = value.strip() - # Assurer que les valeurs en secondes sont conformes à reference_moyen.yaml + # Ensure time values are correctly formatted in seconds for key in ["IdleActionSec", "RuntimeMaxSec"]: - if logind_settings[key] != "Non défini" and not logind_settings[key].endswith("s"): + if logind_settings[key] != "Not defined" and not logind_settings[key].endswith("s"): try: - int_value = int(logind_settings[key]) # Vérifier si c'est un nombre - logind_settings[key] = f"{int_value}s" # Ajouter 's' si nécessaire + int_value = int(logind_settings[key]) # Ensure it's a number + logind_settings[key] = f"{int_value}s" # Append 's' if necessary except ValueError: - pass # Garder la valeur d'origine si elle est déjà une chaîne correcte + pass # Keep the original value if it's already in a correct format return logind_settings -# R70 - Vérifier la séparation des comptes utilisateurs, système et administrateurs +# R70 - Check the separation of system, local, and administrator accounts def get_local_users(serveur): - """Récupère les utilisateurs locaux définis dans /etc/passwd (UID >= 1000).""" + """Retrieves local users from /etc/passwd (UID >= 1000).""" command_local_users = "awk -F: '$3 >= 1000 {print $1}' /etc/passwd" stdin, stdout, stderr = serveur.exec_command(command_local_users) users = sorted(list(filter(None, stdout.read().decode().strip().split("\n")))) return users def get_system_users(serveur): - """Récupère les comptes système (UID < 1000).""" + """Retrieves system accounts (UID < 1000).""" command_system_users = "awk -F: '$3 < 1000 {print $1}' /etc/passwd" stdin, stdout, stderr = serveur.exec_command(command_system_users) users = sorted(list(filter(None, stdout.read().decode().strip().split("\n")))) return users def get_admin_users(serveur): - """Récupère les utilisateurs appartenant aux groupes sudo ou admin.""" + """Retrieves users belonging to sudo or admin groups.""" command_sudo_users = "getent group sudo | awk -F: '{print $4}'" stdin, stdout, stderr = serveur.exec_command(command_sudo_users) sudo_users = stdout.read().decode().strip().split(",") @@ -146,20 +155,20 @@ def get_admin_users(serveur): return admin_users def check_ldap_users(serveur): - """Vérifie si des utilisateurs administrateurs sont définis dans LDAP.""" + """Checks if administrator accounts are defined in LDAP.""" command_ldap_users = "getent passwd | awk -F: '$1 ~ /^ldap/ {print $1}'" stdin, stdout, stderr = serveur.exec_command(command_ldap_users) ldap_users = sorted(list(filter(None, stdout.read().decode().strip().split("\n")))) return ldap_users def verify_account_separation(serveur): - """Vérifie que les comptes système et administrateurs ne sont pas mélangés et retourne les éléments détectés.""" + """Checks that system and administrator accounts are not mixed and returns detected elements.""" local_users = get_local_users(serveur) system_users = get_system_users(serveur) admin_users = get_admin_users(serveur) ldap_users = check_ldap_users(serveur) - # Initialisation du rapport des éléments détectés + # Initialize report for detected elements detected_elements = { "local_users": local_users, "system_users": system_users, @@ -167,39 +176,103 @@ def verify_account_separation(serveur): "ldap_users": ldap_users } - # Vérifications des incohérences + # Check for inconsistencies issues = [] - # Vérifier si des comptes admin sont aussi des comptes système + # Check if admin accounts are also system accounts overlapping_admin_system = set(admin_users) & set(system_users) if overlapping_admin_system: - issues.append(f"Comptes admin présents parmi les comptes système : {', '.join(overlapping_admin_system)}") + issues.append(f"Admin accounts found among system accounts: {', '.join(overlapping_admin_system)}") - # Vérifier si des comptes LDAP sont aussi des comptes système + # Check if LDAP accounts are also system accounts overlapping_ldap_system = set(ldap_users) & set(system_users) if overlapping_ldap_system: - issues.append(f"Comptes LDAP présents parmi les comptes système : {', '.join(overlapping_ldap_system)}") + issues.append(f"LDAP accounts found among system accounts: {', '.join(overlapping_ldap_system)}") - # Vérifier si des comptes admin sont aussi présents dans LDAP + # Check if admin accounts are also in LDAP overlapping_admin_ldap = set(admin_users) & set(ldap_users) if overlapping_admin_ldap: - issues.append(f"Comptes admin présents dans LDAP : {', '.join(overlapping_admin_ldap)}") + issues.append(f"Admin accounts found in LDAP: {', '.join(overlapping_admin_ldap)}") - # Vérifier si des comptes locaux sont administrateurs + # Check if local accounts have admin privileges overlapping_local_admin = set(local_users) & set(admin_users) if overlapping_local_admin: - issues.append(f"Comptes locaux ayant des privilèges admin : {', '.join(overlapping_local_admin)}") + issues.append(f"Local accounts with admin privileges: {', '.join(overlapping_local_admin)}") - # Retourne les éléments détectés avec une liste vide pour les incohérences si conforme + # Return detected elements with an empty list for issues if compliant return detected_elements, issues +# R69 - Secure access to remote user databases +def check_remote_user_database_security(server, reference_data): + """Retrieves security-related information about remote user databases (R69) and ensures compliance.""" + + # Load expected values from reference_moyen.yaml + expected_values = reference_data.get("R69", {}).get("expected", {}) + + # Check if NSS uses a remote database (LDAP or SSSD) + command_nsswitch = "grep -E '^(passwd|group|shadow):' /etc/nsswitch.conf | awk '{for (i=2; i<=NF; i++) print $i}' | sort -u" + stdin, stdout, stderr = server.exec_command(command_nsswitch) + nss_sources = stdout.read().decode().strip().split("\n") + + # Ensure the list does not contain empty elements + nss_sources = [src.strip() for src in nss_sources if src.strip()] + + # Detect if a remote user database is being used (compare with expected values) + uses_remote_db = expected_values.get("uses_remote_db", "None") if expected_values.get("uses_remote_db") in nss_sources else "None" + + if uses_remote_db == "None": + print("No remote user database detected.") + return { + "uses_remote_db": "None", + "secure_connection": "Not applicable", + "binddn_user": "Not applicable", + "limited_rights": "Not applicable" + } + + # Check if TLS is enabled to secure the LDAP/SSSD connection + command_tls = "grep -i 'tls' /etc/ldap/ldap.conf /etc/sssd/sssd.conf 2>/dev/null | grep -v '^#' | awk -F':' '{print $2}' | sed 's/^[ \t]*//g' | sort -u" + stdin, stdout, stderr = server.exec_command(command_tls) + tls_config = stdout.read().decode().strip().split("\n") + + # Ensure TLS compliance: accept start_tls, ssl, or a TLS certificate configuration + expected_tls = expected_values.get("secure_connection", "").lower() + secure_connection = "None" + if expected_tls in ["start_tls", "ssl"] and any(expected_tls in item.lower() for item in tls_config): + secure_connection = expected_tls + elif "TLS_CACERT" in " ".join(tls_config) or "TLS_REQCERT" in " ".join(tls_config): + secure_connection = "tls" # Accept if TLS certificates are set + + # Retrieve the bind user for LDAP/SSSD + command_binddn = "grep -i 'bind' /etc/sssd/sssd.conf /etc/ldap/ldap.conf 2>/dev/null | awk -F'=' '{print substr($0, index($0,$2))}' | sed 's/^[ \t]*//g'" + stdin, stdout, stderr = server.exec_command(command_binddn) + binddn_user = stdout.read().decode().strip() + + # If binddn_user is empty, set it to "Not defined" + if not binddn_user: + binddn_user = "Not defined" + + # Ensure the bind user matches the expected value + expected_binddn = expected_values.get("binddn_user", "") + binddn_user_status = binddn_user if binddn_user == expected_binddn else "Not properly defined" + + # Check if the account has limited rights (compare with expected values) + expected_rights = expected_values.get("limited_rights", "") + limited_rights = expected_rights if "service_account" in binddn_user.lower() else "No" + + return { + "uses_remote_db": uses_remote_db, + "secure_connection": secure_connection, + "binddn_user": binddn_user_status, # Only one field for the bind user check + "limited_rights": limited_rights + } + -# Fonction d'enregistrement des rapports +# Save YAML reports def save_yaml_report(data, output_file): - """Enregistre les données d'analyse dans un fichier YAML dans le dossier dédié.""" + """Saves analysis data to a YAML file in the dedicated folder.""" output_dir = "GenerationRapport/RapportAnalyse" os.makedirs(output_dir, exist_ok=True) output_path = os.path.join(output_dir, output_file) with open(output_path, "w", encoding="utf-8") as file: yaml.dump(data, file, default_flow_style=False, allow_unicode=True) - print(f"Rapport généré : {output_path}") + print(f"Report generated: {output_path}") diff --git a/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml b/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml index 24e8b76..1627277 100644 --- a/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml +++ b/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml @@ -1,37 +1,146 @@ -R34: # Désactiver les comptes de service non utilisés -appliquer: false -status: Non conforme -éléments_attendus: [] -éléments_detectés: -- daemon -- bin -- sys -- sync -- games -- man -- lp -- mail -- news -- uucp -- proxy -- www-data -- backup -- list -- irc -- gnats -- systemd-network -- systemd-resolve -- systemd-timesync -- messagebus -- syslog -- _apt -- tss -- uuidd -- tcpdump -- sshd -- landscape -- pollinate -- fwupd-refresh -- systemd-coredump -- lxd -- postfix +R34: + appliquer: false + rule_id: R34 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - daemon + - bin + - sys + - sync + - games + - man + - lp + - mail + - news + - uucp + - proxy + - www-data + - backup + - list + - irc + - gnats + - systemd-network + - systemd-resolve + - systemd-timesync + - messagebus + - syslog + - _apt + - tss + - uuidd + - tcpdump + - sshd + - landscape + - pollinate + - fwupd-refresh + - systemd-coredump + - lxd + - postfix + - openldap + - sssd + - nslcd +R39: + appliquer: false + rule_id: R39 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + présentes: + - "Defaults\tenv_reset" + - "Defaults\tsecure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin\"" + - "Defaults\tmail_badpass" +R40: + appliquer: false + rule_id: R40 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - '%admin' + - user1 + - user2 + - user1 + - user3 + - user4 + - user3 + - user1 +R42: + appliquer: true + rule_id: R42 + status: Conforme + éléments_attendus: Non spécifié + éléments_detectés: [] +R43: + appliquer: false + rule_id: R43 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - user1 ALL=(ALL) /bin/cat * + - user1 ALL=(ALL) /usr/bin/vi /etc/config.conf + - user4 ALL=(ALL) /bin/cp /tmp/file /backup/ +R44: + appliquer: false + rule_id: R44 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - user1 ALL=(ALL) /usr/bin/vi /etc/config.conf +R50: + appliquer: false + rule_id: R50 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - /etc/shadow 640 + - /etc/gshadow 640 + - /etc/ssh/sshd_config 644 + - /etc/cron.d 755 + - /etc/cron.daily 755 + - /etc/cron.hourly 755 + - /etc/cron.monthly 755 + - /etc/cron.weekly 755 +R52: + appliquer: false + rule_id: R52 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - '/run/systemd/journal/socket - permissions incorrectes: srw-rw-rw-' + - '/run/systemd/notify - permissions incorrectes: srwxrwxrwx' + - '/run/dbus/system_bus_socket - permissions incorrectes: srw-rw-rw-' + - 'Sockets non référencées détectées: /run/systemd/journal/dev-log, public/cleanup, + public/pickup, Local, *, private/rewrite, /run/systemd/journal/stdout, /var/run/slapd/ldapi' +R55: + appliquer: false + rule_id: R55 + status: Non conforme + éléments_attendus: Non spécifié + éléments_detectés: + - 'Options incorrectes pour /tmp : ' + - Les modules PAM `pam_namespace` ou `pam_mktemp` ne sont pas activés. + - 'Fichiers modifiables par tout le monde détectés :' + - 88 0 crw-rw-rw- 1 nobody nogroup 10, 229 Feb 20 08:44 /dev/fuse + - ' 139 0 crw-rw-rw- 1 nobody nogroup 10, 200 Feb 20 08:44 /dev/net/tun' + - ' 8 0 crw-rw-rw- 1 nobody nogroup 1, 7 Feb 20 08:44 /dev/full' + - ' 5 0 crw-rw-rw- 1 nobody nogroup 1, 3 Feb 20 08:44 /dev/null' + - ' 9 0 crw-rw-rw- 1 nobody nogroup 1, 8 Feb 20 08:44 /dev/random' + - ' 12 0 crw-rw-rw- 1 nobody nogroup 5, 0 Feb 21 08:22 /dev/tty' + - ' 10 0 crw-rw-rw- 1 nobody nogroup 1, 9 Feb 20 08:44 /dev/urandom' + - ' 7 0 crw-rw-rw- 1 nobody nogroup 1, 5 Feb 20 08:44 /dev/zero' + - ' 2 0 crw-rw-rw- 1 root root 5, 2 Feb 21 08:22 /dev/ptmx' + - ' 69220 0 -rw-rw-rw- 1 nobody nogroup 0 Feb 20 09:29 /proc/sys/kernel/ns_last_pid' +R67: + appliquer: false + rule_id: R67 + status: Non conforme + éléments_attendus: + detected_pam_modules: pam_ldap + security_modules: + pam_faillock: Enabled + pam_pwquality: Enabled + pam_wheel: Enabled + éléments_detectés: + - 'detected_pam_modules: pam_ldap' + - 'pam_faillock: Non trouvé' + - 'pam_pwquality: Enabled' + - 'pam_wheel: Enabled' diff --git a/GenerationRapport/RapportAnalyse/services_moyen.yml b/GenerationRapport/RapportAnalyse/services_moyen.yml index ae246f8..169aeb5 100644 --- a/GenerationRapport/RapportAnalyse/services_moyen.yml +++ b/GenerationRapport/RapportAnalyse/services_moyen.yml @@ -2,8 +2,8 @@ R35: apply: false description: Use unique and exclusive service accounts detected_elements: - - 2 postfix - - 22 root + - 7 postfix + - 23 root - 2 systemd+ - 9 ubuntu expected_elements: [] diff --git a/GenerationRapport/RapportAnalyse/system_moyen.yml b/GenerationRapport/RapportAnalyse/system_moyen.yml index 0358cf4..e151871 100644 --- a/GenerationRapport/RapportAnalyse/system_moyen.yml +++ b/GenerationRapport/RapportAnalyse/system_moyen.yml @@ -43,7 +43,7 @@ R9: kernel.kptr_restrict: '1' kernel.panic_on_oops: '0' kernel.perf_cpu_time_max_percent: '25' - kernel.perf_event_max_sample_rate: '38000' + kernel.perf_event_max_sample_rate: '40000' kernel.perf_event_paranoid: '4' kernel.pid_max: '4194304' kernel.randomize_va_space: '2' diff --git a/GenerationRapport/RapportAnalyse/users_moyen.yml b/GenerationRapport/RapportAnalyse/users_moyen.yml new file mode 100644 index 0000000..612662e --- /dev/null +++ b/GenerationRapport/RapportAnalyse/users_moyen.yml @@ -0,0 +1,111 @@ +R32: + apply: false + description: Configure automatic session expiration and logind settings + detected_elements: + TMOUT: '18000' + logind_conf: + IdleAction: lock + IdleActionSec: 900s + RuntimeMaxSec: 3600s + expected_elements: + TMOUT: '600' + logind_conf: + IdleAction: lock + IdleActionSec: 900s + RuntimeMaxSec: 3600s + rule_id: R32 + status: Non-compliant +R69: + apply: false + description: Secure access to remote user databases + detected_elements: + detected_elements: + - 'netgroup: nis' + - '' + expected_elements: + - TLS_REQCERT demand + - SSL start_tls + - KRB5_KTNAME /etc/krb5.keytab + - SASL_MECH GSSAPI + status: Non-compliant + expected_elements: + remote_user_database_security: + - No remote user database detected + - TLS_REQCERT demand + - SSL start_tls + - KRB5_KTNAME /etc/krb5.keytab + - SASL_MECH GSSAPI + rule_id: R69 + status: Non-compliant +R70: + apply: false + description: Separate system accounts and administrators from the directory + detected_elements: + admin_users: + - ubuntu + ldap_users: [] + local_users: + - co + - connexion + - nobody + - recent + - ubuntu + system_users: + - _apt + - backup + - bin + - daemon + - fwupd-refresh + - games + - gnats + - irc + - landscape + - list + - lp + - lxd + - mail + - man + - messagebus + - news + - pollinate + - postfix + - proxy + - root + - sshd + - sync + - sys + - syslog + - systemd-coredump + - systemd-network + - systemd-resolve + - systemd-timesync + - tcpdump + - tss + - uucp + - uuidd + - www-data + expected_elements: + admin_users: [] + ldap_users: [] + local_users: [] + system_users: + - root + - daemon + - bin + - sys + - sync + - games + - man + - lp + - mail + - news + - uucp + - proxy + - www-data + - backup + - list + - irc + - gnats + - nobody + rule_id: R70 + status: Non-compliant diff --git a/GenerationRapport/RapportAnalyse/utilisateurs_moyen.yml b/GenerationRapport/RapportAnalyse/utilisateurs_moyen.yml index 6ab776b..60f8c77 100644 --- a/GenerationRapport/RapportAnalyse/utilisateurs_moyen.yml +++ b/GenerationRapport/RapportAnalyse/utilisateurs_moyen.yml @@ -1,47 +1,42 @@ R32: - appliquer: false - rule_id: R32 - status: Non conforme - éléments_attendus: - TMOUT: '600' + apply: false + description: Configure automatic session expiration and logind settings + detected_elements: + TMOUT: '18000' logind_conf: IdleAction: lock IdleActionSec: 900s RuntimeMaxSec: 3600s - éléments_detectés: - TMOUT: '18000' + expected_elements: + TMOUT: '600' logind_conf: IdleAction: lock IdleActionSec: 900s RuntimeMaxSec: 3600s + status: Non-compliant +R69: + apply: true + description: Ensure that NSS is configured securely when using remote user databases. + If using 'sss' (SSSD), 'uses_remote_db' should be 'sss', and 'secure_connection' + must be 'TLS_CACERT'. If using 'ldap', 'uses_remote_db' should be 'ldap', and + 'secure_connection' must be 'start_tls' or 'ssl'. The authentication account ('binddn_user') + must be separate from user accounts and formatted as 'cn=service_account,dc=example'. + The account should have limited privileges ('limited_rights' should be 'Yes' (cn=service_account)). + detected_elements: + binddn_user: cn=service_account,dc=example,dc=com + limited_rights: true + secure_connection: tls + uses_remote_db: sss + expected_elements: + binddn_user: cn=service_account,dc=example,dc=com + limited_rights: true + secure_connection: tls + uses_remote_db: sss + status: Compliant R70: - appliquer: false - rule_id: R70 - status: Non conforme - éléments_attendus: - admin_users: [] - ldap_users: [] - local_users: [] - system_users: - - root - - daemon - - bin - - sys - - sync - - games - - man - - lp - - mail - - news - - uucp - - proxy - - www-data - - backup - - list - - irc - - gnats - - nobody - éléments_detectés: + apply: false + description: Separate system accounts and administrators from the directory + detected_elements: admin_users: - ubuntu ldap_users: [] @@ -68,11 +63,14 @@ R70: - man - messagebus - news + - nslcd + - openldap - pollinate - postfix - proxy - root - sshd + - sssd - sync - sys - syslog @@ -85,3 +83,27 @@ R70: - uucp - uuidd - www-data + expected_elements: + admin_users: [] + ldap_users: [] + local_users: [] + system_users: + - root + - daemon + - bin + - sys + - sync + - games + - man + - lp + - mail + - news + - uucp + - proxy + - www-data + - backup + - list + - irc + - gnats + - nobody + status: Non-compliant From baa26d3060b5f789e10103a68388f67adc2435bb Mon Sep 17 00:00:00 2001 From: Florian Date: Fri, 21 Feb 2025 17:23:09 +0100 Subject: [PATCH 2/2] =?UTF-8?q?ajout=20john.py=20+=20fonction=20pour=20r?= =?UTF-8?q?=C3=A9cup=C3=A9rer=20shadow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RapportAnalyse/gestion_acces_moyen.yml | 26 +-- .../RapportAnalyse/services_moyen.yml | 6 +- .../RapportAnalyse/system_moyen.yml | 2 +- John.py | 175 +++++++++++++++++ hash_files/shadow_copy | 41 ++++ script.py | 183 +++++++++++------- 6 files changed, 341 insertions(+), 92 deletions(-) create mode 100644 John.py create mode 100644 hash_files/shadow_copy diff --git a/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml b/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml index 1627277..0fdc122 100644 --- a/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml +++ b/GenerationRapport/RapportAnalyse/gestion_acces_moyen.yml @@ -47,8 +47,8 @@ R39: éléments_detectés: présentes: - "Defaults\tenv_reset" - - "Defaults\tsecure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin\"" - "Defaults\tmail_badpass" + - "Defaults\tsecure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin\"" R40: appliquer: false rule_id: R40 @@ -108,8 +108,8 @@ R52: - '/run/systemd/journal/socket - permissions incorrectes: srw-rw-rw-' - '/run/systemd/notify - permissions incorrectes: srwxrwxrwx' - '/run/dbus/system_bus_socket - permissions incorrectes: srw-rw-rw-' - - 'Sockets non référencées détectées: /run/systemd/journal/dev-log, public/cleanup, - public/pickup, Local, *, private/rewrite, /run/systemd/journal/stdout, /var/run/slapd/ldapi' + - 'Sockets non référencées détectées: public/cleanup, /var/run/slapd/ldapi, private/rewrite, + Local, /run/systemd/journal/stdout, /run/systemd/journal/dev-log, *, private/local' R55: appliquer: false rule_id: R55 @@ -119,16 +119,16 @@ R55: - 'Options incorrectes pour /tmp : ' - Les modules PAM `pam_namespace` ou `pam_mktemp` ne sont pas activés. - 'Fichiers modifiables par tout le monde détectés :' - - 88 0 crw-rw-rw- 1 nobody nogroup 10, 229 Feb 20 08:44 /dev/fuse - - ' 139 0 crw-rw-rw- 1 nobody nogroup 10, 200 Feb 20 08:44 /dev/net/tun' - - ' 8 0 crw-rw-rw- 1 nobody nogroup 1, 7 Feb 20 08:44 /dev/full' - - ' 5 0 crw-rw-rw- 1 nobody nogroup 1, 3 Feb 20 08:44 /dev/null' - - ' 9 0 crw-rw-rw- 1 nobody nogroup 1, 8 Feb 20 08:44 /dev/random' - - ' 12 0 crw-rw-rw- 1 nobody nogroup 5, 0 Feb 21 08:22 /dev/tty' - - ' 10 0 crw-rw-rw- 1 nobody nogroup 1, 9 Feb 20 08:44 /dev/urandom' - - ' 7 0 crw-rw-rw- 1 nobody nogroup 1, 5 Feb 20 08:44 /dev/zero' - - ' 2 0 crw-rw-rw- 1 root root 5, 2 Feb 21 08:22 /dev/ptmx' - - ' 69220 0 -rw-rw-rw- 1 nobody nogroup 0 Feb 20 09:29 /proc/sys/kernel/ns_last_pid' + - 88 0 crw-rw-rw- 1 nobody nogroup 10, 229 Feb 21 14:01 /dev/fuse + - ' 139 0 crw-rw-rw- 1 nobody nogroup 10, 200 Feb 21 14:01 /dev/net/tun' + - ' 8 0 crw-rw-rw- 1 nobody nogroup 1, 7 Feb 21 14:01 /dev/full' + - ' 5 0 crw-rw-rw- 1 nobody nogroup 1, 3 Feb 21 14:01 /dev/null' + - ' 9 0 crw-rw-rw- 1 nobody nogroup 1, 8 Feb 21 14:01 /dev/random' + - ' 12 0 crw-rw-rw- 1 nobody nogroup 5, 0 Feb 21 15:09 /dev/tty' + - ' 10 0 crw-rw-rw- 1 nobody nogroup 1, 9 Feb 21 14:01 /dev/urandom' + - ' 7 0 crw-rw-rw- 1 nobody nogroup 1, 5 Feb 21 14:01 /dev/zero' + - ' 2 0 crw-rw-rw- 1 root root 5, 2 Feb 21 14:01 /dev/ptmx' + - ' 108106 0 -rw-rw-rw- 1 nobody nogroup 0 Feb 21 15:48 /proc/sys/kernel/ns_last_pid' R67: appliquer: false rule_id: R67 diff --git a/GenerationRapport/RapportAnalyse/services_moyen.yml b/GenerationRapport/RapportAnalyse/services_moyen.yml index 169aeb5..c1f4f09 100644 --- a/GenerationRapport/RapportAnalyse/services_moyen.yml +++ b/GenerationRapport/RapportAnalyse/services_moyen.yml @@ -2,10 +2,10 @@ R35: apply: false description: Use unique and exclusive service accounts detected_elements: - - 7 postfix - - 23 root + - 9 postfix + - 21 root - 2 systemd+ - - 9 ubuntu + - 8 ubuntu expected_elements: [] status: Non-compliant R63: diff --git a/GenerationRapport/RapportAnalyse/system_moyen.yml b/GenerationRapport/RapportAnalyse/system_moyen.yml index e151871..bfc1a65 100644 --- a/GenerationRapport/RapportAnalyse/system_moyen.yml +++ b/GenerationRapport/RapportAnalyse/system_moyen.yml @@ -43,7 +43,7 @@ R9: kernel.kptr_restrict: '1' kernel.panic_on_oops: '0' kernel.perf_cpu_time_max_percent: '25' - kernel.perf_event_max_sample_rate: '40000' + kernel.perf_event_max_sample_rate: '63000' kernel.perf_event_paranoid: '4' kernel.pid_max: '4194304' kernel.randomize_va_space: '2' diff --git a/John.py b/John.py new file mode 100644 index 0000000..9693893 --- /dev/null +++ b/John.py @@ -0,0 +1,175 @@ +import paramiko +import os +import subprocess +import shutil + +# Function to check if John The Ripper is installed +def is_john_installed(): + """Checks if John The Ripper is installed on the system.""" + return shutil.which("john") is not None + +# Function to install John The Ripper +def install_john(): + """Installs John The Ripper from source and configures it for global usage.""" + print("[John] Installing John The Ripper...") + + commands = [ + "sudo apt update && sudo apt install -y build-essential libssl-dev", + "git clone https://github.com/openwall/john.git && cd john/src", + "./configure && make -sj$(nproc)", + "cd ../run && sudo ln -s $(pwd)/john /usr/local/bin/john", # Create a global symlink + "echo \"alias john='$(pwd)/john'\" >> ~/.bashrc && source ~/.bashrc" # Set alias + ] + + try: + for cmd in commands: + subprocess.run(cmd, shell=True, check=True, executable="/bin/bash") + + print("[John] Installation completed successfully!") + + # Verify installation + if is_john_installed(): + print("[John] John The Ripper is successfully installed and ready to use.") + else: + print("[John] Installation completed, but 'john' command is not found. Try running:") + print(" source ~/.bashrc") + print("or restart your terminal.") + + except subprocess.CalledProcessError as e: + print(f"[John] Installation failed: {e}") + +# Function to retrieve hash files from the server +def retrieve_hash_files(serveur): + """Retrieves hash files from the remote server via SSH and stores them locally.""" + hash_files = [] + print("\n[John] Searching for hashed password files on the remote server...") + + # Create a temporary directory on the remote server + temp_dir = "/tmp/hash_extract" + serveur.exec_command(f"mkdir -p {temp_dir} && sudo chmod 777 {temp_dir}") + + # Create a readable copy of /etc/shadow + command_shadow = f"sudo cp /etc/shadow {temp_dir}/shadow_copy && sudo chmod 644 {temp_dir}/shadow_copy" + serveur.exec_command(command_shadow) + + # Ensure the copy exists before retrieving + command_check = f"test -f {temp_dir}/shadow_copy && echo '{temp_dir}/shadow_copy'" + stdin, stdout, stderr = serveur.exec_command(command_check) + shadow_copy_result = stdout.read().decode().strip() + + if shadow_copy_result: + hash_files.append(shadow_copy_result) + + # Find and copy .htpasswd and .htaccess files to the temp directory + command_htpasswd = f"sudo find / -name '.htpasswd' -o -name '.htaccess' 2>/dev/null -exec cp {{}} {temp_dir}/ \\;" + serveur.exec_command(command_htpasswd) + + # List the files in the temp directory + stdin, stdout, stderr = serveur.exec_command(f"ls {temp_dir}") + files_list = stdout.read().decode().strip().split("\n") + + if not files_list or files_list == [""]: + print("[John] No hash files found on the server.") + return + + # Store files locally in the same folder as script.py + local_dir = os.path.dirname(os.path.abspath(__file__)) + "/hash_files/" + os.makedirs(local_dir, exist_ok=True) + + for file in files_list: + remote_file = f"{temp_dir}/{file}" + local_path = os.path.join(local_dir, file) + try: + sftp = serveur.open_sftp() + sftp.get(remote_file, local_path) + print(f"[John] Retrieved: {remote_file} → {local_path}") + except Exception as e: + print(f"[John] Error transferring file {remote_file}: {e}") + finally: + sftp.close() + + # Cleanup: Remove temporary directory and its contents on the remote server + serveur.exec_command(f"sudo rm -rf {temp_dir}") + + print("\n[John] Hash file retrieval completed.") + + +# Function to use John The Ripper +def use_john(): + """Runs John The Ripper locally on retrieved hash files.""" + local_dir = "./hash_files/" + + if not os.path.exists(local_dir) or not os.listdir(local_dir): + print("[John] No hash files found locally. Please retrieve them first using option 4.") + return + + print("\n===== John The Ripper Menu =====") + print("1 - Dictionary Attack") + print("2 - Advanced Rules Attack") + print("3 - Install John The Ripper") + print("4 - Return to Main Menu") + + choice = input("Select an option (1-4): ") + + if choice == "3": + install_john() + return + + if not is_john_installed(): + print("[John] John The Ripper is not installed. Please install it first (option 3).") + return + + hash_files = [os.path.join(local_dir, f) for f in os.listdir(local_dir)] + + if choice == "1": + for file in hash_files: + run_john_dictionary(file) + + elif choice == "2": + for file in hash_files: + run_john_rules(file) + + elif choice == "4": + return + + else: + print("Invalid option, please select a valid choice.") + +# Function to run John The Ripper with a dictionary attack +def run_john_dictionary(local_file): + """Runs John The Ripper in dictionary attack mode.""" + print(f"\n[John] Attempting password cracking with dictionary for: {local_file}") + + command = [ + "john", + "--wordlist=/usr/share/wordlists/rockyou.txt", + "--format=auto", + local_file + ] + + try: + subprocess.run(command, check=True) + print("\n[John] Process completed. Displaying results:") + subprocess.run(["john", "--show", local_file]) + except subprocess.CalledProcessError as e: + print(f"[John] Error during execution: {e}") + +# Function to run John The Ripper with advanced rules +def run_john_rules(local_file): + """Runs John The Ripper with advanced password derivation rules.""" + print(f"\n[John] Attempting password cracking with advanced rules for: {local_file}") + + command = [ + "john", + "--wordlist=/usr/share/wordlists/rockyou.txt", + "--rules=Jumbo", + "--format=auto", + local_file + ] + + try: + subprocess.run(command, check=True) + print("\n[John] Process completed. Displaying results:") + subprocess.run(["john", "--show", local_file]) + except subprocess.CalledProcessError as e: + print(f"[John] Error during execution: {e}") diff --git a/hash_files/shadow_copy b/hash_files/shadow_copy new file mode 100644 index 0000000..ec31a08 --- /dev/null +++ b/hash_files/shadow_copy @@ -0,0 +1,41 @@ +root:*:20115:0:99999:7::: +daemon:*:20115:0:99999:7::: +bin:*:20115:0:99999:7::: +sys:*:20115:0:99999:7::: +sync:*:20115:0:99999:7::: +games:*:20115:0:99999:7::: +man:*:20115:0:99999:7::: +lp:*:20115:0:99999:7::: +mail:*:20115:0:99999:7::: +news:*:20115:0:99999:7::: +uucp:*:20115:0:99999:7::: +proxy:*:20115:0:99999:7::: +www-data:*:20115:0:99999:7::: +backup:*:20115:0:99999:7::: +list:*:20115:0:99999:7::: +irc:*:20115:0:99999:7::: +gnats:*:20115:0:99999:7::: +nobody:*:20115:0:99999:7::: +systemd-network:*:20115:0:99999:7::: +systemd-resolve:*:20115:0:99999:7::: +systemd-timesync:*:20115:0:99999:7::: +messagebus:*:20115:0:99999:7::: +syslog:*:20115:0:99999:7::: +_apt:*:20115:0:99999:7::: +tss:*:20115:0:99999:7::: +uuidd:*:20115:0:99999:7::: +tcpdump:*:20115:0:99999:7::: +sshd:*:20115:0:99999:7::: +landscape:*:20115:0:99999:7::: +pollinate:*:20115:0:99999:7::: +fwupd-refresh:*:20115:0:99999:7::: +systemd-coredump:!!:20129:::::: +ubuntu:$6$FQuWmiCdwyDGuW0C$Goo/BJbmO4MjZN8sx7S4hkrgcLgsLR5qCjITnIBZ8TjEmdSnGMOp8xjEsiEluO3yovx90UYOBJDtrzsRsMb.M0:20132:0:99999:7::: +lxd:!:20129:::::: +connexion:!$6$TZWPRXVSflIyQIR6$OKcbrswAVsJD.PXnIe45Ufsane/0D2nBTX6Dhvym3Ie0izerjdDc5mpu9UGtGHMmUm.PqZzfrb/2NSRiCcPWj0:20129:0:99999:7::0: +co:$6$GCvvMltC7jIKDk4F$/N9aliZxt85jOsm.ij7IZdION5a91zo0ofRgrolS3WpqaOyEQeFeIBeTwD8ARYe7Pq/r/kiYvmZr5H34ksIKQ/:20129:0:99999:7::20059: +recent:$6$RuIB8/85qopRX.Ph$PIZM40CqRDdD3Ku0GATWunEhN58sHuxNuiUi/EFACFNYnyofQbKjaFT0Oh/Sj.eGsiQ7Wt54AQPgono67YvNm1:20131:0:99999:7::: +postfix:*:20137:0:99999:7::: +openldap:!:20139:0:99999:7::: +sssd:*:20139:0:99999:7::: +nslcd:*:20139:0:99999:7::: diff --git a/script.py b/script.py index 08f872a..eb37533 100755 --- a/script.py +++ b/script.py @@ -1,46 +1,48 @@ import sys from Config import load_config, ssh_connect -from AnalyseConfiguration.Analyseur import analyse_SSH, analyse_min +from AnalyseConfiguration.Analyseur import analyse_SSH, analyse_min, analyse_moyen from ApplicationRecommandations.AppRecommandationsSSH import apply_selected_recommendationsSSH from ApplicationRecommandations.AppRecommandationsMin import application_recommandations_min -from AnalyseConfiguration.Analyseur import analyse_SSH, analyse_min, analyse_moyen - -# Fonction pour afficher le menu principal -def afficher_menu(): - print("\n===== Menu Principal =====") - print("1 - Exécuter une analyse") - print("2 - Appliquer les recommandations") - print("3 - Appliquer les recommandations SSH") - print("4 - Quitter") - return input("Sélectionnez une option (1-4) : ") - -# Fonction pour afficher les niveaux d'analyse -def selectionner_niveau_analyse(): - print("\n===== Sélection du niveau d'analyse =====") - print("1 - Analyse globale") - print("2 - Analyse minimale") - print("3 - Analyse intermédiaire") - print("4 - Analyse renforcée") - print("5 - Analyse de la configuration SSH uniquement") - print("6 - Retour au menu principal") - return input("Sélectionnez une option (1-6) : ") - -# Fonction principale du script +from John import install_john, use_john, retrieve_hash_files # Import John The Ripper functions + +# Function to display the main menu +def display_main_menu(): + print("\n===== Main Menu =====") + print("1 - Run an analysis") + print("2 - Apply recommendations") + print("3 - Apply SSH recommendations") + print("4 - Retrieve hash files from server") # Needs SSH connection + print("5 - Use John The Ripper") # Runs John locally + print("6 - Exit") + return input("Select an option (1-6): ") + +# Function to display the analysis levels +def select_analysis_level(): + print("\n===== Select Analysis Level =====") + print("1 - Global analysis") + print("2 - Minimal analysis") + print("3 - Intermediate analysis") + print("4 - Advanced analysis") + print("5 - SSH configuration analysis only") + print("6 - Return to the main menu") + return input("Select an option (1-6): ") + +# Main script function def main(): while True: - choix_menu = afficher_menu() + menu_choice = display_main_menu() - if choix_menu == "1": # Exécuter une analyse - choix_analyse = selectionner_niveau_analyse() + if menu_choice == "1": # Run an analysis + analysis_choice = select_analysis_level() - if choix_analyse in ["1", "2", "3", "4", "5"]: - # Charger la configuration SSH + if analysis_choice in ["1", "2", "3", "4", "5"]: + # Load SSH configuration config = load_config("ssh.yaml") if not config: - print("Configuration invalide") + print("Invalid configuration") continue - # Établir la connexion SSH + # Establish SSH connection client = ssh_connect( hostname=config.get("hostname"), port=config.get("port"), @@ -50,49 +52,49 @@ def main(): ) if not client: - print("Échec de la connexion SSH") + print("SSH connection failed") continue - print("\n--- Début de l'analyse ---\n") + print("\n--- Starting analysis ---\n") - # Lancer l'analyse en fonction du choix de l'utilisateur - if choix_analyse == "1": - print("\n[Analyse] Exécution de l'analyse globale...") - analyse_min(client) # Ajout des analyses futures ici + # Run the analysis based on user selection + if analysis_choice == "1": + print("\n[Analysis] Running global analysis...") + analyse_min(client) # Future analyses can be added here - elif choix_analyse == "2": - print("\n[Analyse] Exécution de l'analyse minimale...") + elif analysis_choice == "2": + print("\n[Analysis] Running minimal analysis...") analyse_min(client) - elif choix_analyse == "3": - print("\n[Analyse] Exécution de l'analyse intermédiaire...") - analyse_moyen(client) # Ajout de l'analyse intermédiaire + elif analysis_choice == "3": + print("\n[Analysis] Running intermediate analysis...") + analyse_moyen(client) # Intermediate analysis - elif choix_analyse == "4": - print("\n[Analyse] Exécution de l'analyse renforcée...") - # Ajouter ici la fonction analyse_renforcee(client) + elif analysis_choice == "4": + print("\n[Analysis] Running advanced analysis...") + # Add the function analyse_renforcee(client) here - elif choix_analyse == "5": - print("\n[Analyse] Exécution de l'analyse SSH uniquement...") + elif analysis_choice == "5": + print("\n[Analysis] Running SSH configuration analysis only...") analyse_SSH(client) - # Fermer la connexion après l'analyse + # Close the connection after analysis client.close() - print("\n--- Fin de l'analyse ---\n") + print("\n--- Analysis complete ---\n") - elif choix_analyse == "6": + elif analysis_choice == "6": continue - elif choix_menu == "2": # Appliquer les recommandations générales - print("\n--- Début de l'application des recommandations générales ---\n") + elif menu_choice == "2": # Apply general recommendations + print("\n--- Starting general recommendations application ---\n") - # Charger la configuration SSH + # Load SSH configuration config = load_config("ssh.yaml") if not config: - print("Configuration invalide") + print("Invalid configuration") continue - # Établir la connexion SSH + # Establish SSH connection client = ssh_connect( hostname=config.get("hostname"), port=config.get("port"), @@ -102,29 +104,27 @@ def main(): ) if not client: - print("Échec de la connexion SSH") + print("SSH connection failed") continue - # Appliquer les recommandations générales (niveau minimal) - #verification d'existance des rapports yaml de chaque thematiques - path_report = "./GenerationRapport/RapportAnalyse/" # Dossier contenant les rapports - + # Apply general recommendations (minimal level) + path_report = "./GenerationRapport/RapportAnalyse/" # Folder containing reports application_recommandations_min(path_report, client) - # Fermer la connexion après application + # Close the connection after application client.close() - print("\n--- Fin de l'application des recommandations générales ---\n") + print("\n--- General recommendations application complete ---\n") - elif choix_menu == "3": # Appliquer les recommandations spécifiques SSH - print("\n--- Début de l'application des recommandations SSH ---\n") + elif menu_choice == "3": # Apply specific SSH recommendations + print("\n--- Starting SSH recommendations application ---\n") - # Charger la configuration SSH + # Load SSH configuration config = load_config("ssh.yaml") if not config: - print("Configuration invalide") + print("Invalid configuration") continue - # Établir la connexion SSH + # Establish SSH connection client = ssh_connect( hostname=config.get("hostname"), port=config.get("port"), @@ -134,23 +134,56 @@ def main(): ) if not client: - print("Échec de la connexion SSH") + print("SSH connection failed") continue - # Appliquer uniquement les recommandations SSH + # Apply only SSH recommendations apply_selected_recommendationsSSH("testRecommandationSSH.yaml", client) - # Fermer la connexion après application + # Close the connection after application + client.close() + print("\n--- SSH recommendations application complete ---\n") + + elif menu_choice == "4": # Retrieve hash files from server + print("\n--- Retrieving hash files from server ---\n") + + # Load SSH configuration + config = load_config("ssh.yaml") + if not config: + print("Invalid configuration") + continue + + # Establish SSH connection + client = ssh_connect( + hostname=config.get("hostname"), + port=config.get("port"), + username=config.get("username"), + key_path=config.get("key_path"), + passphrase=config.get("passphrase") + ) + + if not client: + print("SSH connection failed") + continue + + # Retrieve the hash files + retrieve_hash_files(client) + + # Close SSH connection client.close() - print("\n--- Fin de l'application des recommandations SSH ---\n") + print("\n--- Hash files retrieval complete ---\n") + + elif menu_choice == "5": # Use John The Ripper locally + print("\n--- Running John The Ripper ---\n") + use_john() # Call the John The Ripper module - elif choix_menu == "4": # Quitter - print("Fermeture du programme...") + elif menu_choice == "6": # Exit + print("Exiting program...") sys.exit() else: - print("Option invalide, veuillez choisir une option correcte.") + print("Invalid option, please select a valid choice.") -# Point d'entrée du script +# Script entry point if __name__ == "__main__": main()