Beispiel #1
0
 def path_find_existing(self, dst, as_ip=False):
     if dst in [host.name for host in Host.find_all()]:
         host = Host.find_one(name=dst)
         dst = host.closest_endpoint
     else:
         try:
             dst = Endpoint.find_one(ip_port=dst)
         except:
             print("Please specify a valid endpoint in the IP:PORT form")
             return
     if dst is None:
         print("The endpoint provided doesn't exist in this workspace")
         return
     if Path.direct(dst):
         print("The destination should be reachable from the host")
         return
     try:
         chain = Path.get(dst)
     except NoPathError:
         print("No path could be found to the destination")
         return
     if chain[0] is None:
         chain[0] = "local"
     if as_ip:
         print(" > ".join(str(link.closest_endpoint) \
                 if isinstance(link, Host) else str(link) for link in chain))
     else:
         print(" > ".join(str(link) for link in chain))
Beispiel #2
0
    def host_del(self, host):
        """Remove a :class:`Host` from the workspace

        Args:
            name (str): The `Host` 's username
        """

        if host not in [host.name for host in Host.find_all()]:
            print("Not a known Host name.")
            return False
        host = Host.find_one(name=host)
        self.unstore(host.delete())
        return True
Beispiel #3
0
    def get(cls, dst, first=True):
        """Get the chain of paths from `"Local"` to an `Endpoint`

        Args:
            dst (:class:`Endpoint`): the destination `Endpoint`

        Returns:
            A `List` of :class:`Hosts` forming a chain from `"Local"` to dst

        Raises:
            NoPathError: if no path could be found to `dst`
        """

        try:
            previous_hop = Host.find_one(prev_hop_to=dst)
        except NoPathError as exc:
            raise exc
        if previous_hop is None:
            return [None, dst.host]
        chain = cls.get(previous_hop.closest_endpoint, first=False)
        if first:
            chain.append(dst)
            return chain
        chain.append(dst.host)
        return chain
Beispiel #4
0
 def host_search(self, field, val, show_all=False, add_tag=None):
     hosts = Host.search(field, val, show_all)
     if add_tag is not None:
         for host in hosts:
             for endpoint in host.endpoints:
                 endpoint.tag(add_tag)
     return hosts
Beispiel #5
0
    def find_one(cls,
                 connection_id=None,
                 endpoint=None,
                 scope=None,
                 gateway_to=None):
        """Find a `Connection` by its id, endpoint or if it can be used as a gateway to an :class:`Endpoint`

        Args:
            connection_id (int): the `Connection` id to search
            endpoint (:class:`Endpoint`): the `Connection` endpoint to search
            gateway_to (:class:`Endpoint`): the Endpoint to which you want to find a gateway
            scope (bool): whether to include only in scope Connections (`True`), out of scope Connections (`False`) or both (`None`)

        Returns:
            A single `Connection` or `None`.
        """

        if gateway_to is not None:
            if gateway_to.distance is not None and gateway_to.distance == 0:
                return None
            try:
                closest_host = Host.find_one(prev_hop_to=gateway_to)
            except NoPathError as exc:
                raise exc
            if closest_host is None:
                return None
            return cls.find_one(endpoint=closest_host.closest_endpoint,
                                scope=True)

        cursor = Db.get().cursor()
        if connection_id is not None:
            req = cursor.execute(
                'SELECT endpoint, user, cred FROM connections WHERE id=?',
                (connection_id, ))
        elif endpoint is not None:
            req = cursor.execute(
                'SELECT endpoint, user, cred FROM connections WHERE endpoint=? ORDER BY root ASC',
                (endpoint.id, ))
        else:
            cursor.close()
            return None
        if scope is None:
            row = cursor.fetchone()
            cursor.close()
            if row is None:
                return None
            return Connection(Endpoint.find_one(endpoint_id=row[0]),
                              User.find_one(user_id=row[1]),
                              Creds.find_one(creds_id=row[2]))
        for row in req:
            conn = Connection(Endpoint.find_one(endpoint_id=row[0]),
                              User.find_one(user_id=row[1]),
                              Creds.find_one(creds_id=row[2]))
            if scope == conn.scope:
                cursor.close()
                return conn
        cursor.close()
        return None
