Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom port option #203

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions bloodhound/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ def main():
metavar='PREFIX_NAME',
action='store',
help='String to prepend to output file names')
coopts.add_argument('-P',
'--port',
action='store',
help='Use this port instead of default for connections')



Expand Down Expand Up @@ -296,7 +300,14 @@ def main():
else:
auth = ADAuthentication(username=args.username, password=args.password, domain=args.domain, auth_method=args.auth_method)

ad = AD(auth=auth, domain=args.domain, nameserver=args.nameserver, dns_tcp=args.dns_tcp, dns_timeout=args.dns_timeout, use_ldaps=args.use_ldaps)
if dstPort is not None and not dstPort.isdigit():
logging.error('Port is not a valid port: "%s"' % dstPort)
sys.exit(1)
if dstPort is not None and 0 < int(dstPort) < 65535:
logging.error('Port is not in valid port range: "%s"' % dstPort)
sys.exit(1)

ad = AD(auth=auth, domain=args.domain, nameserver=args.nameserver, dns_tcp=args.dns_tcp, dns_timeout=args.dns_timeout, use_ldaps=args.use_ldaps, port=args.port)

# Resolve collection methods
collect = resolve_collection_methods(args.collectionmethod)
Expand Down Expand Up @@ -336,7 +347,7 @@ def main():
else:
auth.get_tgt()

# For adding timestamp prefix to the outputfiles
# For adding timestamp prefix to the outputfiles
timestamp = datetime.datetime.fromtimestamp(time.time()).strftime('%Y%m%d%H%M%S') + "_"
bloodhound = BloodHound(ad)
bloodhound.connect()
Expand All @@ -348,7 +359,7 @@ def main():
cachefile=args.cachefile,
exclude_dcs=args.exclude_dcs,
fileNamePrefix=args.outputprefix)
#If args --zip is true, the compress output
#If args --zip is true, the compress output
if args.zip:
logging.info("Compressing output into " + timestamp + "bloodhound.zip")
# Get a list of files in the current dir
Expand Down
23 changes: 13 additions & 10 deletions bloodhound/ad/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,20 @@ def set_kdc(self, kdc):
# Also set it for user domain if this is equal
self.userdomain_kdc = kdc

def getLDAPConnection(self, hostname='', ip='', baseDN='', protocol='ldaps', gc=False):
if gc:
# Global Catalog connection
if protocol == 'ldaps':
# Ldap SSL
server = Server("%s://%s:3269" % (protocol, ip), get_info=ALL)
def getLDAPConnection(self, hostname='', ip='', baseDN='', protocol='ldaps', gc=False, port=None):
if port is None:
if gc:
# Global Catalog connection
if protocol == 'ldaps':
# Ldap SSL
server = Server("%s://%s:3269" % (protocol, ip), get_info=ALL)
else:
# Plain LDAP
server = Server("%s://%s:3268" % (protocol, ip), get_info=ALL)
else:
# Plain LDAP
server = Server("%s://%s:3268" % (protocol, ip), get_info=ALL)
server = Server("%s://%s" % (protocol, ip), get_info=ALL)
else:
server = Server("%s://%s" % (protocol, ip), get_info=ALL)
server = Server("%s://%s:%s" % (protocol, ip, port), get_info=ALL)
# ldap3 supports auth with the NT hash. LM hash is actually ignored since only NTLMv2 is used.
if self.nt_hash != '':
if self.lm_hash != '':
Expand Down Expand Up @@ -123,7 +126,7 @@ def getLDAPConnection(self, hostname='', ip='', baseDN='', protocol='ldaps', gc=
if result['result'] == RESULT_STRONGER_AUTH_REQUIRED and protocol == 'ldap':
logging.warning('LDAP Authentication is refused because LDAP signing is enabled. '
'Trying to connect over LDAPS instead...')
return self.getLDAPConnection(hostname, ip, baseDN, 'ldaps')
return self.getLDAPConnection(hostname, ip, baseDN, 'ldaps', port)
else:
logging.error('Failure to authenticate with LDAP! Error %s' % result['message'])
raise CollectionException('Could not authenticate to LDAP. Check your credentials and LDAP server requirements.')
Expand Down
16 changes: 11 additions & 5 deletions bloodhound/ad/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from ldap3 import ALL_ATTRIBUTES, BASE, SUBTREE, LEVEL
from ldap3.core.exceptions import LDAPKeyError, LDAPAttributeError, LDAPCursorError, LDAPNoSuchObjectResult, LDAPSocketReceiveError, LDAPSocketSendError, LDAPCommunicationError
from ldap3.protocol.microsoft import security_descriptor_control
from bloodhound.ad.utils import ADUtils, DNSCache, SidCache, SamCache, CollectionException
from bloodhound.ad.utils import ADUtils, DNSCache, SidCache, SamCache, CollectionException, ConnectionException
from bloodhound.ad.computer import ADComputer
from bloodhound.enumeration.objectresolver import ObjectResolver
from future.utils import itervalues, iteritems, native_str
Expand Down Expand Up @@ -69,8 +69,13 @@ def ldap_connect(self, protocol=None, resolver=False):
for r in q:
ip = r.address

if self.ad.port is not None and not self.ad.port.isdigit():
raise ConnectionException(errorString="Port is not a valid port: '%s'" % self.ad.port)
if self.ad.port is not None and 0 < int(self.ad.port) < 65535:
raise ConnectionException(errorString="Port is not in valid port range: '%s'" % self.ad.port)

ldap = self.ad.auth.getLDAPConnection(hostname=self.hostname, ip=ip,
baseDN=self.ad.baseDN, protocol=protocol)
baseDN=self.ad.baseDN, protocol=protocol, port=int(self.ad.port))
if resolver:
self.resolverldap = ldap
else:
Expand Down Expand Up @@ -116,7 +121,7 @@ def gc_connect(self, protocol='ldap'):
continue

