996 lines
34 KiB
Python
996 lines
34 KiB
Python
|
"""
|
||
|
Fuzzbunch command shell.
|
||
|
|
||
|
- Implements (or inherits from FbCmd class) all core fuzzbunch commands.
|
||
|
- Support for Modules (plugin managers)
|
||
|
|
||
|
Modules add additional commands and operate in their own context
|
||
|
|
||
|
"""
|
||
|
import os
|
||
|
from command import FbCmd
|
||
|
import exception
|
||
|
import redirection
|
||
|
import session
|
||
|
import util
|
||
|
import figlet
|
||
|
import edfmeta
|
||
|
from log import log
|
||
|
__all__ = ['Fuzzbunch']
|
||
|
|
||
|
GVAR_CHAR = '$'
|
||
|
class Fuzzbunch(FbCmd):
|
||
|
"""
|
||
|
Fuzzbunch, in and of itself, is an execution environment. It provides a set of
|
||
|
commands and contexts to interact with.
|
||
|
|
||
|
The Fuzzbunch class is really an extension of the FbCmd class, which allows it to add
|
||
|
additional, context-specific commands to the general command line handling. The base
|
||
|
set of commands it adds to the FbCmd class are:
|
||
|
* autorun
|
||
|
* banner
|
||
|
* back
|
||
|
* enter
|
||
|
* exit
|
||
|
* mark
|
||
|
* redirect
|
||
|
* retarget
|
||
|
* session
|
||
|
* setg
|
||
|
* show
|
||
|
* standardop
|
||
|
* toolpaste
|
||
|
* unsetg
|
||
|
* use
|
||
|
|
||
|
For information regarding these commands, please run Fuzzbunch and type 'help <cmd>' at
|
||
|
the command prompt.
|
||
|
|
||
|
"""
|
||
|
def __init__(self,
|
||
|
configfile,
|
||
|
base_dir,
|
||
|
log_dir,
|
||
|
stdin=None,
|
||
|
stdout=None,
|
||
|
stderr=None):
|
||
|
"""@brief Initialize the Fuzzbunch object
|
||
|
|
||
|
@param configfile The main Fuzzbunch configuration file (an XML file)
|
||
|
@param base_dir
|
||
|
@param log_dir Location for Fuzzbunch log files
|
||
|
@param stdin
|
||
|
@param stdout
|
||
|
@param stderr
|
||
|
"""
|
||
|
|
||
|
# Initialize the command interpreter, which creates a CmdCtx
|
||
|
self.configvars = {} # Stores global config info (not setg globals)
|
||
|
self.readconfig(configfile) # Read in variables set for Fuzzbunch
|
||
|
|
||
|
# Fix bug #2910 - Color breaks in some terminals that don't support ansi encoding. Added
|
||
|
# option to disable color
|
||
|
enablecolor = eval(self.configvars['globals']['Color'])
|
||
|
FbCmd.__init__(self, stdin=stdin, stdout=stdout, stderr=stderr, enablecolor=enablecolor )
|
||
|
|
||
|
# Set the info function to Fuzzbunch's print_info function
|
||
|
self.defaultcontext.print_info = self.print_info
|
||
|
self.preconfig()
|
||
|
|
||
|
self.fbglobalvars = util.iDict() # Our Fuzzbunch global variables
|
||
|
self.pluginmanagers = util.iDict() # A list of PluginManagers, each
|
||
|
# of which contains a list of Plugins.
|
||
|
|
||
|
# Create our Session manager, which has a list of the plugins we've run
|
||
|
self.session = session.Session(self.name)
|
||
|
self.session.set_dirs(base_dir, log_dir)
|
||
|
|
||
|
# Set the logdir from the Fuzzbunch.xml file, which will be overridden
|
||
|
# later when retarget is executed
|
||
|
self.default_logdir = os.path.normpath(log_dir)
|
||
|
self.set_logdir(log_dir)
|
||
|
|
||
|
# Create a Redirection object to keep track of the status of redirection, and to
|
||
|
# perform transforms on the parameters prior to and after executing plugins
|
||
|
self.redirection = redirection.RedirectionManager(self.io)
|
||
|
|
||
|
self.fontdir = os.path.join(base_dir, "fonts")
|
||
|
self.storage = os.path.join(base_dir, "storage")
|
||
|
self.setbanner()
|
||
|
self.postconfig()
|
||
|
self.pwnies = False
|
||
|
|
||
|
self.conv_tools = util.iDict([('MultiLine', self.toolpaste_ep),
|
||
|
('MD5', self.toolpaste_md5),
|
||
|
('SHA1', self.toolpaste_sha1),
|
||
|
('Base64', self.toolpaste_base64),
|
||
|
])
|
||
|
|
||
|
self.log = log(self.name, self.version, dict(debugging=True, enabled=True, verbose=False))
|
||
|
|
||
|
def precmd(self, line):
|
||
|
"""Intercept user cmd line to global replacement"""
|
||
|
newline = util.variable_replace(line, self.fbglobalvars)
|
||
|
return FbCmd.precmd(self, newline)
|
||
|
|
||
|
def print_info(self, *ignore):
|
||
|
self.do_banner("")
|
||
|
|
||
|
"""
|
||
|
Log directory handling
|
||
|
|
||
|
"""
|
||
|
def get_logdir(self):
|
||
|
"""Retrieve the current log directory"""
|
||
|
(base_dir, log_dir) = self.session.get_dirs()
|
||
|
return log_dir
|
||
|
|
||
|
def get_basedir(self):
|
||
|
"""Retrieve the current base directory"""
|
||
|
(base_dir, log_dir) = self.session.get_dirs()
|
||
|
return base_dir
|
||
|
|
||
|
def set_logdir(self, log_dir=None):
|
||
|
"""Set the current log directory and create a new log file"""
|
||
|
if not log_dir:
|
||
|
log_dir = os.path.normpath(self.default_logdir)
|
||
|
|
||
|
base_dir = self.get_basedir()
|
||
|
self.session.set_dirs(base_dir, log_dir)
|
||
|
|
||
|
logname = "fuzzbunch-%s.log" % util.formattime()
|
||
|
self.io.setlogfile(os.path.join(log_dir, logname))
|
||
|
|
||
|
|
||
|
"""
|
||
|
Banners
|
||
|
|
||
|
"""
|
||
|
def getstats(self):
|
||
|
""" Return stats in the form of tuple(count, type)"""
|
||
|
return [ (len(list(m.get_plugins())), m.get_type())
|
||
|
for m in self.get_manager_list() ]
|
||
|
|
||
|
def setbanner(self):
|
||
|
"""Set the Fuzzbunch banner (seen when starting fuzzbunch)"""
|
||
|
self.banner, font = figlet.newbanner(self.fontdir, self.bannerstr)
|
||
|
#self.io.write("FONT: %s" % font)
|
||
|
|
||
|
def printbanner(self):
|
||
|
"""Print the currently configured banner"""
|
||
|
banner = {'banner' : self.banner,
|
||
|
'version' : self.version,
|
||
|
'stats' : self.getstats()}
|
||
|
self.io.print_banner(banner)
|
||
|
|
||
|
"""
|
||
|
CMD: Banner
|
||
|
|
||
|
"""
|
||
|
def help_banner(self):
|
||
|
usage = ["banner",
|
||
|
"Print the startup banner"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_banner(self, line):
|
||
|
"""Print the startup banner"""
|
||
|
line = line.strip().split()
|
||
|
if line:
|
||
|
savedbanner = self.bannerstr
|
||
|
self.bannerstr = " ".join(line)
|
||
|
self.setbanner()
|
||
|
self.printbanner()
|
||
|
if line:
|
||
|
self.bannerstr = savedbanner
|
||
|
|
||
|
"""
|
||
|
Console Handlers
|
||
|
"""
|
||
|
def do_resizeconsole(self, line):
|
||
|
try:
|
||
|
import readline
|
||
|
readline.GetOutputFile().size(width=90,height=65)
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
|
||
|
"""
|
||
|
Config File
|
||
|
|
||
|
"""
|
||
|
|
||
|
def readconfig(self, file):
|
||
|
"""Parse the Fuzzbunch.xml file to setup the Fuzzbunch initial environment"""
|
||
|
try:
|
||
|
import xml.dom.minidom
|
||
|
xmlDoc = xml.dom.minidom.parse(file)
|
||
|
|
||
|
config = edfmeta.get_elements(xmlDoc, "config")[0]
|
||
|
redir = edfmeta.get_elements(config, "redirection")[0]
|
||
|
runmode = edfmeta.get_elements(config, "runmode")[0]
|
||
|
banner = edfmeta.get_elements(config, "banner")[0]
|
||
|
scripts = edfmeta.get_elements(config, "autorun")[0]
|
||
|
|
||
|
automode = str(scripts.getAttribute("value"))
|
||
|
if automode.lower() == "on":
|
||
|
automode = True
|
||
|
else:
|
||
|
automode = False
|
||
|
autorun = {}
|
||
|
# 'scripts' contains auto-run scripts. Get them and set up autorun commands
|
||
|
for cat in edfmeta.get_elements(scripts, "category"):
|
||
|
autorun[str(cat.getAttribute("name"))] = []
|
||
|
for command in edfmeta.get_elements(cat, "command"):
|
||
|
autorun[str(cat.getAttribute("name"))].append((command.getAttribute("value"),
|
||
|
command.getAttribute("msg")))
|
||
|
|
||
|
params = {"name" : str(config.getAttribute("name")),
|
||
|
"version" : str(config.getAttribute("version")),
|
||
|
"banner" : str(banner.getAttribute("value")),
|
||
|
"globals" : {},
|
||
|
"redirection" : {"value" : str(redir.getAttribute("value"))},
|
||
|
"runmode" : str(runmode.getAttribute("value")),
|
||
|
"automode" : automode,
|
||
|
"autorun" : autorun
|
||
|
}
|
||
|
for param in edfmeta.get_elements(config, "parameter"):
|
||
|
key = str(param.getAttribute("name"))
|
||
|
params['globals'][key] = str(param.getAttribute("default"))
|
||
|
except:
|
||
|
self.configfile = None
|
||
|
params = {}
|
||
|
self.configfile = file
|
||
|
self.configvars = params
|
||
|
|
||
|
def preconfig(self):
|
||
|
try:
|
||
|
self.name = self.configvars['name']
|
||
|
self.bannerstr = self.configvars['banner']
|
||
|
self.version = self.configvars['version']
|
||
|
except:
|
||
|
self.name = "Fuzzbunch"
|
||
|
self.bannerstr = "FUZZBUNCH"
|
||
|
self.version = "2.0"
|
||
|
# Override the default context's name and type
|
||
|
self.defaultcontext.set_name(self.name)
|
||
|
self.defaultcontext.set_type(self.name)
|
||
|
|
||
|
def postconfig(self):
|
||
|
try:
|
||
|
if self.configvars['redirection']['value'].lower() == "off":
|
||
|
self.redirection.off()
|
||
|
else:
|
||
|
self.redirection.on()
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
fntab = {"interactive" : self.runmode_interactive,
|
||
|
"noninteractive" : self.runmode_noninteractive,
|
||
|
"scripted" : lambda: (self.runmode_interactive(),
|
||
|
self.scripting(True))}
|
||
|
try:
|
||
|
fntab[self.configvars['runmode'].lower()]()
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
try:
|
||
|
self.cmdqueue.append("echo Initializing %s v%s" % (self.name,self.version))
|
||
|
self.cmdqueue.append("echo Adding Global Variables")
|
||
|
for item in self.configvars['globals'].items():
|
||
|
self.cmdqueue.append("setg %s %s" % item)
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
try:
|
||
|
self.autorunvars = self.configvars['autorun']
|
||
|
self.autorun = self.configvars['automode']
|
||
|
self.cmdqueue.append("autorun")
|
||
|
except:
|
||
|
pass
|
||
|
if "LogDir" not in self.configvars['globals']:
|
||
|
self.cmdqueue.append("setg LogDir %s" % self.default_logdir)
|
||
|
self.cmdqueue.append("setg FbStorage %s" % self.storage)
|
||
|
|
||
|
"""
|
||
|
Plugin manager handling
|
||
|
|
||
|
"""
|
||
|
|
||
|
def register_manager(self, type, typeConstructor):
|
||
|
"""Register a manager with Fuzzbunch. Initially these are PluginManager objects"""
|
||
|
if type in self.pluginmanagers:
|
||
|
raise exception.CmdErr, "'%s' already registered" % type
|
||
|
self.pluginmanagers[type] = typeConstructor(type, self)
|
||
|
return self.pluginmanagers[type]
|
||
|
|
||
|
def unregister_manager(self, type):
|
||
|
try:
|
||
|
del self.pluginmanagers[type]
|
||
|
except KeyError:
|
||
|
raise exception.CmdErr, "'%s' not a registered manager type" % type
|
||
|
|
||
|
def get_manager_types(self):
|
||
|
return self.pluginmanagers.keys()
|
||
|
|
||
|
def get_manager_counts(self):
|
||
|
return [ len(list(x.get_plugins())) for x in self.get_manager_list() ]
|
||
|
|
||
|
def get_active_plugin_names(self):
|
||
|
return [ (x.get_type(), x.get_active_name()) for x in self.get_manager_list() ]
|
||
|
|
||
|
def get_manager(self, type):
|
||
|
try:
|
||
|
return self.pluginmanagers[type]
|
||
|
except KeyError:
|
||
|
raise exception.CmdErr, "'%s' not a registered manager type" % type
|
||
|
|
||
|
def get_manager_list(self):
|
||
|
for manager in self.pluginmanagers.values():
|
||
|
yield manager
|
||
|
return
|
||
|
|
||
|
|
||
|
"""
|
||
|
CMD: Quit
|
||
|
|
||
|
"""
|
||
|
def do_quit(self, arg):
|
||
|
"""Quit fuzzbunch"""
|
||
|
try:
|
||
|
opencontracts = [ item.name
|
||
|
for item in self.session.get_itemlist()
|
||
|
if item.value.has_opencontract() ]
|
||
|
if opencontracts:
|
||
|
self.io.print_opensessions({'sessions' : opencontracts})
|
||
|
|
||
|
line = self.io.get_input("Really quit [n] ? ")
|
||
|
if line.lower() not in ("yes", "y", "q", "quit"):
|
||
|
return
|
||
|
if self.log: self.log.close()
|
||
|
return True
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
return True
|
||
|
|
||
|
"""
|
||
|
Context handling user commands
|
||
|
|
||
|
"""
|
||
|
|
||
|
|
||
|
"""
|
||
|
CMD: Info
|
||
|
|
||
|
"""
|
||
|
def help_info(self):
|
||
|
usage = ["info",
|
||
|
"Print information about the current context"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_info(self, *ignore):
|
||
|
"""Print information about the current context"""
|
||
|
self.getcontext().print_info()
|
||
|
|
||
|
"""
|
||
|
CMD: Back
|
||
|
|
||
|
"""
|
||
|
def help_back(self):
|
||
|
usage = ["back",
|
||
|
"Leave the context current plugin back to the default"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_back(self, *ignore):
|
||
|
"""Leave the current context back to the default"""
|
||
|
self.setcontext(None)
|
||
|
self.setprompt()
|
||
|
|
||
|
"""
|
||
|
CMD: Exit
|
||
|
|
||
|
"""
|
||
|
def help_exit(self):
|
||
|
usage = ["exit",
|
||
|
"Leave the context current plugin back to the default"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_exit(self, arg):
|
||
|
"""Alias for back"""
|
||
|
return self.do_back(arg)
|
||
|
|
||
|
"""
|
||
|
CMD: Autorun
|
||
|
|
||
|
"""
|
||
|
def complete_autorun(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion routine for autorun"""
|
||
|
if state == 1:
|
||
|
return [item for item in ("on","off") if item.lower().startswith(text.lower())]
|
||
|
return [""]
|
||
|
|
||
|
def help_autorun(self):
|
||
|
usage = ["autorun [mode]",
|
||
|
"Enable (on) or disable (off) autorun features"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_autorun(self, input):
|
||
|
"""Set autorun mode"""
|
||
|
argc, argv = util.parseinput(input, 1)
|
||
|
|
||
|
if argc == 0:
|
||
|
self.io.print_autoruncmds(self.autorun, self.autorunvars)
|
||
|
else:
|
||
|
if argv[0].lower() in ("on", "enabled", "yes"):
|
||
|
self.autorun = True
|
||
|
self.io.print_msg("Autorun is ON")
|
||
|
elif argv[0].lower() in ("off", "disabled", "no"):
|
||
|
self.autorun = False
|
||
|
self.io.print_msg("Autorun is OFF")
|
||
|
|
||
|
"""
|
||
|
CMD: Enter
|
||
|
|
||
|
"""
|
||
|
def complete_enter(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion routine for enter."""
|
||
|
if state == 1:
|
||
|
return [item
|
||
|
for item in self.get_manager_types()
|
||
|
if item.upper().startswith(text.upper())]
|
||
|
return [""]
|
||
|
|
||
|
def help_enter(self):
|
||
|
usage = ["enter [type]",
|
||
|
"Enter the context of the given plugin type"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_enter(self, input):
|
||
|
"""Enter the context of a plugin"""
|
||
|
argc, argv = util.parseinput(input, 1)
|
||
|
|
||
|
if argc == 0:
|
||
|
self.io.print_module_types({'modules' : self.get_active_plugin_names()})
|
||
|
else:
|
||
|
manager = self.get_manager(argv[0])
|
||
|
if manager is None:
|
||
|
raise exception.CmdErr, "No plugin type for %s" % argv[0]
|
||
|
|
||
|
if manager.get_active_name() is "None":
|
||
|
raise exception.CmdErr, "No active plugin for %s" % argv[0]
|
||
|
|
||
|
self.setcontext(manager)
|
||
|
self.setprompt()
|
||
|
|
||
|
"""
|
||
|
CMD: Use
|
||
|
|
||
|
"""
|
||
|
def complete_use(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion routine for use."""
|
||
|
typeList = self.get_manager_types()
|
||
|
|
||
|
if state == 1:
|
||
|
pluginlist = []
|
||
|
for manager in self.get_manager_list():
|
||
|
pluginlist += manager.get_plugin_names()
|
||
|
return [item
|
||
|
for item in sorted(pluginlist)
|
||
|
if item.upper().startswith(text.upper())]
|
||
|
else:
|
||
|
return []
|
||
|
|
||
|
def help_use(self):
|
||
|
usage = ["use [name]",
|
||
|
"Set the active plugin and enter the context of"
|
||
|
"the plugin"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_use(self, input):
|
||
|
"""Activate a plugin for use and enter context"""
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
if argc == 0:
|
||
|
for manager in self.get_manager_list():
|
||
|
plugins = [ (plugin.getName(), plugin.getVersion())
|
||
|
for plugin in manager.get_plugins() ]
|
||
|
args = {'module' : manager.get_name(),
|
||
|
'plugins' : plugins}
|
||
|
self.io.print_module_lists(args)
|
||
|
elif argc == 1:
|
||
|
for manager in self.get_manager_list():
|
||
|
if argv[0].lower() in [x.lower() for x in manager.get_plugin_names()]:
|
||
|
manager.set_active_plugin(argv[0])
|
||
|
plugin = manager.get_active_plugin()
|
||
|
self.io.newline()
|
||
|
self.io.print_warning("Entering Plugin Context :: %s" % plugin.getName())
|
||
|
self.io.print_msg("Applying Global Variables")
|
||
|
try:
|
||
|
plugin.setParameters(self.fbglobalvars)
|
||
|
except:
|
||
|
pass
|
||
|
self.io.newline()
|
||
|
self.do_enter(manager.get_type())
|
||
|
# At this point, grab anything that is setup to execute
|
||
|
# automatically according to the Fuzzbunch.xml file and
|
||
|
# execute it. This is where 'apply' will get run when you
|
||
|
# enter a context
|
||
|
if self.autorun:
|
||
|
for auto,msg in self.autorunvars.get(manager.get_type(), []):
|
||
|
if msg:
|
||
|
self.runcmd_noex("echo %s" % msg)
|
||
|
self.runcmd_noex(auto)
|
||
|
break
|
||
|
else:
|
||
|
raise exception.CmdErr, "Plugin %s not found!" % argv[0]
|
||
|
|
||
|
"""
|
||
|
CMD: Show
|
||
|
|
||
|
"""
|
||
|
def complete_show(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion routine for show."""
|
||
|
typeList = self.get_manager_types()
|
||
|
if state == 1:
|
||
|
return [item
|
||
|
for item in sorted(typeList)
|
||
|
if item.upper().startswith(text.upper())]
|
||
|
elif state == 2:
|
||
|
if arglist[1] not in typeList:
|
||
|
return [""]
|
||
|
else:
|
||
|
pluginList = self.get_manager(arglist[1]).get_plugin_names()
|
||
|
return [item
|
||
|
for item in pluginList
|
||
|
if item.upper().startswith(text.upper())]
|
||
|
else:
|
||
|
return []
|
||
|
|
||
|
def help_show(self):
|
||
|
usage = ["show [type] [name]",
|
||
|
"Show information about the types and specific plugins"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_show(self, input):
|
||
|
"""Show plugin info"""
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
|
||
|
if argc == 0:
|
||
|
self.io.print_module_types({'modules' : self.get_active_plugin_names()})
|
||
|
elif argc == 1:
|
||
|
plugins = [ (plugin.getName(), plugin.getVersion())
|
||
|
for plugin in self.get_manager(argv[0]).get_plugins() ]
|
||
|
args = {'module' : argv[0],
|
||
|
'plugins' : plugins}
|
||
|
self.io.print_module_lists(args)
|
||
|
elif argc == 2:
|
||
|
self.get_manager(argv[0]).print_info(argv[1])
|
||
|
|
||
|
|
||
|
"""
|
||
|
Contract handling user commands
|
||
|
|
||
|
"""
|
||
|
|
||
|
"""
|
||
|
CMD: Session
|
||
|
|
||
|
"""
|
||
|
def complete_session(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion for session command."""
|
||
|
itemList = [str(i)
|
||
|
for i,item in enumerate(sorted(self.session.get_itemlist()))]
|
||
|
if state == 1:
|
||
|
return [i for i in itemList if i.startswith(text)]
|
||
|
return [""]
|
||
|
|
||
|
def help_session(self):
|
||
|
usage = ["session [index]",
|
||
|
"Show inheritable plugin settings from session"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_session(self, input):
|
||
|
"""Show session items"""
|
||
|
argc, argv = util.parseinput(input, 1)
|
||
|
|
||
|
if argc == 0:
|
||
|
items = [ (item.value.get_longname(), item.value.get_status())
|
||
|
for item in self.session.get_itemlist() ]
|
||
|
self.io.print_session_items({'items' : items})
|
||
|
else:
|
||
|
try:
|
||
|
index = int(argv[0])
|
||
|
except ValueError:
|
||
|
raise exception.CmdErr, "Invalid index"
|
||
|
|
||
|
item = self.session.get_item(index)
|
||
|
args = {'name' : item.get_name(),
|
||
|
'status' : item.get_status(),
|
||
|
'info' : item.get_info()}
|
||
|
self.io.print_session_item(args)
|
||
|
|
||
|
"""
|
||
|
CMD: Mark
|
||
|
|
||
|
"""
|
||
|
def complete_mark(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion for mark command."""
|
||
|
itemList = [str(i)
|
||
|
for i,item in enumerate(sorted(self.session.get_itemlist()))]
|
||
|
if state == 1:
|
||
|
return [i for i in itemList if i.startswith(text)]
|
||
|
elif state == 2:
|
||
|
if arglist[1] not in itemList:
|
||
|
return [""]
|
||
|
else:
|
||
|
markingList = ["READY", "RUNNING", "FAIL", "USED"]
|
||
|
return [item for item in markingList if item.startswith(text.upper())]
|
||
|
return [""]
|
||
|
|
||
|
def help_mark(self):
|
||
|
usage = ["mark [index] [value]",
|
||
|
"Mark a session item with a new status",
|
||
|
"Valid markings:",
|
||
|
" READY Plugin settings are ready to be used",
|
||
|
" RUNNING Plugin is not finished executing",
|
||
|
" FAIL Plugin failed to complete successfully",
|
||
|
" USED Plugin settings have been used"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_mark(self, input):
|
||
|
"""Mark a session item"""
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
|
||
|
if argc == 0:
|
||
|
return self.do_session(input)
|
||
|
elif argc == 1:
|
||
|
return self.help_mark()
|
||
|
elif argc == 2:
|
||
|
try:
|
||
|
index = int(argv[0])
|
||
|
value = argv[1]
|
||
|
except (IndexError, ValueError):
|
||
|
raise exception.CmdErr, "Invalid index"
|
||
|
|
||
|
item = self.session.get_item(index)
|
||
|
item.set_status(value)
|
||
|
self.io.print_success("Item marked as %s" % value)
|
||
|
|
||
|
"""
|
||
|
Redirection support
|
||
|
|
||
|
"""
|
||
|
|
||
|
"""
|
||
|
CMD: Redirect
|
||
|
|
||
|
"""
|
||
|
def complete_redirect(self, text, line, arglist, state, begidx, endidx):
|
||
|
"""Command completion routine for redirect"""
|
||
|
if state == 1:
|
||
|
return [item for item in ("on","off")
|
||
|
if item.lower().startswith(text.lower())]
|
||
|
return [""]
|
||
|
|
||
|
def help_redirect(self):
|
||
|
usage = ["redirect [on|off]",
|
||
|
"Turn redirection on or off. If no arguments, then",
|
||
|
"displays the known redirection state."]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_redirect(self, input):
|
||
|
"""Configure redirection"""
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
self.io.newline()
|
||
|
if argc == 0:
|
||
|
# No arguments on command line. Print the status of redirection
|
||
|
if self.redirection.is_active():
|
||
|
self.io.print_success("Redirection ON")
|
||
|
else:
|
||
|
self.io.print_warning("Redirection OFF")
|
||
|
elif argc == 1:
|
||
|
# Set redirection to on or off
|
||
|
if argv[0].lower() in ("off", "no"):
|
||
|
self.redirection.off()
|
||
|
self.io.print_warning("Redirection OFF")
|
||
|
elif argv[0].lower() in ("on", "yes"):
|
||
|
self.redirection.on()
|
||
|
self.io.print_success("Redirection ON")
|
||
|
else:
|
||
|
raise exception.CmdErr, "Invalid input"
|
||
|
|
||
|
|
||
|
"""
|
||
|
Global variable support
|
||
|
|
||
|
"""
|
||
|
|
||
|
"""
|
||
|
CMD: Setg
|
||
|
|
||
|
"""
|
||
|
def complete_setg(self, text, line, arglist, state, begidx, endidx):
|
||
|
if state == 1:
|
||
|
return [item[0]
|
||
|
for item in sorted(self.fbglobalvars.items())
|
||
|
if item[0].upper().startswith(text.upper())]
|
||
|
return [""]
|
||
|
|
||
|
def help_setg(self):
|
||
|
usage = ["setg [variable name] [value]",
|
||
|
"Set a global variable to value. If the variable",
|
||
|
"does not already exist then it will be created.",
|
||
|
" L:value - Input ascii string to widechar",
|
||
|
" H:value - Input hex string"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
@util.charconvert
|
||
|
def do_setg(self, input):
|
||
|
"""Set a global variable"""
|
||
|
readonly_globals = ["logdir", "tmpdir"]
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
if argc in (0,1):
|
||
|
args = {'title' : "Global Variables",
|
||
|
'vars' : self.fbglobalvars.items()}
|
||
|
self.io.print_set_names(args)
|
||
|
elif argc > 1:
|
||
|
inputList = input.strip().split()
|
||
|
value = " ".join(inputList[1:])
|
||
|
self.fbglobalvars[inputList[0]] = value
|
||
|
self.io.print_success("Set %s => %s" % (inputList[0], value))
|
||
|
if inputList[0].lower() == "logdir":
|
||
|
self.set_logdir(value)
|
||
|
self.fbglobalvars["TmpDir"] = value
|
||
|
elif inputList[0].lower() == "tmpdir":
|
||
|
raise exception.CmdErr, "TmpDir is readonly and set with LogDir"
|
||
|
elif inputList[0].lower() == "color":
|
||
|
# Supports fix for bug #2910
|
||
|
self.io.setcolormode( value.lower() == "true" )
|
||
|
|
||
|
"""
|
||
|
CMD: unsetg
|
||
|
"""
|
||
|
def complete_unsetg(self, text, line, begidx, endidx):
|
||
|
paramlist = self.fbglobalvars.items()
|
||
|
if begidx == 7:
|
||
|
return [item[0]
|
||
|
for item in sorted(paramlist)
|
||
|
if item[0].upper().startswith(text.upper())]
|
||
|
return [""]
|
||
|
|
||
|
def help_unsetg(self):
|
||
|
usage = ["unsetg [variable name]",
|
||
|
"Unset a global variable."]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_unsetg(self, input):
|
||
|
"""Unset a global variable"""
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
if argc == 0:
|
||
|
args = {'title' : "Global Variables",
|
||
|
'vars' : self.fbglobalvars.items()}
|
||
|
self.io.print_set_names(args)
|
||
|
else:
|
||
|
try:
|
||
|
del self.fbglobalvars[argv[0]]
|
||
|
except KeyError:
|
||
|
raise exception.CmdErr, "Invalid input"
|
||
|
self.io.print_success("Unset %s" % argv[0])
|
||
|
|
||
|
"""
|
||
|
CMD: Toolpaste
|
||
|
"""
|
||
|
def complete_toolpaste(self, text, line, arglist, state, begidx, endidx):
|
||
|
if state == 1:
|
||
|
return [item
|
||
|
for item in sorted(self.conv_tools.keys())
|
||
|
if item.upper().startswith(text.upper())]
|
||
|
return [""]
|
||
|
|
||
|
def toolpaste_base64(self, paramname):
|
||
|
import base64
|
||
|
input = self.io.get_input_line('Base64 > ')
|
||
|
if input:
|
||
|
input = base64.b64encode(input)
|
||
|
self.do_setg("%s %s" %(paramname, input))
|
||
|
else:
|
||
|
raise exception.CmdErr, "Invalid input"
|
||
|
|
||
|
def toolpaste_sha1(self, paramname):
|
||
|
import hashlib
|
||
|
input = self.io.get_input_line('SHA1 > ')
|
||
|
if input:
|
||
|
input = hashlib.sha1(input).hexdigest()
|
||
|
self.do_setg("%s h:%s" %(paramname, input))
|
||
|
else:
|
||
|
raise exception.CmdErr, "Invalid input"
|
||
|
|
||
|
def toolpaste_md5(self, paramname):
|
||
|
import hashlib
|
||
|
input = self.io.get_input_line('MD5 > ')
|
||
|
if input:
|
||
|
input = hashlib.md5(input).hexdigest()
|
||
|
self.do_setg("%s h:%s" %(paramname, input))
|
||
|
else:
|
||
|
raise exception.CmdErr, "Invalid input"
|
||
|
|
||
|
def toolpaste_ep(self, paramname):
|
||
|
input = self.io.get_input_lines('MultiLine > ')
|
||
|
self.do_setg("%s h:%s" %(paramname, input))
|
||
|
|
||
|
def help_toolpaste(self):
|
||
|
usage = ["toolpaste [operation type] [variable name]",
|
||
|
"Transforms pasted input and exports as global variable",
|
||
|
"Types:",
|
||
|
" MultiLine Multiline hex input from EP",
|
||
|
" MD5 MD5Sum of input",
|
||
|
" SHA1 SHA1 of input",
|
||
|
" Base64 Base64 of input"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def do_toolpaste(self, input):
|
||
|
"""Paste and convert data from external tool output"""
|
||
|
argc, argv = util.parseinput(input, 2)
|
||
|
if argc in (0,1):
|
||
|
self.help_toolpaste()
|
||
|
elif argc == 2:
|
||
|
try:
|
||
|
self.conv_tools[argv[0]](argv[1])
|
||
|
except KeyError:
|
||
|
raise exception.CmdErr, "Invalid input"
|
||
|
|
||
|
|
||
|
"""
|
||
|
Targetting support
|
||
|
|
||
|
"""
|
||
|
"""
|
||
|
CMD: Retarget
|
||
|
|
||
|
"""
|
||
|
def help_retarget(self):
|
||
|
usage = ["retarget",
|
||
|
"Retarget the current session"]
|
||
|
self.io.print_usage(usage)
|
||
|
|
||
|
def getip_prompt(self, prompt, default):
|
||
|
done = False
|
||
|
while not done:
|
||
|
try:
|
||
|
targetvar = self.io.prompt_user("Default " + prompt, default, gvars=self.fbglobalvars)
|
||
|
targetvar = util.validateip(targetvar)
|
||
|
if not targetvar:
|
||
|
raise exception.CmdErr, "Invalid " + prompt
|
||
|
except exception.PromptErr, err:
|
||
|
raise exception.PromptErr, err.error
|
||
|
except exception.PromptHelp, err:
|
||
|
pass
|
||
|
except exception.CmdErr, err:
|
||
|
self.io.print_error(err.getErr())
|
||
|
else:
|
||
|
done = True
|
||
|
return targetvar
|
||
|
|
||
|
def _get_projectlist(self, d):
|
||
|
"""Gets a list of directories, which should be coverterms"""
|
||
|
dirlist = []
|
||
|
try:
|
||
|
os.makedirs(d)
|
||
|
except:
|
||
|
if not os.path.exists(d):
|
||
|
raise
|
||
|
map(lambda x: os.path.isdir(os.path.join(d, x)) and dirlist.append(x), os.listdir(d))
|
||
|
return dirlist
|
||
|
|
||
|
def _prompt_for_project(self, projects):
|
||
|
try:
|
||
|
vals = [(str(i), v) for i,v in enumerate(projects)]
|
||
|
vals.append( tuple([str(len(vals)), "Create a New Project"]) )
|
||
|
widths = self.io.get_column_max_width(vals)
|
||
|
widths[0] = max(6, widths[0])
|
||
|
widths[1] = max(len("Project"), widths[1])
|
||
|
self.io.print_table(widths, [("Index", "Project")], vals)
|
||
|
c = self.io.prompt_user("Project", "0", gvars=self.fbglobalvars)
|
||
|
if int(c)+1 < len(vals):
|
||
|
try:
|
||
|
return projects[int(c)].lower()
|
||
|
except IndexError:
|
||
|
self.io.print_error("Invalid choice")
|
||
|
return None
|
||
|
elif int(c)+1 == len(vals):
|
||
|
return self.io.prompt_user("New Project Name", None, gvars=self.fbglobalvars).lower()
|
||
|
else:
|
||
|
self.io.print_error("Invalid choice")
|
||
|
return None
|
||
|
except KeyboardInterrupt:
|
||
|
raise
|
||
|
except:
|
||
|
return None
|
||
|
|
||
|
def _prompt_for_logging(self, target, oldproject):
|
||
|
try:
|
||
|
if oldproject is None:
|
||
|
oldproject = ''
|
||
|
base_logdir = self.get_logdir()
|
||
|
base_logdir = ''.join(base_logdir[:base_logdir.find(oldproject)])
|
||
|
if len(base_logdir) == 0:
|
||
|
base_logdir = self.get_logdir()
|
||
|
|
||
|
# Request #1699: Change to include compatible logging structure
|
||
|
self.io.newline()
|
||
|
log_dir = self.io.prompt_user("Base Log directory", base_logdir, gvars=self.fbglobalvars)
|
||
|
log_dir = os.path.abspath(log_dir)
|
||
|
|
||
|
# Get the list of projects
|
||
|
self.io.print_msg("Checking %s for projects" % (log_dir))
|
||
|
projects = self._get_projectlist(log_dir)
|
||
|
|
||
|
# Give the user the choice to use an existing project or create a new one
|
||
|
project = None
|
||
|
while project is None:
|
||
|
project = self._prompt_for_project(projects)
|
||
|
|
||
|
log_dir = os.path.join(log_dir, project, 'z'+target.replace(":", "_")) # To support IPv6 address in log files
|
||
|
if not self.io.prompt_yn("Set target log directory to '%s'?" % (log_dir)):
|
||
|
log_dir = self.io.prompt_user("Target log directory?", log_dir, gvars=self.fbglobalvars)
|
||
|
try:
|
||
|
os.makedirs(log_dir) # Fix from 3.2.0 - Don't reinvent the wheel
|
||
|
except:
|
||
|
if not os.path.exists(log_dir):
|
||
|
raise
|
||
|
self.set_logdir(log_dir)
|
||
|
return (project, log_dir)
|
||
|
except OSError:
|
||
|
self.io.print_warning("Access Denied to '%s'! Choose a different log directory." %(log_dir))
|
||
|
return (None, None)
|
||
|
|
||
|
|
||
|
def do_retarget(self, *ignore):
|
||
|
"""Set basic target info"""
|
||
|
self.do_back(self)
|
||
|
|
||
|
self.io.newline()
|
||
|
self.io.print_msg("Retargetting Session")
|
||
|
self.io.newline()
|
||
|
try:
|
||
|
target = self.getip_prompt("Target IP Address",
|
||
|
self.fbglobalvars.get('targetip', ''))
|
||
|
callback = self.getip_prompt("Callback IP Address", '')
|
||
|
redirection = self.io.prompt_user("Use Redirection", "yes")
|
||
|
if redirection.lower() in ("no", "n", "off"):
|
||
|
redirection = "off"
|
||
|
else:
|
||
|
redirection = "on"
|
||
|
# Setup logging
|
||
|
log_dir = None
|
||
|
project = self.fbglobalvars.get('project', '')
|
||
|
while log_dir is None:
|
||
|
(project, log_dir) = self._prompt_for_logging(target, project)
|
||
|
|
||
|
except (exception.PromptErr, exception.CmdErr), err:
|
||
|
self.io.print_error(err.getErr())
|
||
|
return
|
||
|
|
||
|
self.io.newline()
|
||
|
self.io.print_msg("Initializing Global State")
|
||
|
self.do_setg("TargetIp %s" % target)
|
||
|
self.do_setg("CallbackIp %s" % callback)
|
||
|
self.do_redirect(redirection)
|
||
|
self.do_setg("LogDir %s" % log_dir)
|
||
|
self.do_setg("Project %s" % (project))
|
||
|
self.io.newline()
|
||
|
if self.log:
|
||
|
if 'Project' in self.fbglobalvars: self.log.set(project_name=self.fbglobalvars['Project'])
|
||
|
self.log.open()
|
||
|
"""
|
||
|
CMD: Standard OP
|
||
|
|
||
|
"""
|
||
|
def help_standardop(self):
|
||
|
self.io.print_standardop()
|
||
|
|
||
|
def do_standardop(self, *ignore):
|
||
|
"""Print standard OP usage message"""
|
||
|
self.help_standardop()
|
||
|
|
||
|
|