Beispiel #6
0
 def path_add(self, src, dst):
     if src.lower() != "local":
         if src not in [host.name for host in Host.find_all()]:
             print("Not a known Host name.")
             return
         src = Host.find_one(name=src)
         if src is None:
             print("The source Host provided doesn't exist in this workspace")
             return
     else:
         src = None
     try:
         dst = Endpoint.find_one(ip_port=dst)
     except:
         print("Please specify valid destination endpoint in the IP:PORT form")
     if dst is None:
         print("The destination endpoint provided doesn't exist in this workspace")
         return
     path = Path(src, dst)
     path.save()
     print("Path saved")
Beispiel #7
0
 def path_del(self, src, dst):
     if str(src).lower() != "local":
         if src not in [host.name for host in Host.find_all()]:
             print("Not a known Host name.")
             return False
         src = Host.find_one(name=src)
         if src is None:
             print("The source Host provided doesn't exist in this workspace")
             return False
     else:
         src = None
     try:
         dst = Endpoint.find_one(ip_port=dst)
     except:
         print("Please specify valid destination endpoint in the IP:PORT form")
     if dst is None:
         print("The destination endpoint provided doesn't exist in this workspace")
         return False
     path = Path(src, dst)
     if path.id is None:
         print("The specified Path doesn't exist in this workspace.")
         return False
     self.unstore(path.delete())
     return True
Beispiel #8
0
    def enum_run(self, target=None):
        if target is not None:
            if '@' not in target:
                host = Host.find_one(name=target)
                if host is not None:
                    conn = Connection.find_one(endpoint=host.closest_endpoint)
                    if conn is not None:
                        return [conn]
                raise ValueError("Supplied value doesn't match a known host or a connection string")

            auth, sep, endpoint = target.partition('@')
            if endpoint == "*":
                endpoint = None
            elif endpoint[0] == "!":
                tag = Tag(endpoint[1:])
                endpoints = tag.endpoints
            else:
                endpoint = Endpoint.find_one(ip_port=endpoint)
                if endpoint is None:
                    raise ValueError("Supplied endpoint isn't in workspace")

            user, sep, cred = auth.partition(":")
            if sep == "":
                raise ValueError("No credentials supplied")
            if user == "*":
                user = None
            else:
                user = User.find_one(name=user)
                if user is None:
                    raise ValueError("Supplied user isn't in workspace")
            if cred == "*":
                cred = None
            else:
                if cred[0] == "#":
                    cred = cred[1:]
                cred = Creds.find_one(creds_id=cred)
                if cred is None:
                    raise ValueError("Supplied credentials aren't in workspace")
        else:
            user = self.options["user"]
            endpoint = self.options["endpoint"]
            cred = self.options["creds"]

        return Connection.find_all(endpoint=endpoint, user=user, creds=cred)
Beispiel #9
0
    def host_untag(self, host, tagname):
        """Remove a :class:`Tag` from an :class:`Host`

        Args:
            host (str): the `Host` 's string (ip:port)
            tagname (str): the :class:`Tag` name
        """

        if tagname[0] == "!":
            tagname = tagname[1:]
        try:
            host = Host.find_one(name=host)
        except ValueError:
            print("Could not find host.")
            return False
        if host is None:
            print("Could not find host.")
            return False
        for endpoint in host.endpoints:
            endpoint.untag(tagname)
        return True
Beispiel #10
0
    def find_one(cls, path_id=None):
        """Find an path by its id

        Args:
            pathId (int): the path id to search

        Returns:
            A single `Path` or `None`.
        """

        if path_id is None:
            return None
        cursor = Db.get().cursor()
        cursor.execute('''SELECT src, dst FROM paths WHERE id=?''',
                       (path_id, ))
        row = cursor.fetchone()
        cursor.close()
        if row is None:
            return None
        return Path(Host.find_one(host_id=row[0]),
                    Endpoint.find_one(endpoint_id=row[1]))
