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:
SQL = 0
OS = 1
SQLMAP = 2

View File

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

View File

@ -239,6 +239,7 @@ BASIC_HELP_ITEMS = (
"checkTor",
"flushSession",
"tor",
"sqlmapShell",
"wizard",
)
@ -583,6 +584,9 @@ MIN_BINARY_DISK_DUMP_SIZE = 100
# Regular expression used for extracting form tags
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
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.enums import AUTOCOMPLETE_TYPE
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():
if not readlineAvailable():
return
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)
def loadHistory():
if not readlineAvailable():
return
historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY)
if os.path.exists(historyPath):
@ -48,14 +75,12 @@ class CompleterNG(rlcompleter.Completer):
return matches
def autoCompletion(completion=None):
# First of all we check if the readline is available, by default
# it is not in Python default installation on Windows
if not readline._readline:
def autoCompletion(completion=None, os=None, commands=None):
if not readlineAvailable():
return
if completion == AUTOCOMPLETE_TYPE.OS:
if Backend.isOs(OS.WINDOWS):
if os == OS.WINDOWS:
# Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands
completer = CompleterNG({
"copy": None, "del": None, "dir": None,
@ -76,5 +101,11 @@ def autoCompletion(completion=None):
readline.set_completer(completer.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()
atexit.register(saveHistory)

View File

@ -6,6 +6,7 @@ See the file 'doc/COPYING' for copying permission
"""
import os
import shlex
import sys
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 expandMnemonics
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.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 DUMMY_URL
from lib.core.settings import IS_WIN
from lib.core.settings import MAX_HELP_OPTION_LENGTH
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():
"""
@ -693,6 +702,9 @@ def cmdLineParser():
action="store_true",
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",
action="store_true",
help="Simple wizard interface for beginner users")
@ -765,22 +777,25 @@ def cmdLineParser():
option = parser.get_option("-h")
option.help = option.help.capitalize().replace("this help", "basic help")
args = []
argv = []
prompt = False
advancedHelp = True
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
for i in xrange(len(sys.argv)):
if sys.argv[i] == '-hh':
sys.argv[i] = '-h'
elif sys.argv[i] == '--version':
if sys.argv[i] == "-hh":
sys.argv[i] = "-h"
elif sys.argv[i] == "--version":
print VERSION_STRING
raise SystemExit
elif sys.argv[i] == '-h':
elif sys.argv[i] == "--sqlmap-shell":
prompt = True
elif sys.argv[i] == "-h":
advancedHelp = False
for group in parser.option_groups[:]:
found = False
@ -792,17 +807,56 @@ def cmdLineParser():
if not found:
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:
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(args)
(args, _) = parser.parse_args(argv)
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'"
raise
# Expand given mnemonic options (e.g. -z "ign,flu,bat")
for i in xrange(len(sys.argv) - 1):
if sys.argv[i] == '-z':
expandMnemonics(sys.argv[i + 1], parser, args)
for i in xrange(len(argv) - 1):
if argv[i] == "-z":
expandMnemonics(argv[i + 1], parser, args)
if args.dummy:
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.enums import AUTOCOMPLETE_TYPE
from lib.core.enums import DBMS
from lib.core.enums import OS
from lib.core.exception import SqlmapFilePathException
from lib.core.exception import SqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
@ -117,7 +118,7 @@ class Abstraction(Web, UDF, Xp_cmdshell):
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
autoCompletion(AUTOCOMPLETE_TYPE.OS)
autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX)
while True:
command = None

View File

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