import cmd
import sys
import argparse
import threading
from covertutils.handlers.multi import MultiHandler
#
# The idea is to pass a list of handlers to start with, and create a MultiHandler object from this list.
#
# The initial arguments for this should be a list of Shells. From shells, the handlers will be retrieved and from there, the MultiHandler object will be created
#
try:
raw_input # Python 2
except NameError:
raw_input = input # Python 3
[docs]class CLIArgumentParser( argparse.ArgumentParser ) :
[docs] def exit(self, ex_code = 1, message = "Unrecognised") :
# print message
# print '[!] [EXIT] - ', ex_code, message
return
[docs] def error(self, message) : print (message)
[docs]class MultiShell( cmd.Cmd ) :
[docs] def __init__( self, shells = [], output = None ) :
cmd.Cmd.__init__(self)
self.shells = {}
for shell in shells :
self.__add_handler_shell( shell )
self.prompt = 'covertpreter> '
def __add_handler_shell( self, shell ) :
self.shells[shell.handler.getOrchestrator().getIdentity()] = shell
[docs] def list_sessions( self, verbose = False ) :
handlers = [shell.handler for shell in self.shells.values()]
to_show = []
for orch_id, shell in self.shells.iteritems() :
# print shell.sysinfo
try :
sysinfo = shell.sysinfo
sysinfo = ' - '.join([sysinfo[i] for i in (0,4,3,8)]) # hostname, distro, locale, user
except Exception as e:
# print e
sysinfo = None # Could dispatch selectively a 'SI' command
handler = shell.handler
if verbose :
streams = handler.getOrchestrator().getStreams()
else :
streams = []
to_show.append( {'row' : (orch_id, handler.__class__) , 'streams' : streams, 'info' : sysinfo } )
print ("\tCurrent Sessions:")
for i, sess_dict in enumerate(to_show) :
# print row
row = sess_dict['row']
streams = sess_dict['streams']
num_row = "%d) {:16} - {}" % (i)
print ( num_row.format(*row) )
if sess_dict['info'] :
print sess_dict['info']
else :
print "System Info: N/A"
for stream in streams :
print ("\t-> {}".format(stream))
print ('\n')
[docs] def default(self, line) :
if not line :
return
arg_parser = CLIArgumentParser(prog = "\n%s" % self.prompt)
arg_parser.add_argument("SESSIONS", nargs = '*', help = 'The SESSIONS IDs that the MESSAGE must be sent to. If not provided, it defaults to ALL SESSIONS', default = None)
arg_parser.add_argument("STREAM", type = str, help = 'The STREAM to send the MESSAGE. If a SESSION does not support the provided STREAM, it will be omitted')
arg_parser.add_argument("MESSAGE", type = str, default = None, help = "The MESSAGE to send to the selected SESSIONS")
try :
args = arg_parser.parse_args( line.split() )
except Exception as e :
print e
return
if args.MESSAGE == None :
# print arg_parser.print_help()
return
# print args
if not args.SESSIONS :
print "No sessions selected, ALL sessions will be commanded" # Warning
# [y/n] thing
resp = raw_input("Are you sure? [y/N]: ")
if resp.lower() != 'y' :
return
else :
args.SESSIONS = self.shells.keys()
for session_id in args.SESSIONS :
if session_id in self.shells.keys() :
shell = self.shells[session_id]
command = "{stream_char}{stream} {message}".format(
stream_char = shell.stream_preamp_char,
stream = args.STREAM,
message = args.MESSAGE,
)
print ( "'%s' -> <%s>" % (command, session_id) )
shell.onecmd( command )
[docs] def do_session( self, line ) :
arg_parser = CLIArgumentParser(prog = "session")
arg_parser.add_argument("-i", "--session_num", help = "Jumps to the shell designated by the SESSION_NUM", type = int, required = False)
arg_parser.add_argument("-s", "--session_id", help = "Jumps to the shell designated by the SESSIONS_ID", type = str, required = False)
arg_parser.add_argument("-l", "--list", help = "Lists all current Session Shells", action = 'store_true' )
arg_parser.add_argument("-v", help = "Verbose output of '-l'", action = 'store_true' )
try :
args = arg_parser.parse_args( line.split() )
except Exception as e :
print e
return
# print args
if args.list :
return self.list_sessions( args.v )
try :
i = args.session_num
# print list(self.shells)[i]
shell = self.shells.values()[i]
return shell.start(False)
except Exception as e:
# print e
pass
if args.session_id in self.shells.keys() :
shell = self.shells[args.session_id]
return shell.start(False)
[docs] def do_handler( self, line ) :
arg_parser = CLIArgumentParser(prog='handler')
subparsers = arg_parser.add_subparsers(help='command for the handler', dest="command")
parser_add = subparsers.add_parser('add', help='Add a Handler in a new Thread and start a session')
parser_add.add_argument("SCRIPT", help = "The file that contains the Handler in Python 'covertutils' code", type = str)
parser_add.add_argument("ARGUMENTS", help = "The arguments passed to the Python 'covertutils' handler script", type = str, default = '', nargs = '*')
parser_add.add_argument("--shell", '-s', help = "The argument in the Python code that contains the 'covertutils.shell.baseshell.BaseShell' implementation",
type = str, default = 'shell')
parser_del = subparsers.add_parser('del', help='Delete a Handler')
parser_del.add_argument("SESSION_ID", help = "The ID of the SESSION to purge", type = str)
parser_del.add_argument("--kill", '-k', help = "Send 'KILL' command to the corresponding Agent [TODO]", action = 'store_true', default = False)
args = arg_parser.parse_args(line.split())
# print args
if args.command == 'add' :
if args.SCRIPT == None :
print arg_parser.print_help()
return
filename = args.SCRIPT
arguments = args.ARGUMENTS
shell_var = args.shell
mount_thread = threading.Thread( target = self.mount_new_handler, args = ( filename, arguments, shell_var ) )
mount_thread.daemon = True
mount_thread.start()
elif args.command == 'del' :
if args.SESSION_ID == None :
print arg_parser.print_help()
return
self.unmount_handler(args.SESSION_ID, args.kill)
[docs] def unmount_handler( self, orch_id, kill = False ) :
if orch_id in self.shells.keys() :
if kill :
self.shells[orch_id].onecmd("!control kill")
self.shells[orch_id].handler.stop()
# self.shells[orch_id].handler.receive_function = None
del self.shells[orch_id]
[docs] def mount_new_handler( self, filename, arguments, shell_var = 'shell' ) : # handler add examples/tcp_reverse_handler.py 8080 Pa55phra531
variables = ['handler_filaneme.py'] + arguments
sys.argv = variables
print variables
with open(filename, 'r') as handler_codefile :
handler_code = handler_codefile.read()
# namespace_dict = locals()
namespace_dict = {}
handler_code = handler_code.replace("%s.start()" % shell_var, 'pass') # Replace the blocking command of the shell
# exec( handler_code )
exec( handler_code, namespace_dict )
print namespace_dict[shell_var]
self.__add_handler_shell( namespace_dict[shell_var] )
print "Added Session!"
[docs] def emptyline( self ) : return
[docs] def do_EOF( self, *args ) : return
[docs] def do_exit( self, *args ) : return self.do_q( *args )
[docs] def do_quit( self, *args ) : return self.do_q( *args )
[docs] def do_q( self, *args ) : return self.quitPrompt()
[docs] def quitPrompt( self, *args ) :
# print( args )
exit_input = raw_input("[!]\tQuit shell? [y/N] ")
if exit_input.lower() == 'y' :
print( "Aborted by the user..." )
# sys.exit(0)
return True
return False
[docs] def start( self, warn = True ) :
# try :
while True :
ret = None
try :
ret = self.cmdloop()
# if ret :
break
except KeyboardInterrupt :
print ("\n[!] For exiting use [q|quit|exit]")