Beispiel #11
0
 def get_objects(self, local=False, hosts=False, connections=False, endpoints=False, \
         users=False, creds=False, tunnels=False, paths=False, scope=None, tags=None):
     ret = []
     if local:
         ret.append("local")
     if hosts:
         ret = ret + Host.find_all(scope=scope)
     if connections:
         ret = ret + Connection.find_all(scope=scope)
     if endpoints:
         ret = ret + Endpoint.find_all(scope=scope)
     if users:
         ret = ret + User.find_all(scope=scope)
     if creds:
         ret = ret + Creds.find_all(scope=scope)
     if tunnels:
         ret = ret + list(self.tunnels.values())
     if paths:
         ret = ret + Path.find_all()
     if tags:
         ret = ret + Tag.find_all()
     return ret
Beispiel #12
0
 def identify_object(self, target):
     if target[0] == "#":
         creds_id = target[1:]
     else:
         creds_id = target
     creds = Creds.find_one(creds_id=creds_id)
     if creds is not None:
         return creds
     user = User.find_one(name=target)
     if user is not None:
         return user
     try:
         dst = Endpoint.find_one(ip_port=target)
         if dst is not None:
             return dst
     except:
         pass
     host = Host.find_one(name=target)
     if host is not None:
         return host
     print("Could not identify object.")
     return None
Beispiel #13
0
    def find_all(cls, src=None, dst=None):
        """Find all Paths

        Args:
            src (:class:`.Host` or `None`): the Host to use as source, `"Local"` if `(int)0`
            dst (:class:`.Endpoint`): the Endpoint to use as destination

        Returns:
            A list of all `Path` s in the :class:`.Workspace`
        """

        if src is not None and src == 0:
            src_id = 0
        elif src is not None:
            src_id = src.id
        ret = []
        cursor = Db.get().cursor()
        if src is None:
            if dst is None:
                req = cursor.execute('SELECT src, dst FROM paths')
            else:
                req = cursor.execute('SELECT src, dst FROM paths WHERE dst=?',
                                     (dst.id, ))
        else:
            if dst is None:
                req = cursor.execute('SELECT src, dst FROM paths WHERE src=?',
                                     (src_id, ))
            else:
                req = cursor.execute('SELECT src, dst FROM paths WHERE src=? AND dst=?', \
                        (src_id, dst.id))
        for row in req:
            ret.append(
                Path(Host.find_one(host_id=row[0]),
                     Endpoint.find_one(endpoint_id=row[1])))
        cursor.close()
        return ret
Beispiel #14
0
    def __init__(self, ip, port):
        #check if ip is actually an IP
        ipaddress.ip_address(ip)
        if not isinstance(port, int) and not port.isdigit():
            raise ValueError("The port is not a positive integer")

        self.ip = ip
        self.__port = port
        self.host = None
        self.id = None
        self.scope = True
        self.reachable = None
        self.distance = None
        self.found = None
        self.tags = set()
        cursor = Db.get().cursor()
        cursor.execute(
            'SELECT id, host, reachable, distance, scope, found FROM endpoints WHERE ip=? AND port=?',
            (self.ip, self.port))
        saved_endpoint = cursor.fetchone()
        if saved_endpoint is not None:
            self.id = saved_endpoint[0]
            self.host = Host.find_one(host_id=saved_endpoint[1])
            if saved_endpoint[2] is None:
                self.reachable = None
            else:
                self.reachable = saved_endpoint[2] != 0
            if saved_endpoint[3] is not None:
                self.distance = saved_endpoint[3]
            self.scope = saved_endpoint[4] != 0
            if saved_endpoint[5] is not None:
                self.found = Endpoint.find_one(endpoint_id=saved_endpoint[5])
            for row in cursor.execute('SELECT name FROM tags WHERE endpoint=?',
                                      (self.id, )):
                self.tags.add(row[0])
        cursor.close()
