Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7278af0

Browse files
committed
Implementation for an Issue #832
1 parent 57eb193 commit 7278af0

7 files changed

Lines changed: 124 additions & 20 deletions

File tree

lib/core/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,4 @@ class AUTH_TYPE:
342342
class AUTOCOMPLETE_TYPE:
343343
SQL = 0
344344
OS = 1
345+
SQLMAP = 2

lib/core/exception.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class SqlmapSilentQuitException(SqlmapBaseException):
4444
class SqlmapUserQuitException(SqlmapBaseException):
4545
pass
4646

47+
class SqlmapShellQuitException(SqlmapBaseException):
48+
pass
49+
4750
class SqlmapSyntaxException(SqlmapBaseException):
4851
pass
4952

lib/core/settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@
239239
"checkTor",
240240
"flushSession",
241241
"tor",
242+
"sqlmapShell",
242243
"wizard",
243244
)
244245

@@ -583,6 +584,9 @@
583584
# Regular expression used for extracting form tags
584585
FORM_SEARCH_REGEX = r"(?si)<form(?!.+<form).+?</form>"
585586

587+
# Maximum number of lines to save in history file
588+
MAX_HISTORY_LENGTH = 1000
589+
586590
# Minimum field entry length needed for encoded content (hex, base64,...) check
587591
MIN_ENCODED_LEN_CHECK = 5
588592

lib/core/shell.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,39 @@
1515
from lib.core.data import paths
1616
from lib.core.enums import AUTOCOMPLETE_TYPE
1717
from lib.core.enums import OS
18+
from lib.core.settings import MAX_HISTORY_LENGTH
19+
20+
def readlineAvailable():
21+
"""
22+
Check if the readline is available. By default
23+
it is not in Python default installation on Windows
24+
"""
25+
26+
return readline._readline is not None
27+
28+
def clearHistory():
29+
if not readlineAvailable():
30+
return
31+
32+
readline.clear_history()
1833

1934
def saveHistory():
35+
if not readlineAvailable():
36+
return
37+
2038
historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY)
39+
try:
40+
os.remove(historyPath)
41+
except:
42+
pass
43+
44+
readline.set_history_length(MAX_HISTORY_LENGTH)
2145
readline.write_history_file(historyPath)
2246

2347
def loadHistory():
48+
if not readlineAvailable():
49+
return
50+
2451
historyPath = os.path.expanduser(paths.SQLMAP_SHELL_HISTORY)
2552

2653
if os.path.exists(historyPath):
@@ -47,15 +74,13 @@ def global_matches(self, text):
4774
matches.append(word)
4875

4976
return matches
50-
51-
def autoCompletion(completion=None):
52-
# First of all we check if the readline is available, by default
53-
# it is not in Python default installation on Windows
54-
if not readline._readline:
77+
78+
def autoCompletion(completion=None, os=None, commands=None):
79+
if not readlineAvailable():
5580
return
5681

