Ejemplo n.º 1
0
def get_existing_port(interface_name):
    port = 0
    ports = RCPortChecker().search_interface_ports_by_name(interface_name)
    if ports is not None:
        ports = [i for i in ports.keys() if i > 0]
        if ports is not None and len(ports):
            port = min(ports)
    return port
class RCDeploymentChecker:
	def __init__(self, debug):
		self.debug = debug
		self.interfaces_to_check = {}
		self.remote_interfaces = {}
		self.suspicious_interfaces = {}
		self.rcpc = RCPortChecker()

	def parse_deployment_file(self, path):
		if self.debug:
			print("[+] Parsing %s" % path)
		tree = ET.ElementTree(file=path)
		root = tree.getroot()
		if root.tag != "rcmanager":
			print("[!] It's not valid deployment file")
			sys.exit()
		for node in tree.iterfind('node'):
			endpoint_string = node.attrib["endpoint"]
			# print endpoint_string
			ip = re.findall(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', endpoint_string)
			if "localhost" in endpoint_string.lower() or len(ip) == 0 or "127.0.0.1" in ip[0]:
				if self.debug:
					print("[+] Found local node: %s"%endpoint_string)
				local = True
			else:
				if self.debug:
					print("[+] Found REMOTE node: %s"%endpoint_string)
				local = False
			for upcommand in node.iterfind('upCommand'):
				suspicious = False
				upcommand_string = upcommand.attrib["command"]
				if self.debug:
					print("\t[+] Upcommand: %s"%upcommand_string)
				upcommand_struct = self.parse_upcommand_line(upcommand_string)
				if upcommand_struct is not None:
					config_file_path = upcommand_struct["component_config"]
					if config_file_path is not None and len(config_file_path) > 0:
						if config_file_path[0] != "/":
							if self.debug:
								print("\t[?] Possible relative config file path? %s for endpoint %s" % (
									upcommand_string, endpoint_string))
							suspicious = True
						if local:
							if "/" in config_file_path:
								filename = config_file_path.split("/")[-1]
								name, file_extension = os.path.splitext(filename)
								if name is not None and file_extension is not None:
									if (("config" in name and file_extension == '') or (
											".conf" in file_extension)) and "etc" in config_file_path:
										self.add_to_checkeables(endpoint_string, config_file_path)
									else:
										pass
							else:
								if self.debug:
									print("\t[?] Config file path without \"/\"? upcommand=\"%s\" for endpoint %s" % (
										upcommand_string, endpoint_string))
								suspicious = True
						else:
							self.add_to_remotes(endpoint_string, config_file_path)

						if suspicious is True:
							self.add_to_suspicious(endpoint_string, config_file_path)
							if self.debug:
								print("\t[?] Weird config file name or not found at all %s for endpoint %s" % (
									upcommand_string, endpoint_string))
					else:
						if self.debug:
							print("\t[?] No config file path? upcommand=\"%s\" for endpoint %s" % (
								upcommand_string, endpoint_string))
						suspicious = True

					name = None
					file_extension = None

				else:
					self.add_to_suspicious(endpoint_string, upcommand_string)
		if self.debug:
			print("\n--------\n")

	def add_to_remotes(self, endpoint_string, config_file_path):
		if endpoint_string in self.remote_interfaces:
			self.remote_interfaces[endpoint_string].append(config_file_path)
		else:
			self.remote_interfaces[endpoint_string] = [config_file_path]


	def parse_upcommand_line(self, upcommand_string):
		is_full_path = False
		config_path = None
		upcommand = {}
		if "rcremote" in upcommand_string.lower():
			result = re.match(
				r"rcremote\s+("+RExp.HOST+")\s+(\w+)\s("+RExp.PATH+")\s+("+RExp.COMMAND+")(?:\s+(.*))?",
				upcommand_string)
			if result is not None:
				upcommand["rcremote"] = True
				upcommand["machine"] = result.group(1)
				upcommand["component_name"] = result.group(2)
				upcommand["component_path"] = result.group(3)
				upcommand["component_command"] = result.group(4)
				upcommand["component_config"] = result.group(5)
				if upcommand["component_config"] != None:
					config_path_string = upcommand["component_config"]
					if "--Ice.Config".lower() in config_path_string.lower():
						if "=" in config_path_string:
							upcommand["component_config"] = config_path_string.split("=")[-1]
						else:
							print("[!] Bad formatted string in upcommand. No '=' after --Ice.Config: %s"%(config_path_string))
					upcommand["component_config"] = self.extract_upcommand_config_file_full_path(upcommand)
				return upcommand
			else:
				if self.debug:
					print("Bad rcremote command")
				return None
		elif upcommand_string.strip() == "":
			return None
		else:
			print "WTF!"
			sys.exit()
			# if "/" in config_file_path:
			# 	filename = config_file_path.split("/")[-1]
			# 	name, file_extension = os.path.splitext(filename)
			# else:
			# 	print("\t[?] Config file path without \"/\"? upcommand=\"%s\" for endpoint %s" % (
			# 		upcommand_string, endpoint_string))

	def extract_upcommand_config_file_full_path(self, upcommand):
		config_path = upcommand["component_config"]
		full_path = ""
		if len(config_path) > 0 and config_path[0] == '/':
			return config_path
		else:
			if "etc" in config_path:
				if len(upcommand["component_path"]) > 0:
					full_path = os.path.join(upcommand["component_path"], config_path)

		return full_path

	def print_local_interfaces_check(self):
		for endpoint, paths in self.interfaces_to_check.items():
			endpoint_name = endpoint.split(":")[0]
			endpoint_port = int(re.findall(r'-p\s*(\d+)', endpoint)[0])
			for path in paths:
				result, data = self.check_endpoint_in_config_file(endpoint, path)
				if result == 2:
					matched_port_interface, _ = data
					print((BColors.WARNING + "[?]" + BColors.ENDC +
						   " Need check: Found an interface configured on port " +
						   BColors.OKGREEN + "%d." + BColors.ENDC + " Is " +
						   BColors.OKBLUE + "%s" + BColors.ENDC + " the interface for the endpoint " +
						   BColors.OKBLUE + "%s" + BColors.ENDC + " (%s - %s)") %
						  (endpoint_port,
						   matched_port_interface,
						   endpoint,
						   matched_port_interface,
						   endpoint_name))
				elif result == 0:
					config_port, _ = data
					print("[!] WRONG PORT %s vs %s for endpoint %s in config file %s" % (
						str(endpoint_port), str(config_port), endpoint, path))
				elif result == 1:
					if self.debug:
						print("[+] Matching ports for endpoint %s"%endpoint)
				elif result == -1:
					print((BColors.FAIL+"[!]"+BColors.ENDC+" Not found: Expected path %s for endpoint %s") % (path, endpoint))

	def check_endpoint_in_config_file(self, endpoint, path):
		endpoint_name = endpoint.split(":")[0]
		endpoint_port = int(re.findall(r'-p\s*(\d+)', endpoint)[0])
		if os.path.exists(path) and os.path.isfile(path):
			self.rcpc.clear()
			self.rcpc.parse_config_file(path)
			config_port, config_paths = self.rcpc.search_interface_port_by_name(endpoint_name)
			# Matched
			if config_port is not None and endpoint_port == config_port:
				return 1, [config_port, config_paths]
			else:
				# Not matche
				matched_port_interface, config_paths_2 = self.rcpc.search_interface_by_port(endpoint_port)
				# Look interface in same port
				if matched_port_interface is not None:
					return 2, [matched_port_interface, config_paths_2]
				else:
					return 0, [config_port, config_paths ]
		else:
			return -1, []


	def add_to_suspicious(self, endpoint_string, config_file_path):
		if endpoint_string in self.suspicious_interfaces:
			self.suspicious_interfaces[endpoint_string].append(config_file_path)
		else:
			self.suspicious_interfaces[endpoint_string] = [config_file_path]

	def add_to_checkeables(self, endpoint_string, config_file_path):
		if endpoint_string in self.interfaces_to_check:
			self.interfaces_to_check[endpoint_string].append(config_file_path)
		else:
			self.interfaces_to_check[endpoint_string] = [config_file_path]
	def __init__(self, debug):
		self.debug = debug
		self.interfaces_to_check = {}
		self.remote_interfaces = {}
		self.suspicious_interfaces = {}
		self.rcpc = RCPortChecker()
Ejemplo n.º 4
0
class RCDeploymentChecker:
    def __init__(self, debug=False):
        self.debug = debug
        self.interfaces_to_check = {}
        self.remote_interfaces = {}
        self.suspicious_interfaces = {}
        self.rcpc = RCPortChecker()

    def parse_deployment_file(self, path):
        if self.debug:
            print("[+] Parsing %s" % path)
        # Read the xml file
        tree = ET.ElementTree(file=path)
        root = tree.getroot()

        # Check it's a rcmanager file
        if root.tag != "rcmanager":
            print("[!] It's not valid deployment file")
            sys.exit()

        # Look for nodes of xml file containing endpoints
        for node in tree.iterfind('node'):
            endpoint_string = node.attrib["endpoint"]
            # look for ip on the endpoint string
            ip = re.findall(
                r'(?:(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:[\w\-\_]+\.local))',
                endpoint_string)
            if "localhost" in endpoint_string.lower() or len(
                    ip) == 0 or "127.0.0.1" in ip[0]:
                if self.debug:
                    print("[+] Found local node: %s" % endpoint_string)
                local = True
            else:
                if self.debug:
                    print("[+] Found REMOTE node: %s" % endpoint_string)
                local = False

            # Look for the upcommand strings
            for upcommand in node.iterfind('upCommand'):
                suspicious = False
                upcommand_string = upcommand.attrib["command"]
                if self.debug:
                    print("\t[+] Upcommand: %s" % upcommand_string)
                upcommand_struct = self.parse_upcommand_line(upcommand_string)
                if upcommand_struct is not None:
                    if "component_config" in upcommand_struct:
                        config_file_path = upcommand_struct["component_config"]
                        if config_file_path is not None and len(
                                config_file_path) > 0:
                            if config_file_path[0] != "/":
                                if self.debug:
                                    print(
                                        "\t" + BColors.WARNING + "[?]" +
                                        BColors.ENDC +
                                        " Possible relative config file path? %s for endpoint %s"
                                        % (upcommand_string, endpoint_string))
                                suspicious = True
                            if local:
                                if "/" in config_file_path:
                                    filename = config_file_path.split("/")[-1]
                                    name, file_extension = os.path.splitext(
                                        filename)
                                    if name is not None and file_extension is not None:
                                        if (("config" in name
                                             and file_extension == '') or
                                            (".conf" in file_extension)
                                            ) and "etc" in config_file_path:
                                            self.add_to_checkeables(
                                                endpoint_string,
                                                config_file_path)
                                        else:
                                            pass
                                else:
                                    if self.debug:
                                        print(
                                            "\t" + BColors.WARNING + "[?]" +
                                            BColors.ENDC +
                                            " Config file path without \"/\"? upcommand=\"%s\" for endpoint %s"
                                            % (upcommand_string,
                                               endpoint_string))
                                    suspicious = True
                            else:
                                self.add_to_remotes(endpoint_string,
                                                    config_file_path)

                            if suspicious is True:
                                if self.debug:
                                    print(
                                        "\t" + BColors.WARNING + "[?]" +
                                        BColors.ENDC +
                                        " Weird config file name or not found at all %s for endpoint %s"
                                        % (upcommand_string, endpoint_string))
                        else:
                            if self.debug:
                                print(
                                    "\t" + BColors.WARNING + "[?]" +
                                    BColors.ENDC +
                                    " No config file path? upcommand=\"%s\" for endpoint %s"
                                    % (upcommand_string, endpoint_string))
                            suspicious = True
                    else:
                        if self.debug:
                            print(
                                "\t" + BColors.WARNING + "[?]" + BColors.ENDC +
                                " No config file? \"%s\" upcommand for endpoint %s"
                                % (upcommand_string, endpoint_string))
                        suspicious = True

                    if suspicious:
                        self.add_to_suspicious(endpoint_string,
                                               config_file_path)

                    name = None
                    file_extension = None

                else:
                    self.add_to_suspicious(endpoint_string, upcommand_string)
        if self.debug:
            print("\n--------\n")

    def add_to_remotes(self, endpoint_string, config_file_path):
        if endpoint_string in self.remote_interfaces:
            self.remote_interfaces[endpoint_string].append(config_file_path)
        else:
            self.remote_interfaces[endpoint_string] = [config_file_path]

    # Parse the upcommand line and return it as structured
    def parse_upcommand_line(self, upcommand_string):
        is_full_path = False
        config_path = None
        upcommand = {}
        if "rcremote" in upcommand_string.lower():
            result = re.match(
                r"rcremote\s+(" + RExp.HOST + ")\s+(\w+)\s(" + RExp.PATH +
                ")\s+(" + RExp.COMMAND + ")(?:\s+(.*))?", upcommand_string)
            if result is not None:
                upcommand["rcremote"] = True
                upcommand["machine"] = result.group(1)
                upcommand["component_name"] = result.group(2)
                upcommand["component_path"] = result.group(3)
                upcommand["component_command"] = result.group(4)
                upcommand["component_config"] = result.group(5)
                if ".conf" in upcommand["component_command"]:
                    upcommand["component_config"] = upcommand[
                        "component_command"]
                    upcommand["component_command"] = upcommand[
                        "component_path"]
                    upcommand["component_path"] = ""
                upcommand[
                    "component_config"] = self.extract_upcommand_config_file_full_path(
                        upcommand)
                upcommand[
                    "component_path"] = self.extract_upcommand_component_full_path(
                        upcommand)
                result.group(3)
                return upcommand
            else:
                if self.debug:
                    print((
                        BColors.FAIL +
                        "[!] Failed parsing rcremote command from config file: "
                        + BColors.ENDC + upcommand_string))
                return None
        elif upcommand_string.strip() == "":
            return None
        elif re.match(RExp.PATH, upcommand_string):
            command_parts = upcommand_string.split(" ")
            upcommand["rcremote"] = False
            upcommand["machine"] = "localhost"
            upcommand["component_name"] = command_parts[0].split("/")[-1]
            upcommand["component_path"] = command_parts[0]
            upcommand["component_command"] = command_parts[0]
            if len(command_parts) > 1:
                upcommand["component_config"] = command_parts[1]
                upcommand[
                    "component_config"] = self.extract_upcommand_config_file_full_path(
                        upcommand)
            upcommand[
                "component_path"] = self.extract_upcommand_component_full_path(
                    upcommand)
            return upcommand
        else:
            print("WTF!")
            sys.exit()
        # if "/" in config_file_path:
        # 	filename = config_file_path.split("/")[-1]
        # 	name, file_extension = os.path.splitext(filename)
        # else:
        # 	print("\t[?] Config file path without \"/\"? upcommand=\"%s\" for endpoint %s" % (
        # 		upcommand_string, endpoint_string))

    # def process_config_string(self, config_string):
    # 	result = ""
    # 	if config_string != None:
    # 		config_path_string = config_string
    # 		if "--Ice.Config".lower() in config_path_string.lower():
    # 			if "=" in config_path_string:
    # 				result = config_path_string.split("=")[-1]
    # 			else:
    # 				print("[!] Bad formatted string in upcommand. No '=' after --Ice.Config: %s" % (config_path_string))
    # 		result = self.extract_upcommand_config_file_full_path(upcommand)
    # 	return result

    def extract_upcommand_config_file_full_path(self, upcommand):
        full_path = upcommand["component_config"]
        if full_path is None:
            full_path = ''
        if len(full_path) > 0:
            if "--Ice.Config".lower() in full_path.lower():
                if "=" in full_path:
                    full_path = full_path.split("=")[-1]
            if "etc" in full_path:
                if len(upcommand["component_path"]
                       ) > 0 and upcommand["component_path"][0] == '/':
                    full_path = os.path.join(upcommand["component_path"],
                                             full_path)
        if len(upcommand["component_path"]
               ) > 0 and upcommand["component_path"][0] == '/':
            full_path = os.path.join(upcommand["component_path"], full_path)
        return full_path

    def extract_upcommand_component_full_path(self, upcommand):
        full_path = upcommand["component_path"]
        if len(full_path) == 0 or full_path[0] != "/":
            if "component_config" in upcommand:
                config_path = upcommand["component_config"]
                if len(config_path) > 0 and config_path[
                        0] == '/' and '/etc/' in config_path:
                    print(re.sub(r'.*/etc/.*', '', config_path))
                    full_path = re.sub(r'/etc/.*', '', config_path)
                else:
                    full_path = ''
            else:
                full_path = ''
        return full_path

    def print_local_interfaces_check(self):
        for endpoint, paths in self.interfaces_to_check.items():
            endpoint_name = endpoint.split(":")[0]
            endpoint_port = int(re.findall(r'-p\s*(\d+)', endpoint)[0])
            for path in paths:
                result, data = self.check_endpoint_in_config_file(
                    endpoint, path)
                if result == 2:
                    matched_port_interface, _ = data
                    print(
                        (BColors.WARNING + "[?]" + BColors.ENDC +
                         " Need check: Found an interface configured on port "
                         + BColors.OKGREEN + "%d." + BColors.ENDC + " Is " +
                         BColors.OKBLUE + "%s" + BColors.ENDC +
                         " the interface for the endpoint " + BColors.OKBLUE +
                         "%s" + BColors.ENDC + " (%s - %s)") %
                        (endpoint_port, matched_port_interface, endpoint,
                         matched_port_interface, endpoint_name))
                elif result == 0:
                    config_port, _ = data
                    print(
                        BColors.FAIL + "[!]" + BColors.ENDC +
                        " WRONG PORT %s vs %s for endpoint %s in config file %s"
                        %
                        (str(endpoint_port), str(config_port), endpoint, path))
                elif result == 1:
                    if self.debug:
                        print("[+] Matching ports for endpoint %s" % endpoint)
                elif result == -1:
                    print((BColors.FAIL + "[!]" + BColors.ENDC +
                           " Not found: Expected path %s for endpoint %s") %
                          (path, endpoint))

    def print_remote_interfaces_check(self):
        try:
            import Pyro4
        except:
            print("Pyro4 is needed to check interfaces in remote hosts")
        else:
            for endpoint, paths in self.remote_interfaces.items():
                endpoint_name = endpoint.split(":")[0]
                endpoint_port = int(re.findall(r'-p\s*(\d+)', endpoint)[0])
                endpoint_host = re.findall(r'-h\s*(' + RExp.HOST + ')',
                                           endpoint)[0]
                for path in paths:
                    remote_object = Pyro4.core.Proxy(
                        'PYRO:rcdeploymentchecker@' + endpoint_host + ':9090')
                    try:
                        result, data = remote_object.check_endpoint_in_config_file(
                            endpoint, path)
                    except:
                        print("Could not find remote object for %s" %
                              endpoint_host)
                    else:
                        if result == 2:
                            matched_port_interface, _ = data
                            print((
                                BColors.WARNING + "[?]" + BColors.ENDC +
                                " Need check: Found an interface configured on port "
                                + BColors.OKGREEN + "%d." + BColors.ENDC +
                                " Is " + BColors.OKBLUE + "%s" + BColors.ENDC +
                                " the interface for the endpoint " +
                                BColors.OKBLUE + "%s" + BColors.ENDC +
                                " (%s - %s)") %
                                  (endpoint_port, matched_port_interface,
                                   endpoint, matched_port_interface,
                                   endpoint_name))
                        elif result == 0:
                            config_port, _ = data
                            print(
                                BColors.FAIL + "[!]" + BColors.ENDC +
                                " WRONG PORT %s vs %s for endpoint %s in config file %s"
                                % (str(endpoint_port), str(config_port),
                                   endpoint, path))
                        elif result == 1:
                            if self.debug:
                                print("[+] Matching ports for endpoint %s" %
                                      endpoint)
                        elif result == -1:
                            print(
                                (BColors.FAIL + "[!]" + BColors.ENDC +
                                 " Not found: Expected path %s for endpoint %s"
                                 ) % (path, endpoint))

    def check_endpoint_in_config_file(self, endpoint, path):
        endpoint_name = endpoint.split(":")[0]
        endpoint_port = int(re.findall(r'-p\s*(\d+)', endpoint)[0])
        if os.path.exists(path) and os.path.isfile(path):
            self.rcpc.clear()
            self.rcpc.parse_config_file(path)
            config_port, config_paths = self.rcpc.search_interface_port_by_name(
                endpoint_name)
            # Matched
            if config_port is not None and endpoint_port == config_port:
                return 1, [config_port, config_paths]
            else:
                # Not matche
                matched_port_interface, config_paths_2 = self.rcpc.search_interface_by_port(
                    endpoint_port)
                # Look interface in same port
                if matched_port_interface is not None:
                    return 2, [matched_port_interface, config_paths_2]
                else:
                    return 0, [config_port, config_paths]
        else:
            return -1, []

    def add_to_suspicious(self, endpoint_string, config_file_path):
        if endpoint_string in self.suspicious_interfaces:
            self.suspicious_interfaces[endpoint_string].append(
                config_file_path)
        else:
            self.suspicious_interfaces[endpoint_string] = [config_file_path]

    def add_to_checkeables(self, endpoint_string, config_file_path):
        if endpoint_string in self.interfaces_to_check:
            self.interfaces_to_check[endpoint_string].append(config_file_path)
        else:
            self.interfaces_to_check[endpoint_string] = [config_file_path]

    def listener(self):
        import Pyro4
        Pyro4.Daemon.serveSimple({
            RCDeploymentChecker: 'rcdeploymentchecker',
        },
                                 host="0.0.0.0",
                                 port=9090,
                                 ns=False,
                                 verbose=True)