def NetrSessionEnum(self, serverName='', clientName='', userName='', preferedMaximumLength=0xffffffff, resumeHandle=0): """ returns information about sessions that are established on a server (info struct 502 only supported) :param UNICODE serverName: the NetBIOS name of the remote machine. '' would do the work as well :param UNICODE clientName: Unicode string that specifies the client machine users are connected from. Default value means all users will be returned instead of the client machine they are connecting from. :param UNICODE userName: Unicode string that specifies the specific username to check for connectivity. Default value means all users will be returned. :param INT preferedMaximumLength: specifies the preferred maximum length, in bytes, of the returned data. Default value is MAX_PREFERRED_LENGTH :param INT resumeHandle: a value that contains a handle, which is used to continue an existing share search. First time it should be 0 :return: returns a list of dictionaries for each session returned (strings in UNICODE). print the response to see its contents. On error it raises an exception """ sessionEnum = SRVSVCSessionEnum() sessionEnum['ServerName'] = ndrutils.NDRUniqueStringW() sessionEnum['ServerName']['Data'] = serverName + '\x00'.encode( 'utf-16le') sessionEnum['ServerName'].alignment = 4 sessionEnum['ClientName'] = ndrutils.NDRUniqueStringW() sessionEnum['ClientName']['Data'] = clientName + '\x00'.encode( 'utf-16le') sessionEnum['ClientName'].alignment = 4 sessionEnum['UserName'] = ndrutils.NDRUniqueStringW() sessionEnum['UserName']['Data'] = userName + '\x00'.encode('utf-16le') sessionEnum['UserName'].alignment = 4 sessionEnum['InfoStruct'] = SESSION_ENUM_STRUCT() sessionEnum['InfoStruct']['Level'] = 502 sessionEnum['InfoStruct']['SwitchIs'] = 502 sessionEnum['InfoStruct']['pContainer'] = ndrutils.NDRPointerNew() sessionEnum['InfoStruct']['SessionInfo'] = SESSION_INFO_502_CONTAINER() sessionEnum['InfoStruct']['SessionInfo'][ 'pBuffer'] = ndrutils.NDRPointerNew() sessionEnum['InfoStruct']['SessionInfo']['pBuffer']['RefId'] = 0 sessionEnum['InfoStruct']['SessionInfo']['Buffer'] = '' sessionEnum['PreferedMaximumLength'] = preferedMaximumLength sessionEnum['pResumeHandle'] = ndrutils.NDRPointerNew() sessionEnum['ResumeHandle'] = resumeHandle data = self.doRequest(sessionEnum, checkReturn=1) ans = SRVSVCSessionEnumResponse(data) # Now let's return something useful sessionList = [] for i in range(ans['InfoStruct']['SessionInfo']['EntriesRead']): item = ans['InfoStruct']['SessionInfo']['Buffer']['Item_%d' % i] entry = {} entry['Active'] = item['sesi502_time'] entry['IDLE'] = item['sesi502_idle_time'] entry['Type'] = item['cltype_name']['Data'] entry['Transport'] = item['transport']['Data'] entry['HostName'] = item['cname']['Data'] entry['UserName'] = item['username']['Data'] sessionList.append(entry) return sessionList
def CreateServiceW(self, handle, serviceName, displayName, binaryPathName, serviceType = SERVICE_WIN32_OWN_PROCESS): """ creates a service :param HANDLE handle: a valid HANDLE to the SCM database (see OpenSCManagerW) :param UNICODE serviceName: the name of the service to create :param UNICODE displayName: the display name of the service to create :param UNICODE binaryPathName: the pathname for the binary to be executed when starting the service :param INT serviceType: the type of service to be created. See service types within this file or [MS-SCMR] section 3.1.4.12. :return: returns an SVCCTLRCreateServiceWResponse structure with the service handle. Call dump() method to see its contents. On error it raises an exception """ # We MUST receive Unicode data here createService = SVCCTLRCreateServiceW() createService['SCManager'] = handle createService['ServiceName'] = ndrutils.NDRStringW() createService['ServiceName']['Data'] = (serviceName+'\x00'.encode('utf-16le')) createService['DisplayName'] = ndrutils.NDRUniqueStringW() createService['DisplayName']['Data'] = (displayName+'\x00'.encode('utf-16le')) createService['DesiredAccess'] = SERVICE_ALL_ACCESS createService['ServiceType'] = serviceType createService['StartType'] = SERVICE_AUTO_START #createService['StartType'] = SERVICE_DEMAND_START createService['ErrorControl'] = SERVICE_ERROR_IGNORE createService['BinaryPathName'] = ndrutils.NDRStringW() createService['BinaryPathName']['Data'] = (binaryPathName+'\x00'.encode('utf-16le')) createService['TagID'] = 0 ans = self.doRequest(createService, checkReturn = 1) return SVCCTLRCreateServiceWResponse(ans)
def NetrShareGetInfo(self, serverName, netName): """ retrieves information about a particular shared resource on the server (info struct level 2 only supported) :param UNICODE serverName: the NetBIOS name of the remote machine. '' would do the work as well :param UNICODE netName: Unicode string that specifies the name of the share to return information for :return: a SHARE_INFO_2 like structure (strings in UNICODE). For the meaning of each field see [MS-SRVS] Section 2.2.4.24 """ shareGetInfo = SRVSVCShareGetInfo() shareGetInfo['ServerName'] = ndrutils.NDRUniqueStringW() shareGetInfo['ServerName']['Data'] = serverName + '\x00'.encode( 'utf-16le') shareGetInfo['ServerName'].alignment = 4 shareGetInfo['NetName'] = ndrutils.NDRStringW() shareGetInfo['NetName']['Data'] = netName + '\x00'.encode('utf-16le') shareGetInfo['NetName'].alignment = 4 shareGetInfo['Level'] = 2 data = self.doRequest(shareGetInfo, checkReturn=1) ans = SRVSVCShareGetInfoResponse(data) entry = {} entry['Type'] = ans['InfoStruct']['ShareInfo2']['shi2_type'] entry['NetName'] = ans['InfoStruct']['ShareInfo2']['netname']['Data'] entry['Remark'] = ans['InfoStruct']['ShareInfo2']['remark']['Data'] entry['Permissions'] = ans['InfoStruct']['ShareInfo2'][ 'shi2_permissions'] entry['MaxUses'] = ans['InfoStruct']['ShareInfo2']['shi2_max_uses'] entry['CurrentUses'] = ans['InfoStruct']['ShareInfo2'][ 'shi2_current_uses'] entry['Path'] = ans['InfoStruct']['ShareInfo2']['path']['Data'] return entry
def NetrJobDel(self, serverName, minJobId, maxJobId): jobDel = ATSVCNetrJobDel() jobDel['ServerName'] = ndrutils.NDRUniqueStringW() jobDel['ServerName']['Data'] = (serverName + '\x00').encode('utf-16le') jobDel['MinJobId'] = minJobId jobDel['MaxJobId'] = maxJobId packet = self.doRequest(jobDel, checkReturn=1) return packet
def NetrJobEnum(self, serverName, resumeHandle = 0x0 ): jobEnum = ATSVCNetrJobEnum() jobEnum['ServerName'] = ndrutils.NDRUniqueStringW() jobEnum['ServerName']['Data'] = (serverName+'\x00').encode('utf-16le') jobEnum['ResumeHandle'] = resumeHandle packet = self.doRequest(jobEnum, checkReturn = 1) ans = ATSVCNetrJobEnumResponse(packet) return ans
def OpenSCManagerW(self): openSCManager = SVCCTLROpenSCManagerW() openSCManager['MachineName'] = ndrutils.NDRUniqueStringW() openSCManager['MachineName']['Data'] = 'DUMMY\x00'.encode('utf-16le') openSCManager[ 'DesiredAccess'] = SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS ans = self.doRequest(openSCManager, checkReturn=1) return SVCCTLROpenSCManagerAResponse(ans)
def NetrJobAdd(self, serverName, atInfo): jobAdd = ATSVCNetrJobAdd() jobAdd['ServerName'] = ndrutils.NDRUniqueStringW() jobAdd['ServerName']['Data'] = (serverName+'\x00').encode('utf-16le') jobAdd['pAtInfo'] = atInfo ans = self.doRequest(jobAdd, checkReturn = 1) return ans
def LsarOpenPolicy2(self, server_name, access_mask=0x00020801): open_policy = LSARPCOpenPolicy2() open_policy['ServerName'] = ndrutils.NDRUniqueStringW() open_policy['ServerName']['Data'] = (server_name + '\x00').encode('utf-16le') #TODO: Implement ObjectAtributes structure open_policy[ 'ObjectAttributes'] = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' open_policy['AccessMask'] = access_mask data = self.doRequest(open_policy) ans = LSARPCOpenPolicy2Response(data) return ans
def doStuff(self, rpctransport): dce = dcerpc.DCERPC_v5(rpctransport) user, pwd, domain, _, _ = rpctransport.get_credentials() dce.set_credentials(user,pwd,domain) dce.connect() #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) #dce.set_max_fragment_size(16) dce.bind(atsvc.MSRPC_UUID_ATSVC) at = atsvc.DCERPCAtSvc(dce) # Check [MS-TSCH] Section 2.3.4 atInfo = atsvc.AT_INFO() atInfo['JobTime'] = 0 atInfo['DaysOfMonth'] = 0 atInfo['DaysOfWeek'] = 0 atInfo['Flags'] = 0 atInfo['Command'] = ndrutils.NDRUniqueStringW() atInfo['Command']['Data'] = ('calc.exe\x00').encode('utf-16le') # Remember to remove it on the target server ;) resp = at.NetrJobAdd(('\\\\%s'% rpctransport.get_dip()),atInfo) resp = at.NetrJobEnum(rpctransport.get_dip()) # ToDo: Parse this struct, should be easy resp.dump() # Switching context to TSS dce = dce.alter_ctx(atsvc.MSRPC_UUID_TSS) # Now atsvc should use that new context at = atsvc.DCERPCAtSvc(dce) #path = '\\Microsoft\\Windows\\Media Center' path = '\\' resp = at.SchRpcEnumTasks(path) if resp['Count'] == 1: print resp['TaskName']['Data'] if resp['ErrorCode'] == atsvc.S_FALSE: i = 1 done = False while done is not True: # More items try: resp = at.SchRpcEnumTasks(path,startIndex=i) except: break if resp['Count'] == 1: print resp['TaskName']['Data'] i += 1 elif resp['ErrorCode'] != atsvc.S_FALSE: done = True dce.disconnect()
def OpenSCManagerW(self): """ opens the SCM database on the specified server. :return: returns an SVCCTLROpenSCManagerAResponse structure with the SCM handle. Call dump() method to see its contents. On error it raises an exception """ openSCManager = SVCCTLROpenSCManagerW() openSCManager['MachineName'] = ndrutils.NDRUniqueStringW() openSCManager['MachineName']['Data'] = 'DUMMY\x00'.encode('utf-16le') openSCManager['DesiredAccess'] = SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS ans = self.doRequest(openSCManager, checkReturn = 1) return SVCCTLROpenSCManagerAResponse(ans)
def NetrShareEnum(self, serverName='', preferedMaximumLength=0xffffffff, resumeHandle=0): """ retrieves information about each shared resource on a server (only level1 supported) :param UNICODE serverName: the NetBIOS name of the remote machine. '' would do the work as well :param INT preferedMaximumLength: specifies the preferred maximum length, in bytes, of the returned data. Default value is MAX_PREFERRED_LENGTH :param INT resumeHandle: a value that contains a handle, which is used to continue an existing share search. First time it should be 0 :return: returns a list of dictionaries for each shares returned (strings in UNICODE). print the response to see its contents. On error it raises an exception """ shareEnum = SRVSVCShareEnum() shareEnum['ServerName'] = ndrutils.NDRUniqueStringW() shareEnum['ServerName']['Data'] = serverName + '\x00'.encode( 'utf-16le') shareEnum['ServerName'].alignment = 4 shareEnum['InfoStruct'] = SHARE_ENUM_STRUCT() shareEnum['InfoStruct']['Level'] = 1 shareEnum['InfoStruct']['SwitchIs'] = 1 shareEnum['InfoStruct']['pContainer'] = ndrutils.NDRPointerNew() shareEnum['InfoStruct']['ShareInfo'] = SHARE_INFO_1_CONTAINER() shareEnum['InfoStruct']['ShareInfo'][ 'pBuffer'] = ndrutils.NDRPointerNew() shareEnum['InfoStruct']['ShareInfo']['pBuffer']['RefId'] = 0 shareEnum['InfoStruct']['ShareInfo']['Buffer'] = '' shareEnum['PreferedMaximumLength'] = preferedMaximumLength shareEnum['pResumeHandle'] = ndrutils.NDRPointerNew() shareEnum['ResumeHandle'] = resumeHandle data = self.doRequest(shareEnum, checkReturn=1) ans = SRVSVCShareEnumResponse(data) # Now let's return something useful shareList = [] for i in range(ans['InfoStruct']['ShareInfo']['EntriesRead']): item = ans['InfoStruct']['ShareInfo']['Buffer']['Item_%d' % i] entry = {} entry['Type'] = item['shi1_type'] entry['NetName'] = item['netname']['Data'] entry['Remark'] = item['remark']['Data'] shareList.append(entry) return shareList
def LsarOpenPolicy2(self, systemName, desiredAccess=0x00020801): """ opens a context handle to the RPC server :param string systemName: This parameter does not have any effect on message processing in any environment. It MUST be ignored on receipt. :param int desiredAccess: An ACCESS_MASK value that specifies the requested access rights that MUST be granted on the returned PolicyHandle if the request is successful. Check [MS-DTYP], section 2.4.3 :return: a structure with a policy handle, call dump() to check its structure. Otherwise raises an error """ open_policy = LSARPCOpenPolicy2() open_policy['ServerName'] = ndrutils.NDRUniqueStringW() open_policy['ServerName']['Data'] = (systemName + '\x00').encode('utf-16le') #TODO: Implement ObjectAtributes structure open_policy[ 'ObjectAttributes'] = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' open_policy['AccessMask'] = desiredAccess data = self.doRequest(open_policy) ans = LSARPCOpenPolicy2Response(data) return ans
def CreateServiceW(self, handle, serviceName, displayName, binaryPathName): # We MUST receive Unicode data here createService = SVCCTLRCreateServiceW() createService['SCManager'] = handle createService['ServiceName'] = ndrutils.NDRStringW() createService['ServiceName']['Data'] = (serviceName + '\x00'.encode('utf-16le')) createService['DisplayName'] = ndrutils.NDRUniqueStringW() createService['DisplayName']['Data'] = (displayName + '\x00'.encode('utf-16le')) createService['DesiredAccess'] = SERVICE_ALL_ACCESS createService[ 'ServiceType'] = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS createService['StartType'] = SERVICE_AUTO_START #createService['StartType'] = SERVICE_DEMAND_START createService['ErrorControl'] = SERVICE_ERROR_IGNORE createService['BinaryPathName'] = ndrutils.NDRStringW() createService['BinaryPathName']['Data'] = (binaryPathName + '\x00'.encode('utf-16le')) createService['TagID'] = 0 ans = self.doRequest(createService, checkReturn=1) return SVCCTLRCreateServiceWResponse(ans)
def NetrWkstaTransportEnum( self, serverName ): transportEnum = WKSSVCNetrWkstaTransportEnum() transportEnum['ServerName'] = ndrutils.NDRUniqueStringW() transportEnum['ServerName']['Data'] = (serverName+'\x00').encode('utf-16le') transportEnum['TransportInfo'] = '\x00'*8 + '\x04\x00\x04\x00' + '\x00'*8 data = self.doRequest(transportEnum, checkReturn = 1) ans = WKSSVCNetrWkstaTransportEnumResponse(data) data = ans['Array'] transportList = [] for i in range(ans['Count']): ll = WKSTA_TRANSPORT_INFO_0(data) transportList.append(ll) data = data[len(ll):] for i in range(ans['Count']): transName = ndrutils.NDRStringW(data) transportList[i]['TransportName'] = transName data = data[len(transName):] transAddress = ndrutils.NDRStringW(data) transportList[i]['TransportAddress'] = transAddress data = data[len(transAddress):] ans['Array'] = transportList return ans
def doStuff(self, rpctransport): def output_callback(data): print data dce = rpctransport.get_dce_rpc() dce.set_credentials(*rpctransport.get_credentials()) dce.connect() #dce.set_auth_level(ntlm.NTLM_AUTH_PKT_PRIVACY) #dce.set_max_fragment_size(16) dce.bind(atsvc.MSRPC_UUID_ATSVC) at = atsvc.DCERPCAtSvc(dce) tmpFileName = ''.join([random.choice(string.letters) for i in range(8)]) + '.tmp' # Check [MS-TSCH] Section 2.3.4 atInfo = atsvc.AT_INFO() atInfo['JobTime'] = 0 atInfo['DaysOfMonth'] = 0 atInfo['DaysOfWeek'] = 0 atInfo['Flags'] = 0 atInfo['Command'] = ndrutils.NDRUniqueStringW() atInfo['Command']['Data'] = ('%%COMSPEC%% /C %s > %%SYSTEMROOT%%\\Temp\\%s\x00' % (self.__command, tmpFileName)).encode('utf-16le') resp = at.NetrJobAdd(('\\\\%s'% rpctransport.get_dip()),atInfo) jobId = resp['JobID'] #resp = at.NetrJobEnum(rpctransport.get_dip()) # Switching context to TSS dce2 = dce.alter_ctx(atsvc.MSRPC_UUID_TSS) # Now atsvc should use that new context at = atsvc.DCERPCAtSvc(dce2) # Leaving this code to show how to enumerate jobs #path = '\\' #resp = at.SchRpcEnumTasks(path) #if resp['Count'] == 1: # print resp['TaskName']['Data'] # if resp['ErrorCode'] == atsvc.S_FALSE: # i = 1 # done = False # while done is not True: # # More items # try: # resp = at.SchRpcEnumTasks(path,startIndex=i) # except: # break # if resp['Count'] == 1: # print resp['TaskName']['Data'] # i += 1 # elif resp['ErrorCode'] != atsvc.S_FALSE: # done = True resp = at.SchRpcRun('\\At%d' % jobId) # On the first run, it takes a while the remote target to start executing the job # so I'm setting this sleep.. I don't like sleeps.. but this is just an example # Best way would be to check the task status before attempting to read the file time.sleep(3) # Switching back to the old ctx_id at = atsvc.DCERPCAtSvc(dce) resp = at.NetrJobDel('\\\\%s'% rpctransport.get_dip(), jobId, jobId) smbConnection = rpctransport.get_smb_connection() while True: try: smbConnection.getFile('ADMIN$', 'Temp\\%s' % tmpFileName, output_callback) break except Exception, e: if str(e).find('SHARING') > 0: time.sleep(3) else: raise
def ChangeServiceConfigW(self, handle, displayName=None, binaryPathName=None, serviceType=None, startType=None, serviceStartName=None, password=None): """ changes a service's configuration parameters in the SCM database :param HANDLE handle: a valid HANDLE to the service (see OpenServiceW) :param UNICODE displayName: the new display name of the service. None if you don't want to change this value. :param UNICODE binaryPathName: the new pathname for the binary to be executed when starting the service. None if you don't want to change this value :param UNICODE serviceType: the new type of the service. None if you don't want to change this value. See service types within this file or [MS-SCMR] section 3.1.4.12. :param INT startType: the new startType of the service. None if you don't want to change this value. See [MS-SCMR] section 3.1.4.11 for a list of possible values. :param UNICODE startStartName: the name of the account under which the service should run. None if you don't want to change this value. :param BINARY password: a password value for the user. None if you don't want to change this value. :return: On error it raises an exception. Otherwise it was successful VERY IMPORTANT: If you dare to change the username and password, you need to take care of the following: From [MS-SCMR], section 3.1.4.12 The server MUST treat the lpPassword as a clear-text password if the client is using RPC over TCP, ncacn_ip_tcp (as specified in [MS-RPCE]). See section 2.1.2 Client. The server MUST treat the lpPassword as encrypted and decrypt it, if the client is using a RPC over NP, ncacn_np (as specified in [MS-RPCE]). The server MUST first retrieve a session key as specified in [MS-CIFS] (section 3.5.4.4). An RPC server application requests the session key of a client and then uses the routine as specified in [MS-LSAD] (section 5.1.2) to decrypt the password. It's your reponsibility to fill out the right password data in the password parameter """ changeConfig = SVCCTLRChangeServiceConfigW() changeConfig['ContextHandle'] = handle if startType is not None: changeConfig['StartType'] = startType if binaryPathName is not None: changeConfig['BinaryPathName'] = ndrutils.NDRUniqueStringW() changeConfig['BinaryPathName']['Data'] = ( binaryPathName + '\x00'.encode('utf-16le')) else: changeConfig['BinaryPathName'] = '\x00' * 4 if displayName is not None: changeConfig['DisplayName'] = ndrutils.NDRUniqueStringW() changeConfig['DisplayName']['Data'] = (displayName + '\x00'.encode('utf-16le')) else: changeConfig['DisplayName'] = '\x00' * 4 if serviceType is not None: changeConfig['ServiceType'] = serviceType if serviceStartName is not None: if serviceStartName.find('\\') <= 0: # Local user, we gotta append .\ serviceStartName = '.\\'.encode('utf-16le') + serviceStartName changeConfig['ServiceStartName'] = ndrutils.NDRUniqueStringW() changeConfig['ServiceStartName']['Data'] = ( serviceStartName + '\x00'.encode('utf-16le')) else: changeConfig['ServiceStartName'] = '\x00' * 4 if password is not None: data = password changeConfig['Password'] = pack('<L', random.randint(1, 65535)) changeConfig['Password'] += pack('<L', len(password)) changeConfig['Password'] += data changeConfig['PwSize'] = len(password) else: changeConfig['Password'] = '******' * 4 ans = self.doRequest(changeConfig, checkReturn=1) return ans