Implementation for an Issue #832

This commit is contained in:
Miroslav Stampar 2014-09-16 14:12:43 +02:00
parent 57eb19377e
commit 7278af01ee
7 changed files with 124 additions and 20 deletions

View File

@ -342,3 +342,4 @@ class AUTH_TYPE:
class AUTOCOMPLETE_TYPE: class AUTOCOMPLETE_TYPE:
SQL = 0 SQL = 0
OS = 1 OS = 1
SQLMAP = 2

View File

@ -44,6 +44,9 @@ class SqlmapSilentQuitException(SqlmapBaseException):
class SqlmapUserQuitException(SqlmapBaseException): class SqlmapUserQuitException(SqlmapBaseException):
pass pass
class SqlmapShellQuitException(SqlmapBaseException):
pass
class SqlmapSyntaxException(SqlmapBaseException): class SqlmapSyntaxException(SqlmapBaseException):
pass pass

View File

@ -239,6 +239,7 @@ BASIC_HELP_ITEMS = (
"checkTor", "checkTor",
"flushSession", "flushSession",
"tor", "tor",
"sqlmapShell",
"wizard", "wizard",
) )
@ -583,6 +584,9 @@ MIN_BINARY_DISK_DUMP_SIZE = 100
# Regular expression used for extracting form tags # Regular expression used for extracting form tags
FORM_SEARCH_REGEX = r"(?si)<form(?!.+<form).+?</form>" FORM_SEARCH_REGEX = r"(?si)<form(?!.+<form).+?</form>"
# Maximum number of lines to save in history file
MAX_HISTORY_LENGTH = 1000
# Minimum field entry length needed for encoded content (hex, base64,...) check # Minimum field entry length needed for encoded content (hex, base64,...) check
MIN_ENCODED_LEN_CHECK = 5 MIN_ENCODED_LEN_CHECK = 5

View File

@ -15,12 +15,39 @@ from lib.core.data import logger
from lib.core.data import paths from lib.core.data import paths
from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import AUTOCOMPLETE_TYPE
from lib.core.enums import OS from lib.core.enums import OS
from lib.core.settings import MAX_HISTORY_LENGTH
def readlineAvailable():
"""
Check if the readline is available. By default
it is not in Python default installation on Windows
"""
return readline._readline is not None
def clearHistory():
if not readlineAvailable():
return
readline.clear_history()
def saveHistory(): def saveHistory():
if not readlineAvailable():
return
historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY)
try:
os.remove(historyPath)
except:
pass
readline.set_history_length(MAX_HISTORY_LENGTH)
readline.write_history_file(historyPath) readline.write_history_file(historyPath)
def loadHistory(): def loadHistory():
if not readlineAvailable():
return
historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY) historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY)
if os.path.exists(historyPath): if os.path.exists(historyPath):
@ -48,14 +75,12 @@ class CompleterNG(rlcompleter.Completer):
return matches return matches
def autoCompletion(completion=None): def autoCompletion(completion=None, os=None, commands=None):
# First of all we check if the readline is available, by default if not readlineAvailable():
# it is not in Python default installation on Windows
if not readline._readline:
return return
if completion == AUTOCOMPLETE_TYPE.OS: if completion == AUTOCOMPLETE_TYPE.OS:
if Backend.isOs(OS.WINDOWS): if os == OS.WINDOWS:
# Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands
completer = CompleterNG({ completer = CompleterNG({
"copy": None, "del": None, "dir": None, "copy": None, "del": None, "dir": None,
@ -76,5 +101,11 @@ def autoCompletion(completion=None):
readline.set_completer(completer.complete) readline.set_completer(completer.complete)
readline.parse_and_bind("tab: complete") readline.parse_and_bind("tab: complete")
elif commands:
completer = CompleterNG(dict(((_, None) for _ in commands)))
readline.set_completer_delims(' ')
readline.set_completer(completer.complete)
readline.parse_and_bind("tab: complete")
loadHistory() loadHistory()
atexit.register(saveHistory) atexit.register(saveHistory)

View File

@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
""" """
import os import os
import shlex
import sys import sys
from optparse import OptionError from optparse import OptionError
@ -17,13 +18,21 @@ from lib.core.common import checkDeprecatedOptions
from lib.core.common import checkSystemEncoding from lib.core.common import checkSystemEncoding
from lib.core.common import expandMnemonics from lib.core.common import expandMnemonics
from lib.core.common import getUnicode from lib.core.common import getUnicode
from lib.core.data import cmdLineOptions
from lib.core.data import conf
from lib.core.data import logger from lib.core.data import logger
from lib.core.defaults import defaults from lib.core.defaults import defaults
from lib.core.enums import AUTOCOMPLETE_TYPE
from lib.core.exception import SqlmapShellQuitException
from lib.core.settings import BASIC_HELP_ITEMS from lib.core.settings import BASIC_HELP_ITEMS
from lib.core.settings import DUMMY_URL from lib.core.settings import DUMMY_URL
from lib.core.settings import IS_WIN from lib.core.settings import IS_WIN
from lib.core.settings import MAX_HELP_OPTION_LENGTH from lib.core.settings import MAX_HELP_OPTION_LENGTH
from lib.core.settings import VERSION_STRING from lib.core.settings import VERSION_STRING
from lib.core.shell import autoCompletion
from lib.core.shell import clearHistory
from lib.core.shell import loadHistory
from lib.core.shell import saveHistory
def cmdLineParser(): def cmdLineParser():
""" """
@ -693,6 +702,9 @@ def cmdLineParser():
action="store_true", action="store_true",
help="Conduct through tests only if positive heuristic(s)") help="Conduct through tests only if positive heuristic(s)")
miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
help="Prompt for an interactive sqlmap shell")
miscellaneous.add_option("--wizard", dest="wizard", miscellaneous.add_option("--wizard", dest="wizard",
action="store_true", action="store_true",
help="Simple wizard interface for beginner users") help="Simple wizard interface for beginner users")
@ -765,22 +777,25 @@ def cmdLineParser():
option = parser.get_option("-h") option = parser.get_option("-h")
option.help = option.help.capitalize().replace("this help", "basic help") option.help = option.help.capitalize().replace("this help", "basic help")
args = [] argv = []
prompt = False
advancedHelp = True advancedHelp = True
for arg in sys.argv: for arg in sys.argv:
args.append(getUnicode(arg, system=True)) argv.append(getUnicode(arg, system=True))
checkDeprecatedOptions(args) checkDeprecatedOptions(argv)
# Hide non-basic options in basic help case # Hide non-basic options in basic help case
for i in xrange(len(sys.argv)): for i in xrange(len(sys.argv)):
if sys.argv[i] == '-hh': if sys.argv[i] == "-hh":
sys.argv[i] = '-h' sys.argv[i] = "-h"
elif sys.argv[i] == '--version': elif sys.argv[i] == "--version":
print VERSION_STRING print VERSION_STRING
raise SystemExit raise SystemExit
elif sys.argv[i] == '-h': elif sys.argv[i] == "--sqlmap-shell":
prompt = True
elif sys.argv[i] == "-h":
advancedHelp = False advancedHelp = False
for group in parser.option_groups[:]: for group in parser.option_groups[:]:
found = False found = False
@ -792,17 +807,56 @@ def cmdLineParser():
if not found: if not found:
parser.option_groups.remove(group) parser.option_groups.remove(group)
if prompt:
cmdLineOptions.sqlmapShell = True
_ = ["x", "q", "exit", "quit", "clear"]
for group in parser.option_groups:
for option in group.option_list:
_.extend(option._long_opts)
_.extend(option._short_opts)
autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=_)
while True:
command = None
try: try:
(args, _) = parser.parse_args(args) command = raw_input("sqlmap-shell> ").strip()
except (KeyboardInterrupt, EOFError):
print
raise SqlmapShellQuitException
if not command:
continue
elif command.lower() == "clear":
clearHistory()
print "[i] history cleared"
saveHistory()
elif command.lower() in ("x", "q", "exit", "quit"):
raise SqlmapShellQuitException
elif command[0] != '-':
print "[!] invalid option(s) provided"
print "[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'"
else:
saveHistory()
loadHistory()
break
for arg in shlex.split(command):
argv.append(getUnicode(arg, system=True))
try:
(args, _) = parser.parse_args(argv)
except SystemExit: except SystemExit:
if '-h' in sys.argv and not advancedHelp: if "-h" in sys.argv and not advancedHelp:
print "\n[!] to see full list of options run with '-hh'" print "\n[!] to see full list of options run with '-hh'"
raise raise
# Expand given mnemonic options (e.g. -z "ign,flu,bat") # Expand given mnemonic options (e.g. -z "ign,flu,bat")
for i in xrange(len(sys.argv) - 1): for i in xrange(len(argv) - 1):
if sys.argv[i] == '-z': if argv[i] == "-z":
expandMnemonics(sys.argv[i + 1], parser, args) expandMnemonics(argv[i + 1], parser, args)
if args.dummy: if args.dummy:
args.url = args.url or DUMMY_URL args.url = args.url or DUMMY_URL