5782
if completion == AUTOCOMPLETE_TYPE.OS:
58-
if Backend.isOs(OS.WINDOWS):
83+
if os == OS.WINDOWS:
5984
# Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands
6085
completer = CompleterNG({
6186
"copy": None, "del": None, "dir": None,
@@ -76,5 +101,11 @@ def autoCompletion(completion=None):
76101
readline.set_completer(completer.complete)
77102
readline.parse_and_bind("tab: complete")
78103

104+
elif commands:
105+
completer = CompleterNG(dict(((_, None) for _ in commands)))
106+
readline.set_completer_delims(' ')
107+
readline.set_completer(completer.complete)
108+
readline.parse_and_bind("tab: complete")
109+
79110
loadHistory()
80111
atexit.register(saveHistory)

lib/parse/cmdline.py

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import os
9+
import shlex
910
import sys
1011

1112
from optparse import OptionError
@@ -17,13 +18,21 @@
1718
from lib.core.common import checkSystemEncoding
1819
from lib.core.common import expandMnemonics
1920
from lib.core.common import getUnicode
21+
from lib.core.data import cmdLineOptions
22+
from lib.core.data import conf
2023
from lib.core.data import logger
2124
from lib.core.defaults import defaults
25+
from lib.core.enums import AUTOCOMPLETE_TYPE
26+
from lib.core.exception import SqlmapShellQuitException
2227
from lib.core.settings import BASIC_HELP_ITEMS
2328
from lib.core.settings import DUMMY_URL
2429
from lib.core.settings import IS_WIN
2530
from lib.core.settings import MAX_HELP_OPTION_LENGTH
2631
from lib.core.settings import VERSION_STRING
32+
from lib.core.shell import autoCompletion
33+
from lib.core.shell import clearHistory
34+
from lib.core.shell import loadHistory
35+
from lib.core.shell import saveHistory
2736

2837
def cmdLineParser():
2938
"""
@@ -693,6 +702,9 @@ def cmdLineParser():
693702
action="store_true",
694703
help="Conduct through tests only if positive heuristic(s)")
695704

705+
miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",
706+
help="Prompt for an interactive sqlmap shell")
707+
696708
miscellaneous.add_option("--wizard", dest="wizard",
697709
action="store_true",
698710
help="Simple wizard interface for beginner users")
@@ -765,22 +777,25 @@ def _(self, *args):
765777
option = parser.get_option("-h")
766778
option.help = option.help.capitalize().replace("this help", "basic help")
767779

768-
args = []
780+
argv = []
781+
prompt = False
769782
advancedHelp = True
770783

771784
for arg in sys.argv:
772-
args.append(getUnicode(arg, system=True))
785+
argv.append(getUnicode(arg, system=True))
773786

774-
checkDeprecatedOptions(args)
787+
checkDeprecatedOptions(argv)
775788

776789
# Hide non-basic options in basic help case
777790
for i in xrange(len(sys.argv)):
778-
if sys.argv[i] == '-hh':
779-
sys.argv[i] = '-h'
780-
elif sys.argv[i] == '--version':
791+
if sys.argv[i] == "-hh":
792+
sys.argv[i] = "-h"
793+
elif sys.argv[i] == "--version":
781794
print VERSION_STRING
782795
raise SystemExit
783-
elif sys.argv[i] == '-h':
796+
elif sys.argv[i] == "--sqlmap-shell":
797+
prompt = True
798+
elif sys.argv[i] == "-h":
784799
advancedHelp = False
785800
for group in parser.option_groups[:]:
786801
found = False
@@ -792,17 +807,56 @@ def _(self, *args):
792807
if not found:
793808
parser.option_groups.remove(group)
794809

810+
if prompt:
811+
cmdLineOptions.sqlmapShell = True
812+
813+
_ = ["x", "q", "exit", "quit", "clear"]
814+
for group in parser.option_groups:
815+
for option in group.option_list:
816+
_.extend(option._long_opts)
817+
_.extend(option._short_opts)
818+
819+
autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=_)
820+
821+
while True:
822+
command = None
823+
824+
try:
825+
command = raw_input("sqlmap-shell> ").strip()
826+
except (KeyboardInterrupt, EOFError):
827+
print
828+
raise SqlmapShellQuitException
829+
830+
if not command:
831+
continue
832+
elif command.lower() == "clear":
833+
clearHistory()
834+
print "[i] history cleared"
835+
saveHistory()
836+
elif command.lower() in ("x", "q", "exit", "quit"):
837+
raise SqlmapShellQuitException
838+
elif command[0] != '-':
839+
print "[!] invalid option(s) provided"
840+
print "[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'"
841+
else:
842+
saveHistory()
843+
loadHistory()
844+
break
845+
846+
for arg in shlex.split(command):
847+
argv.append(getUnicode(arg, system=True))
848+
795849
try:
796-
(args, _) = parser.parse_args(args)
850+
(args, _) = parser.parse_args(argv)
797851
except SystemExit:
798-
if '-h' in sys.argv and not advancedHelp:
852+
if "-h" in sys.argv and not advancedHelp:
799853
print "\n[!] to see full list of options run with '-hh'"
800854
raise
801855

802856
# Expand given mnemonic options (e.g. -z "ign,flu,bat")
803-
for i in xrange(len(sys.argv) - 1):
804-
if sys.argv[i] == '-z':
805-
expandMnemonics(sys.argv[i + 1], parser, args)
857+
for i in xrange(len(argv) - 1):
858+
if argv[i] == "-z":
859+
expandMnemonics(argv[i + 1], parser, args)
806860

807861
if args.dummy:
808862
args.url = args.url or DUMMY_URL

lib/takeover/abstraction.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from lib.core.data import logger
1616
from lib.core.enums import AUTOCOMPLETE_TYPE
1717
from lib.core.enums import DBMS
18+
from lib.core.enums import OS
1819
from lib.core.exception import SqlmapFilePathException
1920
from lib.core.exception import SqlmapUnsupportedFeatureException
2021
from lib.core.shell import autoCompletion
@@ -117,7 +118,7 @@ def shell(self):
117118
infoMsg += "'x' or 'q' and press ENTER"
118119
logger.info(infoMsg)
119120

120-
autoCompletion(AUTOCOMPLETE_TYPE.OS)
121+
autoCompletion(AUTOCOMPLETE_TYPE.OS, OS.WINDOWS if Backend.isOs(OS.WINDOWS) else OS.LINUX)
121122

122123
while True:
123124
command = None

sqlmap.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from lib.core.data import paths
3434
from lib.core.common import unhandledExceptionMessage
3535
from lib.core.exception import SqlmapBaseException
36+
from lib.core.exception import SqlmapShellQuitException
3637
from lib.core.exception import SqlmapSilentQuitException
3738
from lib.core.exception import SqlmapUserQuitException
3839
from lib.core.option import initOptions
@@ -101,7 +102,10 @@ def main():
101102
except (SqlmapSilentQuitException, bdb.BdbQuit):
102103
pass
103104

104-
except SqlmapBaseException, ex:
105+
except SqlmapShellQuitException:
106+
cmdLineOptions.sqlmapShell = False
107+
108+
except SqlmapBaseException as ex:
105109
errMsg = getUnicode(ex.message)
106110
logger.critical(errMsg)
107111
sys.exit(1)
@@ -138,6 +142,12 @@ def main():
138142
except KeyboardInterrupt:
139143
pass
140144

145+
if cmdLineOptions.get("sqlmapShell"):
146+
cmdLineOptions.clear()
147+
conf.clear()
148+
kb.clear()
149+
main()
150+
141151
if hasattr(conf, "api"):
142152
try:
143153
conf.database_cursor.disconnect()

0 commit comments

Comments
 (0)