Exemplo n.º 1
0
    def _graph_shodan(self):
        """Convert the Shodan tables with ports added as Neo4j graph nodes linked to hosts."""
        self.c.execute("SELECT ip_address,port,banner_data,os,organization FROM shodan_host_lookup")
        all_shodan_lookup = self.c.fetchall()
        with click.progressbar(all_shodan_lookup,
                               label="Creating Port nodes",
                               length=len(all_shodan_lookup)) as bar:
            for row in bar:
                query = """
                MATCH (a:IP {Address:'%s'})
                CREATE UNIQUE (b:Port {Number:'%s', OS:'%s', Organization:"%s", Hostname:''})<-[r:HAS_PORT]-(a)
                SET a.Organization = "%s"
                RETURN a,b
                """ % (row[0],row[1],row[3],row[4],row[4])
                helpers.execute_query(self.neo4j_driver,query)

        self.c.execute("SELECT domain,ip_address,port,banner_data,os,hostname FROM shodan_search")
        all_shodan_search = self.c.fetchall()
        with click.progressbar(all_shodan_search,
                               label="Creating Port and IP relationships",
                               length=len(all_shodan_search)) as bar:
            for row in bar:
                query = """
                MATCH (a:Port)<-[:HAS_PORT]-(b:IP {Address:'%s'})
                SET a.Hostname = "%s"
                RETURN a
                """ % (row[1],row[5])
                helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 2
0
    def _update_dns(self):
        """Update domain nodes with DNS information."""
        self.c.execute(
            "SELECT domain,ns_record,a_record,mx_record,txt_record,soa_record,dmarc,vulnerable_cache_snooping FROM dns"
        )
        dns_data = self.c.fetchall()

        with click.progressbar(dns_data,
                               label="Updating Domain nodes with DNS info",
                               length=len(dns_data)) as bar:
            for row in bar:
                query = """
                MATCH (a:Domain {Name:"%s"})
                SET a += {NameServers:"%s", Address:"%s", MXRecords:'%s', TXTRecords:'%s', SOARecords:'%s', DMARC:'%s'}
                RETURN a
                """ % (row[0], row[1], row[2], row[3], row[4], row[5], row[6])
                helpers.execute_query(self.neo4j_driver, query)
                for address in row[2].split(","):
                    query = """
                    MATCH (a:Domain {Name:'%s'})
                    MATCH (b:IP {Address:'%s'})
                    CREATE UNIQUE (a)-[r:RESOLVES_TO]->(b)
                    RETURN a,r,b
                    """ % (row[0], address)
                    helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 3
0
    def _graph_shodan(self):
        """Convert the Shodan tables with ports added as Neo4j graph nodes linked to hosts."""
        self.c.execute(
            "SELECT ip_address,port,banner_data,os,organization FROM shodan_host_lookup"
        )
        all_shodan_lookup = self.c.fetchall()

        for row in all_shodan_lookup:
            query = """
            MATCH (a:IP {Address:'%s'})
            CREATE UNIQUE (b:Port {Number:'%s', OS:'%s', Organization:"%s", Hostname:''})<-[r:HAS_PORT]-(a)
            SET a.Organization = "%s"
            RETURN a,b
            """ % (row[0], row[1], row[3], row[4], row[4])
            helpers.execute_query(self.neo4j_driver, query)

        self.c.execute(
            "SELECT domain,ip_address,port,banner_data,os,hostname FROM shodan_search"
        )
        all_shodan_search = self.c.fetchall()

        for row in all_shodan_search:
            query = """
            MATCH (a:Port)<-[:HAS_PORT]-(b:IP {Address:'%s'})
            SET a.Hostname = "%s"
            RETURN a
            """ % (row[1], row[5])
            helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 4
0
 def _update_rdap(self):
     """Update host nodes with RDAP information."""
     self.c.execute("SELECT ip_address,rdap_source,organization,network_cidr,asn,country_code,robtex_related_domains FROM rdap_data")
     all_rdap = self.c.fetchall()
     with click.progressbar(all_rdap,
                            label="Updating IP nodes with RDAP info",
                            length=len(all_rdap)) as bar:
         for row in bar:
             query = """
             MATCH (a:IP {Address:'%s'})
             SET a += {RDAPSource:'%s', Organization:"%s", CIDR:'%s', ASN:'%s', CountryCode:'%s', RelatedDomains:'%s'}
             RETURN a
             """ % (row[0],row[1],row[2],row[3],row[4],row[5],row[6])
             helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 5