Beispiel #15
0
    def identify(self):
        #TODO
        """Indentify the host"""
        if self.transport is None:
            raise ConnectionClosedError
        try:
            ######## hostname ########
            chan = self.transport.open_channel("session", timeout=3)
            hostname = ""
            chan.exec_command("hostname")
            try:
                x = u(chan.recv(1024))
                while len(x) != 0:
                    hostname = hostname + x
                    x = u(chan.recv(1024))
            except socket.timeout:
                pass
            chan.close()
            hostname = hostname.rstrip()
            ######## uname ########
            chan = self.transport.open_channel("session", timeout=3)
            uname = ""
            chan.exec_command("uname -a")
            try:
                x = u(chan.recv(1024))
                while len(x) != 0:
                    uname = uname + x
                    x = u(chan.recv(1024))
            except socket.timeout:
                pass
            chan.close()
            uname = uname.rstrip()
            ######## issue ########
            chan = self.transport.open_channel("session", timeout=3)
            issue = ""
            chan.exec_command("cat /etc/issue")
            try:
                x = u(chan.recv(1024))
                while len(x) != 0:
                    issue = issue + x
                    x = u(chan.recv(1024))
            except socket.timeout:
                pass
            chan.close()
            issue = issue.rstrip()
            ######## machineid ########
            chan = self.transport.open_channel("session", timeout=3)
            machine_id = ""
            chan.exec_command("cat /etc/machine-id")
            try:
                x = u(chan.recv(1024))
                while len(x) != 0:
                    machine_id = machine_id + x
                    x = u(chan.recv(1024))
            except socket.timeout:
                pass
            chan.close()
            machine_id = machine_id.rstrip()
            ######## macs ########
            chan = self.transport.open_channel("session", timeout=3)
            mac_str = ""
            chan.exec_command(
                "for i in `ls -l /sys/class/net/ | grep -v virtual | grep 'devices' | tr -s '[:blank:]' | cut -d ' ' -f 9 | sort`; do ip l show $i | grep ether | tr -s '[:blank:]' | cut -d ' ' -f 3; done"
            )
            try:
                x = u(chan.recv(1024))
                while len(x) != 0:
                    mac_str = mac_str + x
                    x = u(chan.recv(1024))
            except socket.timeout:
                pass
            mac_str = mac_str.rstrip()
            macs = mac_str.split()
            chan.close()

            ######## host ########
            new_host = Host(hostname, uname, issue, machine_id, macs)
            if new_host.id is None:
                print("\t" + str(self) + " is a new host: " + new_host.name)
            else:
                print("\t" + str(self) + " is an existing host: " +
                      new_host.name)
                if not new_host.scope:
                    self.endpoint.scope = False
            new_host.save()
            self.endpoint.host = new_host
            self.endpoint.save()
        except Exception as exc:
            print("Error : " + str(exc))
            return False
        return True
