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
def creds_add(self, creds_type, stmt): """Add :class:`Creds` to the workspace Args: creds_type (str): The `Creds` ' object type stmt (`argparse.Namespace`): the rest of the command be parsed by the object """ content = Extensions.auths[creds_type].fromStatement(stmt) new_creds = Creds(creds_type, content) new_creds.save() return new_creds.id
def from_target(cls, arg): if '@' in arg and ':' in arg: auth, sep, endpoint = arg.partition('@') 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") user = User.find_one(name=user) if user is None: raise ValueError("Supplied user isn't in workspace") 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") return Connection(endpoint, user, cred) if ':' not in arg: arg = arg + ':22' endpoint = Endpoint.find_one(ip_port=arg) if endpoint is None: raise ValueError("Supplied endpoint isn't in workspace") connection = cls.find_one(endpoint=endpoint) if connection is None: raise ValueError("No working connection for supplied endpoint") return connection
def creds_edit(self, creds_id): """Edit a :class:`Creds` ' properties Args: creds_id (str): The `Creds` ' id """ if creds_id[0] == '#': creds_id = creds_id[1:] creds = Creds.find_one(creds_id=creds_id) if creds is None: print("Specified creds not found") return creds.edit()
def creds_del(self, creds_id): """Delete a :class:`Creds` ' from the workspace Args: creds_id (str): The `Creds` ' id """ if creds_id[0] == '#': creds_id = creds_id[1:] creds = Creds.find_one(creds_id=creds_id) if creds is None: print("Specified creds not found") return False if self.options["creds"] == creds: self.set_option("creds", None) self.unstore(creds.delete()) return True
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)
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
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
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
def set_option(self, option, value): """Set an option for the `Workspace` Args: option (str): the option to set value (str): the new value """ if option == 'connection': if value is None: self.options['endpoint'] = None self.options['user'] = None self.options['creds'] = None print("endpoint => "+str(self.options['endpoint'])) print("user => "+str(self.options['user'])) print("creds => "+str(self.options['creds'])) elif '@' not in value or ':' not in value: return connection = Connection.from_target(value) if connection is None: return self.options['endpoint'] = connection.endpoint self.options['user'] = connection.user self.options['creds'] = connection.creds print("endpoint => "+str(self.options['endpoint'])) print("user => "+str(self.options['user'])) print("creds => "+str(self.options['creds'])) return if not option in list(self.options.keys()): raise ValueError(option+" isn't a valid option.") if value is not None: value = value.strip() if option == "endpoint": if value[0] == "!": value = Tag(value[1:]) else: endpoint = Endpoint.find_one(ip_port=value) if endpoint is None: raise ValueError value = endpoint elif option == "user": user = User.find_one(name=value) if user is None: raise ValueError value = user elif option == "creds": if value[0] == '#': creds_id = value[1:] else: creds_id = value creds = Creds.find_one(creds_id=creds_id) if creds is None: raise ValueError value = creds elif option == "payload": value = Extensions.payloads[value] self.options[option] = value else: self.options[option] = None print(option+" => "+str(self.options[option]))
def find_all(cls, endpoint=None, user=None, creds=None, scope=None): """Find all `Connection` matching the criteria If two or more arguments are specified, the returned Connections must match each ("AND") Args: endpoint (:class:`Endpoint` or :class:`Tag`): the `Connection` endpoint to search or a :class:`Tag` of endpoints to search user (:class:`User`): the `Connection` user to search creds (:class:`Creds`): the `Connection` creds to search scope (bool): whether to include only in scope Connections (`True`), out of scope Connections (`False`) or both (`None`) Returns: A list of matching `Connection`. """ ret = [] cursor = Db.get().cursor() query = 'SELECT endpoint, user, cred FROM connections' params = [] first = True if endpoint is not None and not isinstance(endpoint, Tag): if first: query = query + ' WHERE ' first = False else: query = query + ' AND ' query = query + 'endpoint=?' params.append(endpoint.id) elif endpoint is not None and isinstance(endpoint, Tag): if first: query = query + ' WHERE (' first = False else: query = query + ' AND (' first_endpoint = True for end in endpoint.endpoints: if not first_endpoint: query = query + ' OR ' else: first_endpoint = False query = query + 'endpoint=?' params.append(end.id) query = query + ' )' if user is not None: if first: query = query + ' WHERE ' first = False else: query = query + ' AND ' query = query + 'user=?' params.append(user.id) if creds is not None: if first: query = query + ' WHERE ' first = False else: query = query + ' AND ' query = query + 'cred=?' params.append(creds.id) req = cursor.execute(query, tuple(params)) 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 is None or conn.scope == scope: ret.append(conn) cursor.close() return ret
def run(cls, stmt, workspace): outfile = getattr(stmt, 'output') findings = getattr(stmt, 'findings', False) dotcode = 'digraph compromission_graph {\nnode [shape=plain,fontname="monospace"];\nrankdir="LR";\n' for endpoint in workspace.get_objects(endpoints=True, scope=True): label = "<table cellborder='1' cellspacing='0'><tr><td>" + str( endpoint) + "</td></tr>" if endpoint.host is not None: label = label + '<tr><td>' + str(endpoint.host) + '</td></tr>' if findings: foundEndpoints = Endpoint.find_all(found=endpoint, scope=True) foundUsers = User.find_all(found=endpoint, scope=True) foundCreds = Creds.find_all(found=endpoint, scope=True) if foundEndpoints or foundUsers or foundCreds: label = label + "<tr><td><table cellborder='1' cellspacing='0'><tr><td colspan='2'>Findings</td></tr>" if foundEndpoints: label = label + '<tr><td>Endpoints</td><td>' first = True for foundEndpoint in foundEndpoints: if not first: label = label + '<br />' else: first = False label = label + str(foundEndpoint) label = label + '</td></tr>' if foundUsers: label = label + '<tr><td>Users</td><td>' first = True for user in foundUsers: if not first: label = label + '<br />' else: first = False label = label + str(user) label = label + '</td></tr>' if foundCreds: label = label + '<tr><td>Creds</td><td>' first = True for cred in foundCreds: if not first: label = label + '<br />' else: first = False label = label + str(cred) label = label + '</td></tr>' label = label + "</table></td></tr>" label = label + "</table>" dotcode = dotcode + 'node_' + str( endpoint.id) + ' [label=<' + label + '>]\n' if endpoint.found is None: dotcode = dotcode + '"local" -> "node_' + str( endpoint.id) + '"\n' else: dotcode = dotcode + '"node_' + str( endpoint.found.id) + '" -> "node_' + str( endpoint.id) + '"\n' dotcode = dotcode + '}' with open(outfile, "w") as f: f.write(dotcode) print("Export saved as " + outfile) return True