0
 def _update_whois(self):
     """Update domain nodes with WHOIS information."""
     self.c.execute("SELECT domain,registrar,expiration,organization,registrant,admin_contact,tech_contact,address,dns_sec FROM whois_data")
     all_whois = self.c.fetchall()
     with click.progressbar(all_whois,
                            label="Updating Domain nodes with WHOIS info",
                            length=len(all_whois)) as bar:
         for row in bar:
             query = """
             MATCH (a:Domain {Name:'%s'})
             SET a += {Registrar:"%s", Expiration:'%s', Organization:"%s", Registrant:"%s", Admin:"%s", Tech:"%s", ContactAddress:"%s", DNSSEC:'%s'}
             RETURN a
             """ % (row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8])
             helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 6
0
    def _update_rdap(self):
        """Update host nodes with RDAP information."""
        self.c.execute(
            "SELECT ip_address,rdap_source,organization,network_cidr,asn,country_code,robtex_related_domains FROM rdap_data"
        )
        all_rdap = self.c.fetchall()

        for row in all_rdap:
            query = """
            MATCH (a:IP {Address:'%s'})
            SET a += {RDAPSource:'%s', Organization:"%s", CIDR:'%s', ASN:'%s', CountryCode:'%s', RelatedDomains:'%s'}
            RETURN a
            """ % (row[0], row[1], row[2], row[3], row[4], row[5], row[6])
            helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 7
0
    def _update_whois(self):
        """Update domain nodes with whois information."""
        self.c.execute(
            "SELECT domain,registrar,expiration,organization,registrant,admin_contact,tech_contact,address,dns_sec FROM whois_data"
        )
        all_whois = self.c.fetchall()

        for row in all_whois:
            query = """
            MATCH (a:Domain {Name:'%s'})
            SET a += {Registrar:"%s", Expiration:'%s', Organization:"%s", Registrant:"%s", Admin:"%s", Tech:"%s", ContactAddress:"%s", DNSSEC:'%s'}
            RETURN a
            """ % (row[0], row[1], row[2], row[3], row[4], row[5], row[6],
                   row[7], row[8])
            helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 8
0
    def get_all_domains(self, inclusive=False):
        """Fetch and return distinct domains from the BloodHound data set for which there is data.
        If a True value is provided for inclusive then all domains are pulled from the dataset for
        comparison purposes.
        """
        # We fetch groups and then get the domain property for the group. We do this instead
        # of MATCHing on domains, or even users, because pulling domains from those objects
        # may lead to failed queries later due to not enough data about the additional domains.
        # BloodHound may have users from additional domains via foreign group membership, which
        # adds those domains to Domains while no other data about that domain is available.

        # Include ALL domains regardless of info available -- useful for comparisons
        if inclusive:
            query = """
            MATCH (d:Domain)
            RETURN DISTINCT d.name
            """
        # Get only domains for which we have data
        else:
            query = """
            MATCH (g:Group)
            RETURN DISTINCT g.domain
            """

        results = helpers.execute_query(self.neo4j_driver, query)

        domains = []
        for record in results:
            domains.append(record[0])

        return domains
Exemplo n.º 9
0
 def _graph_subdomains(self):
     """Convert the subdomains table into Neo4j graph nodes with relationships to the domain
     and other subdomain nodes.
     """
     self.c.execute(
         "SELECT domain,subdomain,ip_address,domain_frontable FROM subdomains"
     )
     all_subdomains = self.c.fetchall()
     with click.progressbar(all_subdomains,
                            label="Creating Subdomain nodes",
                            length=len(all_subdomains)) as bar:
         # Enforce unique nodes for subdomains
         query = """
         CREATE CONSTRAINT ON (a:Subdomain) ASSERT a.Name IS UNIQUE
         """
         helpers.execute_query(self.neo4j_driver, query)
         # Loop over each subdomain to create nodes
         for row in bar:
             # Start with the full domain info and then split it apart
             # If we have a subdomain of a subdomain we want to create that relationship
             base_domain = row[0]
             subdomain = row[1]
             partial_subdomain = '.'.join(subdomain.split('.')[1:])
             ip_address = row[2]
             domain_frontable = row[3]
             # Create the subdomain node
             query = """
             MERGE (x:Subdomain {Name:'%s'})
             ON CREATE SET x.Address = "%s", x.DomainFrontable = '%s'
             ON MATCH SET x.Address = "%s", x.DomainFrontable = '%s'
             """ % (subdomain, ip_address, domain_frontable, ip_address,
                    domain_frontable)
             helpers.execute_query(self.neo4j_driver, query)
             # Check if the partial subdomain is the base domain
             if partial_subdomain == base_domain:
                 query = """
                 MATCH (b:Domain {Name:'%s'})
                 MERGE (a:Subdomain {Name:'%s'})
                 ON CREATE SET a.Address = "%s", a.DomainFrontable = '%s'
                 MERGE (c:IP {Address:"%s"})
                 MERGE (c)<-[r1:RESOLVES_TO]-(a)<-[r2:HAS_SUBDOMAIN]-(b)
                 RETURN a,b,c
                 """ % (base_domain, subdomain, ip_address,
                        domain_frontable, ip_address)
                 helpers.execute_query(self.neo4j_driver, query)
             # If not, the subdomain is a subdomain of another subdomain, so create that relationship
             else:
                 query = """
                 MERGE (a:Subdomain {Name:'%s'})
                 ON CREATE SET a.Address = "%s", a.DomainFrontable = '%s'
                 MERGE (b:Subdomain {Name:'%s'})
                 MERGE (c:IP {Address:"%s"})
                 MERGE (c)<-[r1:RESOLVES_TO]-(a)<-[r2:HAS_SUBDOMAIN]-(b)
                 RETURN a,b,c
                 """ % (subdomain, ip_address, domain_frontable,
                        partial_subdomain, ip_address)
                 helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 10