Beispiel #16
0
    def enum_connect(self, target=None, force=False, unprobed=False):
        if target is not None:
            if '@' not in target:
                host = Host.find_one(name=target)
                if host is not None:
                    conn = Connection.find_one(endpoint=host.closest_endpoint)
                    if conn is not None:
                        return [conn]
                raise ValueError("Supplied value doesn't match a known host or a connection string")

            auth, sep, endpoint = target.partition('@')
            if endpoint == "*":
                endpoints = Endpoint.find_all(scope=True)
            elif endpoint[0] == "!":
                tag = Tag(endpoint[1:])
                endpoints = tag.endpoints
            else:
                endpoint = Endpoint.find_one(ip_port=endpoint)
                if endpoint is None:
                    raise ValueError("Supplied endpoint isn't in workspace")
                endpoints = [endpoint]

            user, sep, cred = auth.partition(":")
            if sep == "":
                raise ValueError("No credentials supplied")
            if user == "*":
                users = User.find_all(scope=True)
            else:
                user = User.find_one(name=user)
                if user is None:
                    raise ValueError("Supplied user isn't in workspace")
                users = [user]
            if cred == "*":
                creds = Creds.find_all(scope=True)
            else:
                if cred[0] == "#":
                    cred = cred[1:]
                cred = Creds.find_one(creds_id=cred)
                if cred is None:
                    raise ValueError("Supplied credentials aren't in workspace")
                creds = [cred]
            if len(endpoints)*len(users)*len(creds) == 1:
                return [Connection(endpoints[0], users[0], creds[0])]
        else:
            user = self.options["user"]
            if user is None:
                users = User.find_all(scope=True)
            else:
                users = [user]
            endpoint = self.options["endpoint"]
            if isinstance(endpoint, Tag):
                endpoints = endpoint.endpoints
            elif endpoint is None:
                endpoints = Endpoint.find_all(scope=True)
            else:
                endpoints = [endpoint]
            cred = self.options["creds"]
            if cred is None:
                creds = Creds.find_all(scope=True)
            else:
                creds = [cred]
            if len(endpoints)*len(users)*len(creds) == 1:
                return [Connection(endpoints[0], users[0], creds[0])]

        ret = []
        for endpoint in endpoints:
            if not unprobed and not endpoint.reachable:
                continue
            for user in users:
                if len(creds) != 1:
                    working_connections = Connection.find_all(endpoint=endpoint, user=user)
                    if not force and working_connections:
                        print("Connection already found with user "+str(user)+" on endpoint "+str(endpoint)+", creds bruteforcing is disabled. Specify creds or use --force.")
                        continue
                for cred in creds:
                    conn = Connection(endpoint, user, cred)
                    if force:
                        ret.append(conn)
                    else:
                        if conn.id is None:
                            ret.append(conn)
        return ret
Beispiel #17
0
    def probe(self, targets, gateway="auto", verbose=False, find_new=False):
        for endpoint in targets:
            print("Probing \033[1;34m"+str(endpoint)+"\033[0m > ", end="", flush=True)
            if verbose:
                print("")

            conn = Connection(endpoint, None, None)
            working = False
            if not find_new and endpoint.reachable and str(gateway) == "auto":
                if verbose:
                    print("\nEndpoint is supposed to be reachable, trying...")
                working = conn.probe(verbose=verbose)
                host = Host.find_one(prev_hop_to=endpoint)
            if not working and str(gateway) != "auto":
                if verbose:
                    print("\nA gateway was given, trying...")
                if gateway == "local":
                    gateway_conn = None
                    host = None
                else:
                    host = Host.find_one(name=gateway)
                    gateway_conn = Connection.find_one(endpoint=host.closest_endpoint)
                try:
                    working = conn.probe(gateway=gateway_conn, verbose=verbose)
                except ConnectionClosedError as exc:
                    print("\nError: "+str(exc))
                    return
            if not working and not find_new:
                try:
                    Path.get(endpoint)
                except NoPathError:
                    pass
                else:
                    if verbose:
                        print("\nThere is an existing path to the Endpoint, trying...")
                    working = conn.probe(verbose=verbose)
                    host = Host.find_one(prev_hop_to=endpoint)
                    if not working and host is not None:
                        self.path_del(host, endpoint)
            if not working:
                if verbose:
                    print("\nTrying to reach directly from local...")
                host = None
                working = conn.probe(gateway=None, verbose=verbose)
            if not working:
                if verbose:
                    print("\nTrying from every Host from closest to furthest...")
                hosts = Host.find_all(scope=True)
                hosts.sort(key=lambda h: h.distance)
                working = False
                for host in hosts:
                    gateway_endpoint = host.closest_endpoint
                    loop_gateway = Connection.find_one(endpoint=gateway_endpoint)
                    working = conn.probe(gateway=loop_gateway, verbose=verbose)
                    if working:
                        break

            if working:
                path = Path(host, endpoint)
                path.save()
                if host is None:
                    print("\033[1;32mOK\033[0m: reached directly from \033[1;34mlocal\033[0m.")
                else:
                    print("\033[1;32mOK\033[0m: reached using \033[1;34m"+str(host)+"\033[0m as gateway")
            else:
                print("\033[1;31mKO\033[0m: could not reach the endpoint.")
            if verbose:
                print("########################\n")