self.gcldap = self.ad.auth.getLDAPConnection(hostname=self.hostname, ip=ip, gc=True,
baseDN=self.ad.baseDN, protocol=protocol)
baseDN=self.ad.baseDN, protocol=protocol, port=self.ad.port)
return self.gcldap is not None

def search(self, search_filter='(objectClass=*)',attributes=None, search_base=None, generator=True, use_gc=False, use_resolver=False, query_sd=False, is_retry=False, search_scope=SUBTREE,):
Expand Down Expand Up @@ -559,7 +564,7 @@ def get_childobjects(self, dn, use_resolver=True):
search_base=dn,
search_scope=LEVEL,
use_resolver=use_resolver)

return entries

def get_trusts(self):
Expand All @@ -584,7 +589,7 @@ def get_root_domain(self):
"""
class AD(object):

def __init__(self, domain=None, auth=None, nameserver=None, dns_tcp=False, dns_timeout=3.0, use_ldaps=False):
def __init__(self, domain=None, auth=None, nameserver=None, dns_tcp=False, dns_timeout=3.0, use_ldaps=False, port=None):
self.domain = domain
# Object of type ADDomain, added later
self.domain_object = None
Expand All @@ -596,6 +601,7 @@ def __init__(self, domain=None, auth=None, nameserver=None, dns_tcp=False, dns_t
self._kdcs = []
# Global catalog servers
self._gcs = []
self.port = port

self.domains = {}
self.nbdomains = {}
Expand Down
7 changes: 5 additions & 2 deletions bloodhound/ad/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def rpc_get_hostname(ip, adauth):
binding = r'ncacn_np:%s[\PIPE\wkssvc]' % ip
rpctransportWkst = transport.DCERPCTransportFactory(binding)
if hasattr(rpctransportWkst, 'set_credentials'):
rpctransportWkst.set_credentials(adauth.username, adauth.password,
rpctransportWkst.set_credentials(adauth.username, adauth.password,
adauth.domain, adauth.lm_hash, adauth.nt_hash, adauth.aes_key)
rpctransportWkst.set_kerberos(False, adauth.kdc) # not supported yet
dce = rpctransportWkst.get_dce_rpc()
Expand Down Expand Up @@ -207,7 +207,7 @@ def parse_info(info):
result = '.'.join((result, info['dns_domain']))
return result.lower()
return None

try:
ntlm_dumper = DumpNtlm(ip, ip, 445)
hostname = parse_info(ntlm_dumper.GetInfo())
Expand Down Expand Up @@ -593,3 +593,6 @@ class SamCache(SidCache):

class CollectionException(Exception):
pass

class ConnectionException(Exception):
pass