0
 def _graph_subdomains(self):
     """Convert the subdomains table into Neo4j graph nodes with relationships to the domain
     and other subdomain nodes.
     """
     self.c.execute("SELECT domain,subdomain,ip_address,domain_frontable FROM subdomains")
     all_subdomains = self.c.fetchall()
     with click.progressbar(all_subdomains,
                            label="Creating Subdomain nodes",
                            length=len(all_subdomains)) as bar:
         # Enforce unique nodes for subdomains
         query = """
         CREATE CONSTRAINT ON (a:Subdomain) ASSERT a.Name IS UNIQUE
         """
         helpers.execute_query(self.neo4j_driver,query)
         # Loop over each subdomain to create nodes
         for row in bar:
             # Start with the full domain info and then split it apart
             # If we have a subdomain of a subdomain we want to create that relationship
             base_domain = row[0]
             subdomain = row[1]
             partial_subdomain = '.'.join(subdomain.split('.')[1:])
             ip_address = row[2]
             domain_frontable = row[3]
             # Create the subdomain node
             query = """
             MERGE (x:Subdomain {Name:'%s'})
             ON CREATE SET x.Address = "%s", x.DomainFrontable = '%s'
             ON MATCH SET x.Address = "%s", x.DomainFrontable = '%s'
             """ % (subdomain,ip_address,domain_frontable,ip_address,domain_frontable)
             helpers.execute_query(self.neo4j_driver,query)
             # Check if the partial subdomain is the base domain
             if partial_subdomain == base_domain:
                 query = """
                 MATCH (b:Domain {Name:'%s'})
                 MERGE (a:Subdomain {Name:'%s'})
                 ON CREATE SET a.Address = "%s", a.DomainFrontable = '%s'
                 MERGE (c:IP {Address:"%s"})
                 MERGE (c)<-[r1:RESOLVES_TO]-(a)<-[r2:HAS_SUBDOMAIN]-(b)
                 RETURN a,b,c
                 """ % (base_domain,subdomain,ip_address,domain_frontable,ip_address)
                 helpers.execute_query(self.neo4j_driver,query)
             # If not, the subdomain is a subdomain of another subdomain, so create that relationship
             else:
                 query = """
                 MERGE (a:Subdomain {Name:'%s'})
                 ON CREATE SET a.Address = "%s", a.DomainFrontable = '%s'
                 MERGE (b:Subdomain {Name:'%s'})
                 MERGE (c:IP {Address:"%s"})
                 MERGE (c)<-[r1:RESOLVES_TO]-(a)<-[r2:HAS_SUBDOMAIN]-(b)
                 RETURN a,b,c
                 """ % (subdomain,ip_address,domain_frontable,partial_subdomain,ip_address)
                 helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 11