View File

@ -15,6 +15,7 @@ from lib.core.data import conf
from lib.core.data import logger from lib.core.data import logger
from lib.core.enums import AUTOCOMPLETE_TYPE from lib.core.enums import AUTOCOMPLETE_TYPE
from lib.core.enums import DBMS from lib.core.enums import DBMS
from lib.core.enums import OS
from lib.core.exception import SqlmapFilePathException from lib.core.exception import SqlmapFilePathException
from lib.core.exception import SqlmapUnsupportedFeatureException from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion from lib.core.shell import autoCompletion
@ -117,7 +118,7 @@ class Abstraction(Web, UDF, Xp_cmdshell):
infoMsg += "'x' or 'q' and press ENTER" infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg) logger.info(infoMsg)
autoCompletion(AUTOCOMPLETE_TYPE.OS) autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX)
while True: while True:
command = None command = None

View File

@ -33,6 +33,7 @@ from lib.core.data import logger
from lib.core.data import paths from lib.core.data import paths
from lib.core.common import unhandledExceptionMessage from lib.core.common import unhandledExceptionMessage
from lib.core.exception import SqlmapBaseException from lib.core.exception import SqlmapBaseException
from lib.core.exception import SqlmapShellQuitException
from lib.core.exception import SqlmapSilentQuitException from lib.core.exception import SqlmapSilentQuitException
from lib.core.exception import SqlmapUserQuitException from lib.core.exception import SqlmapUserQuitException
from lib.core.option import initOptions from lib.core.option import initOptions
@ -101,7 +102,10 @@ def main():
except (SqlmapSilentQuitException, bdb.BdbQuit): except (SqlmapSilentQuitException, bdb.BdbQuit):
pass pass
except SqlmapBaseException, ex: except SqlmapShellQuitException:
cmdLineOptions.sqlmapShell = False
except SqlmapBaseException as ex:
errMsg = getUnicode(ex.message) errMsg = getUnicode(ex.message)
logger.critical(errMsg) logger.critical(errMsg)
sys.exit(1) sys.exit(1)
@ -138,6 +142,12 @@ def main():
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
if cmdLineOptions.get("sqlmapShell"):
cmdLineOptions.clear()
conf.clear()
kb.clear()
main()
if hasattr(conf, "api"): if hasattr(conf, "api"):
try: try:
conf.database_cursor.disconnect() conf.database_cursor.disconnect()