class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__( self, remoteName, dstport=445, filename="", username="", password="", domain="", lmhash="", nthash="", aesKey="", TGT=None, TGS=None, remote_host="", smb_connection=0, doKerberos=False, kdcHost=None, ): DCERPCTransport.__init__(self, remoteName, dstport) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.set_credentials(username, password, domain, lmhash, nthash, aesKey, TGT, TGS) self._doKerberos = doKerberos self._kdcHost = kdcHost if remote_host != "": self.setRemoteHost(remote_host) if smb_connection == 0: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(*smb_connection.getCredentials()) self.__prefDialect = None self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: self.__smb_connection = SMBConnection( self.getRemoteName(), self.getRemoteHost(), sess_port=self.get_dport(), preferredDialect=self.__prefDialect, ) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection == 0: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self._username, self._password, self._domain, self._lmhash, self._nthash) else: self.__smb_connection.kerberosLogin( self._username, self._password, self._domain, self._lmhash, self._nthash, self._aesKey, kdcHost=self._kdcHost, TGT=self._TGT, TGS=self._TGS, ) self.__tid = self.__smb_connection.connectTree("IPC$") self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection = 0 def send(self, data, forceWriteAndx=0, forceRecv=0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset : offset + self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset=offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv=0, count=0): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead=self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(*smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__(self, dstip, dstport=445, filename='', username='', password='', domain='', lmhash='', nthash='', aesKey='', TGT=None, TGS=None, remote_name='', smb_connection=0, doKerberos=False): DCERPCTransport.__init__(self, dstip, dstport) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.set_credentials(username, password, domain, lmhash, nthash, aesKey, TGT, TGS) self.__remote_name = remote_name self._doKerberos = doKerberos if smb_connection == 0: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(*smb_connection.getCredentials()) self.__prefDialect = None if isinstance(smb_connection, smb.SMB): # Backward compatibility hack, let's return a # SMBBackwardCompatibilityTransport instance return SMBBackwardCompatibilityTransport(filename = filename, smb_server = smb_connection) else: self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: if self.__remote_name == '': if self.get_dport() == nmb.NETBIOS_SESSION_PORT: self.__smb_connection = SMBConnection('*SMBSERVER', self.get_dip(), sess_port = self.get_dport(),preferredDialect = self.__prefDialect) else: self.__smb_connection = SMBConnection(self.get_dip(), self.get_dip(), sess_port = self.get_dport(),preferredDialect = self.__prefDialect) else: self.__smb_connection = SMBConnection(self.__remote_name, self.get_dip(), sess_port = self.get_dport(),preferredDialect = self.__prefDialect) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection == 0: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self._username, self._password, self._domain, self._lmhash, self._nthash) else: self.__smb_connection.kerberosLogin(self._username, self._password, self._domain, self._lmhash, self._nthash, self._aesKey, TGT=self._TGT, TGS=self._TGS) self.__tid = self.__smb_connection.connectTree('IPC$') self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection = 0 def send(self,data, forceWriteAndx = 0, forceRecv = 0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset:offset+self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset = offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv = 0, count = 0 ): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead = self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(*smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__(self, remoteName, dstport=445, filename='', username='', password='', domain='', lmhash='', nthash='', aesKey='', TGT=None, TGS=None, remote_host='', smb_connection=0, doKerberos=False, kdcHost=None): DCERPCTransport.__init__(self, remoteName, dstport) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.set_credentials(username, password, domain, lmhash, nthash, aesKey, TGT, TGS) self._doKerberos = doKerberos self._kdcHost = kdcHost if remote_host != '': self.setRemoteHost(remote_host) if smb_connection == 0: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(*smb_connection.getCredentials()) self.__prefDialect = None self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: self.__smb_connection = SMBConnection( self.getRemoteName(), self.getRemoteHost(), sess_port=self.get_dport(), preferredDialect=self.__prefDialect) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection == 0: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self._username, self._password, self._domain, self._lmhash, self._nthash) else: self.__smb_connection.kerberosLogin(self._username, self._password, self._domain, self._lmhash, self._nthash, self._aesKey, kdcHost=self._kdcHost, TGT=self._TGT, TGS=self._TGS) self.__tid = self.__smb_connection.connectTree('IPC$') self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection.close() self.__smb_connection = 0 def send(self, data, forceWriteAndx=0, forceRecv=0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset:offset + self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset=offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv=0, count=0): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile( self.__tid, self.__handle, bytesToRead=self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(*smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()
class ImpacketConnection: class Options: def __init__(self, hostname="", domain_name="", username="", password="", lmhash="", nthash="", kerberos=False, aesKey="", dc_ip=None, timeout=5): self.hostname = hostname self.domain_name = domain_name self.username = username self.password = password self.lmhash = lmhash self.nthash = nthash self.timeout = timeout self.kerberos = kerberos self.aesKey = aesKey self.dc_ip = dc_ip def __init__(self, options: Options): self.options = options self.hostname = options.hostname self.domain_name = options.domain_name self.username = options.username self.password = options.password self.lmhash = options.lmhash self.nthash = options.nthash self.kerberos = options.kerberos self.aesKey = options.aesKey self.dc_ip = options.dc_ip self.timeout = options.timeout self._log = Logger(self.hostname) self._conn = None def get_logger(self): return self._log def set_logger(self, logger): self._log = logger def login(self): try: ip = list({ addr[-1][0] for addr in getaddrinfo(self.hostname, 0, 0, 0, 0) })[0] if ip != self.hostname: self._log.debug("Host {} resolved to {}".format( self.hostname, ip)) except gaierror as e: return RetCode(ERROR_DNS_ERROR, e) try: self._conn = SMBConnection(self.hostname, ip, timeout=self.timeout) except Exception as e: return RetCode(ERROR_CONNECTION_ERROR, e) username = '' if not self.kerberos: username = self.username.split("@")[0] self._log.debug("Authenticating against {}".format(ip)) else: self._log.debug("Authenticating against {}".format(self.hostname)) try: if not self.kerberos: self._conn.login(username, self.password, domain=self.domain_name, lmhash=self.lmhash, nthash=self.nthash, ntlmFallback=True) else: self._conn.kerberosLogin(username, self.password, domain=self.domain_name, lmhash=self.lmhash, nthash=self.nthash, aesKey=self.aesKey, kdcHost=self.dc_ip) except SessionError as e: self._log.debug("Provided credentials : {}\\{}:{}".format( self.domain_name, username, self.password)) return RetCode(ERROR_LOGIN_FAILURE, e) except KerberosException as e: self._log.debug("Kerberos error") return RetCode(ERROR_LOGIN_FAILURE, e) except Exception as e: return RetCode(ERROR_UNDEFINED, e) return RetCode(ERROR_SUCCESS) def connectTree(self, share_name): return self._conn.connectTree(share_name) def openFile(self, tid, fpath, timeout: int = 3): self._log.debug("Opening file {}".format(fpath)) start = time.time() while True: try: fid = self._conn.openFile(tid, fpath, desiredAccess=FILE_READ_DATA) self._log.debug("File {} opened".format(fpath)) return fid except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0 or str(e).find( 'STATUS_OBJECT_NAME_NOT_FOUND') >= 0: # Output not finished, let's wait if time.time() - start > timeout: raise (Exception(e)) time.sleep(1) else: raise Exception(e) def queryInfo(self, tid, fid): while True: try: info = self._conn.queryInfo(tid, fid) return info except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0: # Output not finished, let's wait time.sleep(2) else: raise Exception(e) def getFile(self, share_name, path_name, callback): while True: try: self._conn.getFile(share_name, path_name, callback) break except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0: # Output not finished, let's wait time.sleep(2) else: raise Exception(e) def deleteFile(self, share_name, path_name): while True: try: self._conn.deleteFile(share_name, path_name) self._log.debug("File {} deleted".format(path_name)) break except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0: time.sleep(2) else: raise Exception(e) def putFile(self, share_name, path_name, callback): try: self._conn.putFile(share_name, path_name, callback) self._log.debug("File {} uploaded".format(path_name)) except Exception as e: raise Exception( "An error occured while uploading %s on %s share : %s" % (path_name, share_name, e)) def readFile(self, tid, fid, offset, size): return self._conn.readFile(tid, fid, offset, size, singleCall=False) def closeFile(self, tid, fid): return self._conn.closeFile(tid, fid) def disconnectTree(self, tid): return self._conn.disconnectTree(tid) def isadmin(self): try: self.connectTree("C$") return RetCode(ERROR_SUCCESS) except Exception as e: return RetCode(ERROR_ACCESS_DENIED, e) def close(self): if self._conn is not None: self._log.debug("Closing Impacket connection") self._conn.close() def clean(self): try: self.close() return RetCode(ERROR_SUCCESS) except Exception as e: return RetCode(ERROR_CONNECTION_CLEANING, e)
class ServiceInstall: def __init__(self, SMBObject, exeFile, serviceName='', binary_service_name=None): self._rpctransport = 0 self.__service_name = serviceName if len(serviceName) > 0 else ''.join( [random.choice(string.ascii_letters) for i in range(4)]) if binary_service_name is None: self.__binary_service_name = ''.join( [random.choice(string.ascii_letters) for i in range(8)]) + '.exe' else: self.__binary_service_name = binary_service_name self.__exeFile = exeFile # We might receive two different types of objects, always end up # with a SMBConnection one if isinstance(SMBObject, smb.SMB) or isinstance(SMBObject, smb3.SMB3): self.connection = SMBConnection(existingConnection=SMBObject) else: self.connection = SMBObject self.share = '' def getShare(self): return self.share 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 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 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 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 = f.replace('/', '\\') try: self.connection.putFile(tree, pathname, fh.read) except: LOG.critical("Error uploading file %s, aborting....." % dst) raise fh.close() 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.debug('Exception', exc_info=True) 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 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 uninstall(self): fileCopied = True serviceCreated = True # Do the stuff here try: # Let's get the shares svcManager = self.openSvcManager() if svcManager != 0: resp = scmr.hROpenServiceW(self.rpcsvc, svcManager, self.__service_name + '\x00') service = resp['lpServiceHandle'] LOG.info('Stopping service %s.....' % self.__service_name) try: scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP) except: pass LOG.info('Removing service %s.....' % self.__service_name) scmr.hRDeleteService(self.rpcsvc, service) scmr.hRCloseServiceHandle(self.rpcsvc, service) scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) LOG.info('Removing file %s.....' % self.__binary_service_name) self.connection.deleteFile(self.share, self.__binary_service_name) except Exception: LOG.critical("Error performing the uninstallation, cleaning up") 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: try: self.connection.deleteFile(self.share, self.__binary_service_name) except: pass pass if serviceCreated is True: try: scmr.hRDeleteService(self.rpcsvc, service) except: pass
class ServiceInstall: def __init__(self, SMBObject, exeFile, serviceName=''): self._rpctransport = 0 self.__service_name = serviceName if len(serviceName) > 0 else ''.join([random.choice(string.ascii_letters) for i in range(4)]) self.__binary_service_name = ''.join([random.choice(string.ascii_letters) for i in range(8)]) + '.exe' self.__exeFile = exeFile # We might receive two different types of objects, always end up # with a SMBConnection one if isinstance(SMBObject, smb.SMB) or isinstance(SMBObject, smb3.SMB3): self.connection = SMBConnection(existingConnection = SMBObject) else: self.connection = SMBObject self.share = '' def getShare(self): return self.share 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 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 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 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 = f.replace('/','\\') try: self.connection.putFile(tree, pathname, fh.read) except: LOG.critical("Error uploading file %s, aborting....." % dst) raise fh.close() 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 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) 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 uninstall(self): fileCopied = True serviceCreated = True # Do the stuff here try: # Let's get the shares svcManager = self.openSvcManager() if svcManager != 0: resp = scmr.hROpenServiceW(self.rpcsvc, svcManager, self.__service_name+'\x00') service = resp['lpServiceHandle'] LOG.info('Stopping service %s.....' % self.__service_name) try: scmr.hRControlService(self.rpcsvc, service, scmr.SERVICE_CONTROL_STOP) except: pass LOG.info('Removing service %s.....' % self.__service_name) scmr.hRDeleteService(self.rpcsvc, service) scmr.hRCloseServiceHandle(self.rpcsvc, service) scmr.hRCloseServiceHandle(self.rpcsvc, svcManager) LOG.info('Removing file %s.....' % self.__binary_service_name) self.connection.deleteFile(self.share, self.__binary_service_name) except Exception: LOG.critical("Error performing the uninstallation, cleaning up" ) 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: try: self.connection.deleteFile(self.share, self.__binary_service_name) except: pass pass if serviceCreated is True: try: scmr.hRDeleteService(self.rpcsvc, service) except: pass
class SMBTransport(DCERPCTransport): """Implementation of ncacn_np protocol sequence""" def __init__(self, target, credential = SMBCredential(), filename='', smb_connection=None): DCERPCTransport.__init__(self, target) self.__socket = None self.__tid = 0 self.__filename = filename self.__handle = 0 self.__pending_recv = 0 self.__credential = credential self.set_credentials(credential) if target.hostname is not None: self.setRemoteHost(target.hostname) if smb_connection is None: self.__existing_smb = False else: self.__existing_smb = True self.set_credentials(smb_connection.getCredentials()) self.__prefDialect = None self.__smb_connection = smb_connection def preferred_dialect(self, dialect): self.__prefDialect = dialect def setup_smb_connection(self): if not self.__smb_connection: self.__smb_connection = SMBConnection(self.getRemoteName(), self.getRemoteHost(), sess_port=self.get_dport(), preferredDialect=self.__prefDialect) def connect(self): # Check if we have a smb connection already setup if self.__smb_connection is None: self.setup_smb_connection() if self._doKerberos is False: self.__smb_connection.login(self.__credential) else: self.__smb_connection.kerberos_login(self.__credential) self.__tid = self.__smb_connection.connectTree('IPC$') self.__handle = self.__smb_connection.openFile(self.__tid, self.__filename) self.__socket = self.__smb_connection.getSMBServer().get_socket() return 1 def disconnect(self): self.__smb_connection.disconnectTree(self.__tid) # If we created the SMB connection, we close it, otherwise # that's up for the caller if self.__existing_smb is False: self.__smb_connection.logoff() self.__smb_connection.close() self.__smb_connection = None def send(self,data, forceWriteAndx = 0, forceRecv = 0): if self._max_send_frag: offset = 0 while 1: toSend = data[offset:offset+self._max_send_frag] if not toSend: break self.__smb_connection.writeFile(self.__tid, self.__handle, toSend, offset = offset) offset += len(toSend) else: self.__smb_connection.writeFile(self.__tid, self.__handle, data) if forceRecv: self.__pending_recv += 1 def recv(self, forceRecv = 0, count = 0 ): if self._max_send_frag or self.__pending_recv: # _max_send_frag is checked because it's the same condition we checked # to decide whether to use write_andx() or send_trans() in send() above. if self.__pending_recv: self.__pending_recv -= 1 return self.__smb_connection.readFile(self.__tid, self.__handle, bytesToRead = self._max_recv_frag) else: return self.__smb_connection.readFile(self.__tid, self.__handle) def get_smb_connection(self): return self.__smb_connection def set_smb_connection(self, smb_connection): self.__smb_connection = smb_connection self.set_credentials(smb_connection.getCredentials()) self.__existing_smb = True def get_smb_server(self): # Raw Access to the SMBServer (whatever type it is) return self.__smb_connection.getSMBServer() def get_socket(self): return self.__socket def doesSupportNTLMv2(self): return self.__smb_connection.doesSupportNTLMv2()