0
    def avg_path_length(self, domain):
        """Returns the average number of hops in a path to a Domain Admin in the given domain."""
        query = """
        MATCH p = shortestPath((n {domain:UPPER('%s')})-[r*1..]->(g:Group {name:'DOMAIN ADMINS@%s'}))
        RETURN toInt(AVG(LENGTH(p))) as avgPathLength
        """ % (domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        for record in results:
            return record[0]
Exemplo n.º 12
0
    def get_total_computers(self, domain):
        """Returns the total number of computers in the given domain."""
        query = """
        MATCH (totalComputers:Computer {domain:UPPER('%s')})
        RETURN COUNT(DISTINCT(totalComputers))
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        for record in results:
            return record[0]
Exemplo n.º 13
0
    def get_all_da_paths(self, domain):
        """Returns the number of paths to a Domain Admin that exist for the given domain."""
        query = """
        MATCH p = shortestPath((pathToDAUsers:User {domain:UPPER('%s')})-[r*1..]-> 
        (g:Group {name:UPPER('DOMAIN ADMINS@%s')}))
        RETURN COUNT(DISTINCT(pathToDAUsers))
        """ % (domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        for record in results:
            return record[0]
Exemplo n.º 14
0
    def _graph_certificates(self):
        """Convert the certificates table into Neo4j graph nodes with relationships to the domain
        nodes.
        """
        self.c.execute(
            "SELECT host,subject,issuer,start_date,expiration_date,self_signed,signature_algo,censys_fingerprint,alternate_names FROM certificates"
        )
        all_certificates = self.c.fetchall()

        for row in all_certificates:
            if row[5]:
                self_signed = False
            else:
                self_signed = True
            query = """
            CREATE (a:Certificate {Subject:"%s", Issuer:"%s", StartDate:"%s", ExpirationDate:"%s", SelfSigned:"%s", SignatureAlgo:"%s", CensysFingerprint:"%s"})
            RETURN a
            """ % (row[1], row[2], row[3], row[4], self_signed, row[6], row[7])
            helpers.execute_query(self.neo4j_driver, query)

            alt_names = row[8].split(",")
            for name in alt_names:
                query = """
                MATCH (a:Subdomain {Name:"%s"})
                MATCH (b:Certificate {CensysFingerprint:"%s"})
                MERGE (a)<-[r:ISSUED_FOR]-(b)
                """ % (name.strip(), row[7])
                helpers.execute_query(self.neo4j_driver, query)
                query = """
                MATCH (a:Domain {Name:"%s"})
                MATCH (b:Certificate {CensysFingerprint:"%s"})
                MERGE (a)<-[r:ISSUED_FOR]-(b)
                """ % (name.strip(), row[7])
                helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 15
0
 def _graph_certificates(self):
     """Convert the certificates table into Neo4j graph nodes with relationships to the domain
     nodes.
     """
     self.c.execute("SELECT host,subject,issuer,start_date,expiration_date,self_signed,signature_algo,censys_fingerprint,alternate_names FROM certificates")
     all_certificates = self.c.fetchall()
     with click.progressbar(all_certificates,
                            label="Creating Certificate nodes",
                            length=len(all_certificates)) as bar:
         for row in bar:
             if row[5]:
                 self_signed = False
             else:
                 self_signed = True
             query = """
             CREATE (a:Certificate {Subject:"%s", Issuer:"%s", StartDate:"%s", ExpirationDate:"%s", SelfSigned:"%s", SignatureAlgo:"%s", CensysFingerprint:"%s"})
             RETURN a
             """ % (row[1],row[2],row[3],row[4],self_signed,row[6],row[7])
             helpers.execute_query(self.neo4j_driver,query)
             alt_names = row[8].split(",")
             for name in alt_names:
                 query = """
                 MERGE (a:Subdomain {Name:"%s"})
                 MERGE (b:Certificate {CensysFingerprint:"%s"})
                 MERGE (a)<-[r:ISSUED_FOR]-(b)
                 """ % (name.strip(),row[7])
                 helpers.execute_query(self.neo4j_driver,query)
                 query = """
                 MERGE (a:Domain {Name:"%s"})
                 MERGE (b:Certificate {CensysFingerprint:"%s"})
                 MERGE (a)<-[r:ISSUED_FOR]-(b)
                 """ % (name.strip(),row[7])
                 helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 16
0
    def _graph_hosts(self):
        """Convert the hosts table into Neo4j graph nodes."""
        self.c.execute("SELECT host_address,in_scope_file,source FROM hosts")
        all_hosts = self.c.fetchall()

        for row in all_hosts:
            if row[1] == 0:
                scoped = False
            else:
                scoped = True
            if helpers.is_ip(row[0]):
                query = """
                MERGE (x:IP {Address:'%s', Scoped:'%s', Source:'%s'})
                RETURN x
                """ % (row[0], scoped, row[2])
                helpers.execute_query(self.neo4j_driver, query)
            else:
                query = """
                MERGE (x:Domain {Name:'%s', Scoped:'%s', Source:'%s'})
                RETURN x
                """ % (row[0], scoped, row[2])
                helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 17
0
    def get_admin_groups(self, domain):
        """Get the Domain Admins, Enterprise Admins, and Administrator group members for the
        given domain.
        """
        da_query = """
        MATCH (n:Group) WHERE n.name =~ 'DOMAIN ADMINS@%s'
        WITH n MATCH (n)<-[r:MemberOf*1..]-(m)
        RETURN m.name,r
        """ % domain

        ea_query = """
        MATCH (n:Group) WHERE n.name =~ 'ENTERPRISE ADMINS@%s'
        WITH n MATCH (n)<-[r:MemberOf*1..]-(m)
        RETURN m.name,r
        """ % domain

        admin_query = """
        MATCH (n:Group) WHERE n.name =~ 'ADMINISTRATORS@%s'
        WITH n MATCH (n)<-[r:MemberOf*1..]-(m)
        RETURN m.name,r
        """ % domain

        da_results = helpers.execute_query(self.neo4j_driver, da_query)
        ea_results = helpers.execute_query(self.neo4j_driver, ea_query)
        admin_results = helpers.execute_query(self.neo4j_driver, admin_query)

        domain_admins = []
        for record in da_results:
            domain_admins.append(record[0])

        enterprise_admins = []
        for record in ea_results:
            enterprise_admins.append(record[0])

        admins = []
        for record in admin_results:
            admins.append(record[0])

        return domain_admins, enterprise_admins, admins
Exemplo n.º 18
0
    def _update_dns(self):
        """Update domain nodes with DNS information."""
        self.c.execute("SELECT domain,ns_record,a_record,mx_record,txt_record,soa_record,dmarc,vulnerable_cache_snooping FROM dns")
        dns_data = self.c.fetchall()

        with click.progressbar(dns_data,
                               label="Updating Domain nodes with DNS info",
                               length=len(dns_data)) as bar:
            for row in bar:
                query = """
                MATCH (a:Domain {Name:"%s"})
                SET a += {NameServers:"%s", Address:"%s", MXRecords:'%s', TXTRecords:'%s', SOARecords:'%s', DMARC:'%s'}
                RETURN a
                """ % (row[0],row[1],row[2],row[3],row[4],row[5],row[6])
                helpers.execute_query(self.neo4j_driver,query)
                for address in row[2].split(","):
                    query = """
                    MATCH (a:Domain {Name:'%s'})
                    MATCH (b:IP {Address:'%s'})
                    CREATE UNIQUE (a)-[r:RESOLVES_TO]->(b)
                    RETURN a,r,b
                    """ % (row[0],address)
                    helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 19
0
    def _graph_subdomains(self):
        """Convert the subdomains table into Neo4j graph nodes with relationships to the domain
        nodes.
        """
        self.c.execute(
            "SELECT domain,subdomain,ip_address,domain_frontable FROM subdomains"
        )
        all_subdomains = self.c.fetchall()

        for row in all_subdomains:
            query = """
            MERGE (x:Subdomain {Name:'%s', Address:"%s", DomainFrontable:'%s'})
            """ % (row[1], row[2], row[3])
            helpers.execute_query(self.neo4j_driver, query)

            query = """
            MATCH (a:Subdomain {Name:'%s'})
            MATCH (b:Domain {Name:'%s'})
            MATCH (c:IP {Address:"%s"})
            CREATE UNIQUE (c)<-[r1:RESOLVES_TO]-(a)-[r2:SUBDOMAIN_OF]->(b)
            RETURN a,b,c
            """ % (row[1], row[0], row[2])
            helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 20
0
    def find_blocked_inheritance(self, domain):
        """Finds Active Directory OUs that block inheritance of group policies."""
        query = """
        MATCH (o:OU {domain:'%s'})
        WHERE o.blocksinheritance = True
        RETURN o.name
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        blocker_ous = []
        for record in results:
            blocker_ous.append(record[0])

        return blocker_ous
Exemplo n.º 21
0
    def find_unconstrained_delegation(self, domain):
        """Identifies computers with unconstrained delegation enabled on the given domain."""
        query = """
        MATCH (c:Computer {domain:'%s'})
        WHERE c.unconstraineddelegation = True
        RETURN c.name
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        computers = []
        for record in results:
            computers.append(record[0])

        return computers
Exemplo n.º 22
0
    def count_local_admins(self, domain):
        """Discover the number of local admins for each computer in the domain."""
        query = """
        MATCH p = (u1:User)-[r:MemberOf|AdminTo*1..]->(c:Computer)
        RETURN c.name as computerName,COUNT(DISTINCT(u1)) AS adminCount
        ORDER BY adminCount DESC
        """

        results = helpers.execute_query(self.neo4j_driver, query)

        admin_count = {}
        for record in results:
            admin_count[record[0]] = record[1]

        return admin_count
Exemplo n.º 23
0
 def _graph_hosts(self):
     """Convert the hosts table into Neo4j graph nodes."""
     self.c.execute("SELECT host_address,in_scope_file,source FROM hosts")
     all_hosts = self.c.fetchall()
     with click.progressbar(all_hosts,
                            label="Creating Domain and IP nodes",
                            length=len(all_hosts)) as bar:
         for row in bar:
             if row[1] == 0:
                 scoped = False
             else:
                 scoped = True
             if helpers.is_ip(row[0]):
                 query = """
                 MERGE (x:IP {Address:'%s', Scoped:'%s', Source:'%s'})
                 RETURN x
                 """ % (row[0], scoped, row[2])
                 helpers.execute_query(self.neo4j_driver, query)
             else:
                 query = """
                 MERGE (x:Domain {Name:'%s', Scoped:'%s', Source:'%s'})
                 RETURN x
                 """ % (row[0], scoped, row[2])
                 helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 24
0
    def find_da_spn(self, domain):
        """Identify Domain Admins linked to SPNs."""
        query = """
        MATCH (u:User {domain:'%s'})-[:MemberOf*1..]->(g:Group {name:'DOMAIN ADMINS@%s'})
        WHERE u.hasspn = True
        RETURN u.name
        """ % (domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        has_spn = []
        for record in results:
            has_spn.append(record[0])

        return has_spn
Exemplo n.º 25
0
    def get_all_gpos(self, domain):
        """Get the names of all GPOs for the given domain."""
        query = """
        MATCH (g:GPO {domain:'%s'})
        WHERE NOT (g.name is Null or g.name = "")
        RETURN g.name
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        gpos = []
        for record in results:
            gpos.append(record[0])

        return gpos
Exemplo n.º 26
0
    def find_remote_desktop_users(self, domain):
        """Identify members of the Remote Desktop Users."""
        query = """
        MATCH (n:Group) WHERE n.name = 'REMOTE DESKTOP USERS@%s'
        WITH n MATCH (n)<-[r:MemberOf*1..]-(m)
        RETURN m.name
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        members = []
        for member in results:
            members.append(member[0])

        return members
Exemplo n.º 27
0
 def _graph_hosts(self):
     """Convert the hosts table into Neo4j graph nodes."""
     self.c.execute("SELECT host_address,in_scope_file,source FROM hosts")
     all_hosts = self.c.fetchall()
     with click.progressbar(all_hosts,
                            label="Creating Domain and IP nodes",
                            length=len(all_hosts)) as bar:
         for row in bar:
             if row[1] == 0:
                 scoped = False
             else:
                 scoped = True
             if helpers.is_ip(row[0]):
                 query = """
                 MERGE (x:IP {Address:'%s', Scoped:'%s', Source:'%s'})
                 RETURN x
                 """% (row[0],scoped,row[2])
                 helpers.execute_query(self.neo4j_driver,query)
             else:
                 query = """
                 MERGE (x:Domain {Name:'%s', Scoped:'%s', Source:'%s'})
                 RETURN x
                 """ % (row[0],scoped,row[2])
                 helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 28
0
    def get_operating_systems(self, domain):
        """Get a list of the opreating systems reported for the given domain's computers."""
        query = """
        MATCH (c:Computer {domain:'%s'})
        WHERE NOT (c.operatingsystem = "" or c.operatingsystem is Null)
        RETURN DISTINCT(c.operatingsystem) as OperartingSystems,COUNT(c.operatingsystem) as Total
        ORDER BY Total DESC
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        operating_systems = {}
        for record in results:
            operating_systems[record[0]] = record[1]

        return operating_systems
Exemplo n.º 29
0
    def find_foreign_group_membership(self, domain):
        """Identify users with foregin group memberships."""
        query = """
        MATCH (n:User) 
        WHERE n.name ENDS WITH ('@' + '%s') 
        WITH n 
        MATCH (n)-[r:MemberOf]->(m:Group) 
        WHERE NOT m.name ENDS WITH ('@' + '%s') 
        RETURN n.name,m.name
        """ % (domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        users = {}
        for record in results:
            users[record[0]] = record[1]

        return users
Exemplo n.º 30
0
    def find_local_admin_groups(self, domain):
        """Identify groups that are not built-in Admin groups and have Local Administrator
        privileges.
        """
        query = """
        MATCH (g:Group {domain:'%s'})-[:AdminTo*1..]->(c:Computer)
        WHERE NOT ('DOMAIN ADMINS@%s' in g.name)
        AND NOT ('ENTERPRISE ADMINS@%s' in g.name)
        AND NOT ('ADMINISTRATORS@%s' in g.name)
        RETURN DISTINCT(g.name)
        """ % (domain, domain, domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        groups = []
        for record in results:
            groups.append(record[0])

        return groups
Exemplo n.º 31
0
    def find_old_pwdlastset(self, domain, months=6):
        """Find active users with PwdLastSet dates older than the specified number of months."""
        months_ago = datetime.today() - timedelta(months*365/12)

        query = """
        MATCH (u:User {domain:'%s'})
        RETURN u.name,u.pwdlastset
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        old_passwords = {}
        for record in results:
            timestamp = record[1]
            if timestamp:
                pwdlastset = datetime.fromtimestamp(timestamp)
                if pwdlastset < months_ago:
                    old_passwords[record[0]] = ctime(timestamp)

        return old_passwords
Exemplo n.º 32
0
    def get_systems_with_da(self, domain):
        """Returns a list of computers that are not Domain Controllers and have at least one active
        session for a Domain Admin user.
        """
        query = """
        MATCH (c2:Computer)-[r3:MemberOf*1..]->(g2:Group {name:UPPER('DOMAIN CONTROLLERS@%s')})
        WITH COLLECT(c2.name) as domainControllers
        MATCH (c1:Computer)-[r1:HasSession]->(u1:User)-[r2:MemberOf*1..]->(g1:Group {name:UPPER('DOMAIN ADMINS@%s')})
        WHERE NOT (c1.name IN domainControllers)
        RETURN DISTINCT(c1.name)
        ORDER BY c1.name ASC
        """ % (domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        computers = []
        for record in results:
            computers.append(record[0])

        return computers
Exemplo n.º 33
0
    def find_admin_groups(self, domain):
        """Attempt to find interesting groups with ADMIN in their names. The built-in Domain
        Admins, Enterprise Admins, and Administrator accounts are ignored.
        """
        query = """
        MATCH (g:Group {domain:'%s'})
        WHERE g.name =~ '(?i).*ADMIN.*'
        AND NOT ('DOMAIN ADMINS@%s' in g.name)
        AND NOT ('ENTERPRISE ADMINS@%s' in g.name)
        AND NOT ('ADMINISTRATORS@%s' in g.name)
        RETURN g.name
        """ % (domain, domain, domain, domain)

        results = helpers.execute_query(self.neo4j_driver, query)

        groups = []
        for record in results:
            groups.append(record[0])

        return groups
Exemplo n.º 34
0
    def get_total_users(self, domain, enabled=False):
        """Returns the total number of users in the given domain. All user accounts are returned
        unless the Enabled flag is set, in which case only accounts with the "Enabled" attribute
        are returned.
        """
        if enabled:
            query = """
            MATCH (totalUsers:User {domain:UPPER('%s')})
            WHERE (totalUsers.enabled = True)
            RETURN COUNT(DISTINCT(totalUsers))
            """ % domain            
        else:
            query = """
            MATCH (totalUsers:User {domain:UPPER('%s')})
            RETURN COUNT(DISTINCT(totalUsers))
            """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        for record in results:
            return record[0]
Exemplo n.º 35
0
    def _graph_company(self):
        """Create nodes for the organization names and link them to domains based on whois records
        and Full Contact API results.
        """
        org_names = []
        try:
            self.c.execute("SELECT organization FROM whois_data")
            whois_orgs = self.c.fetchall()
            for org in whois_orgs:
                org_names.append(org[0])
        except:
            pass

        try:
            self.c.execute(
                "SELECT company_name,website,website_overview,employees,year_founded FROM company_info"
            )
            company_info = self.c.fetchone()
            org_names.append(company_info[0])
            org_names = set(org_names)
        except:
            pass

        if len(org_names) > 0:
            for org in org_names:
                query = """
                MERGE (x:Organization {Name:"%s"})
                RETURN x
                """ % (org)
                helpers.execute_query(self.neo4j_driver, query)

        if company_info:
            query = """
            MATCH (x:Organization {Name:'%s'})
            SET x += {Website:'%s', WebsiteOverview:"%s", Employees:'%s', YearFounded:'%s'}
            RETURN x
            """ % (company_info[0], company_info[1], company_info[2],
                   company_info[3], company_info[4])
            helpers.execute_query(self.neo4j_driver, query)

        for org in org_names:
            query = """
            MATCH (o:Organization {Name:"%s"})
            MATCH (d:Domain) WHERE d.Organization="%s"
            MERGE (o)-[r:OWNS]->(d)
            RETURN o,r,d
            """ % (org, org)
            helpers.execute_query(self.neo4j_driver, query)
Exemplo n.º 36
0
    def get_avg_group_membership(self, domain, recursive=False):
        """Calculate the average number of groups memberships for each user. If the recursive
        flag is set, this function will unroll group memberships to get the total number
        of groups.
        """
        if recursive:
            query = """
            MATCH (u:User {domain: UPPER('%s')})-[r:MemberOf*1..]->(g:Group)
            WITH u.name as userName,COUNT(r) as relCount
            RETURN AVG(relCount)
            """ % domain
        else:
            query = """
            MATCH (u:User {domain: UPPER('%s')})-[r:MemberOf*1]->(g:Group)
            WITH u.name as userName,COUNT(r) as relCount
            RETURN AVG(relCount)
            """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        for record in results:
            return record[0]
Exemplo n.º 37
0
    def find_special_users(self, domain):
        """Attempt to find user accounts containing common prefixes or suffixes that often
        denote accounts with administrator privileges.
        """
        # TODO: This seems like it could be more efficient
        query = """
        MATCH (u:User {domain:'%s'})
        WHERE u.name STARTS WITH '_' or u.name STARTS WITH '$'
        or u.name =~ '(?i).*ADMIN_.*' or u.name =~ '(?i).*ADMIN-.*'
        or u.name =~ '(?i).*_ADMIN.*' or u.name =~ '(?i).*-ADMIN.*'
        or u.name =~ '(?i).*ADM_.*' or u.name =~ '(?i).*ADM-.*'
        or u.name =~ '(?i).*_ADM.*' or u.name =~ '(?i).*-ADM.*'
        or u.name =~ '(?i).*_A.*' or u.name =~ '(?i).*-A.*'
        or u.name =~ '(?i).*A_.*' or u.name =~ '(?i).*A-.*'
        RETURN u.name
        """ % domain

        results = helpers.execute_query(self.neo4j_driver, query)

        users = []
        for record in results:
            users.append(record[0])

        return users
Exemplo n.º 38
0
 def clear_neo4j_database(self):
     """Clear the current Neo4j database by detaching and deleting all nodes."""
     query = "MATCH (n) DETACH DELETE n"
     helpers.execute_query(self.neo4j_driver,query)
Exemplo n.º 39
0
    def _graph_company(self):
        """Create nodes for the organization names and link them to domains based on WHOIS records
        and Full Contact API results.
        """
        org_names = []
        try:
            self.c.execute("SELECT company_name,website,website_overview,employees,year_founded FROM company_info")
            company_info = self.c.fetchone()
            org_names.append(company_info[0])
        except:
            pass
        org_names = set(org_names)
        if len(org_names) > 0:
            for org in org_names:
                query = """
                MERGE (x:Organization {Name:"%s"})
                RETURN x
                """ % (org)
                helpers.execute_query(self.neo4j_driver,query)
        else:
            query = """
            MERGE (x:Organization {Name:"Target"})
            RETURN x
            """
            helpers.execute_query(self.neo4j_driver,query)

        if company_info:
            query = """
            MATCH (x:Organization {Name:'%s'})
            SET x += {Website:'%s', WebsiteOverview:"%s", Employees:'%s', YearFounded:'%s'}
            RETURN x
            """% (company_info[0],company_info[1],company_info[2],company_info[3],company_info[4])
            helpers.execute_query(self.neo4j_driver,query)

        for org in org_names:
            if len(org_names) == 1:
                # Associate the domain nodes with the organization
                query = """
                MATCH (d:Domain)
                SET d += {Organization:'%s'}
                RETURN d
                """% (org)
                helpers.execute_query(self.neo4j_driver,query)
                # Create the relationships between the organization node and the domain nodes
                query = """
                MATCH (o:Organization {Name:"%s"})
                MATCH (d:Domain) WHERE d.Organization="%s"
                MERGE (o)-[r:OWNS]->(d)
                RETURN o,r,d
                """% (org,org)
                helpers.execute_query(self.neo4j_driver,query)            
            else:
                query = """
                MATCH (o:Organization {Name:"%s"})
                MATCH (d:Domain) WHERE d.Organization="%s"
                MERGE (o)-[r:OWNS]->(d)
                RETURN o,r,d
                """% (org,org)
                helpers.execute_query(self.neo4j_driver,query)