mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2024-11-21 17:16:35 +03:00
Implementation for an Issue #832
This commit is contained in:
parent
57eb19377e
commit
7278af01ee
|
@ -342,3 +342,4 @@ class AUTH_TYPE:
|
|||
class AUTOCOMPLETE_TYPE:
|
||||
SQL = 0
|
||||
OS = 1
|
||||
SQLMAP = 2
|
||||
|
|
|
@ -44,6 +44,9 @@ class SqlmapSilentQuitException(SqlmapBaseException):
|
|||
class SqlmapUserQuitException(SqlmapBaseException):
|
||||
pass
|
||||
|
||||
class SqlmapShellQuitException(SqlmapBaseException):
|
||||
pass
|
||||
|
||||
class SqlmapSyntaxException(SqlmapBaseException):
|
||||
pass
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
@ -47,15 +74,13 @@ class CompleterNG(rlcompleter.Completer):
|
|||
matches.append(word)
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
12
sqlmap.py
12
sqlmap.py
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue
Block a user