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

Skip to content

Commit bd1ea13

Browse files
committed
Merge branch 'master' of github.com:sqlmapproject/sqlmap
2 parents f8bc747 + e7b93b5 commit bd1ea13

16 files changed

Lines changed: 100 additions & 343 deletions

File tree

lib/controller/checks.py

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,24 @@ def checkSqlInjection(place, parameter, value):
8585
if kb.endDetection:
8686
break
8787

88+
if conf.dbms is None:
89+
if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
90+
if not Backend.getIdentifiedDbms() and not kb.heuristicDbms:
91+
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
92+
93+
if not conf.testFilter and (Backend.getErrorParsedDBMSes() or kb.heuristicDbms) not in ([], None, UNKNOWN_DBMS):
94+
if kb.reduceTests is None and Backend.getErrorParsedDBMSes():
95+
msg = "heuristic (parsing) test showed that the "
96+
msg += "back-end DBMS could be '%s'. " % (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
97+
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
98+
kb.reduceTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
99+
100+
if kb.extendTests is None:
101+
_ = (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
102+
msg = "do you want to include all tests for '%s' " % _
103+
msg += "ignoring provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk)
104+
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
105+
88106
title = test.title
89107
stype = test.stype
90108
clause = test.clause
@@ -143,15 +161,24 @@ def checkSqlInjection(place, parameter, value):
143161
logger.debug(debugMsg)
144162
continue
145163

164+
165+
# Skip DBMS-specific test if it does not match either the
166+
# previously identified or the user's provided DBMS (either
167+
# from program switch or from parsed error message(s))
168+
if "details" in test and "dbms" in test.details:
169+
dbms = test.details.dbms
170+
else:
171+
dbms = None
172+
146173
# Skip tests if title is not included by the given filter
147174
if conf.testFilter:
148-
if not any(re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector,\
149-
test.details.dbms if "details" in test and "dbms" in test.details else "")):
175+
if not any(re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector, dbms)):
150176
debugMsg = "skipping test '%s' because " % title
151177
debugMsg += "its name/vector/dbms is not included by the given filter"
152178
logger.debug(debugMsg)
153179
continue
154-
else:
180+
181+
if not (kb.extendTests and intersect(dbms, kb.extendTests)):
155182
# Skip test if the risk is higher than the provided (or default)
156183
# value
157184
# Parse test's <risk>
@@ -170,14 +197,6 @@ def checkSqlInjection(place, parameter, value):
170197
logger.debug(debugMsg)
171198
continue
172199

173-
# Skip DBMS-specific test if it does not match either the
174-
# previously identified or the user's provided DBMS (either
175-
# from program switch or from parsed error message(s))
176-
if "details" in test and "dbms" in test.details:
177-
dbms = test.details.dbms
178-
else:
179-
dbms = None
180-
181200
if dbms is not None:
182201
if injection.dbms is not None and not intersect(injection.dbms, dbms):
183202
debugMsg = "skipping test '%s' because " % title
@@ -192,17 +211,7 @@ def checkSqlInjection(place, parameter, value):
192211
logger.debug(debugMsg)
193212
continue
194213

195-
if conf.dbms is None and len(Backend.getErrorParsedDBMSes()) > 0 and not intersect(dbms, Backend.getErrorParsedDBMSes()) and kb.skipOthersDbms is None:
196-
msg = "parsed error message(s) showed that the "
197-
msg += "back-end DBMS could be %s. " % Format.getErrorParsedDBMSes()
198-
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
199-
200-
if readInput(msg, default="Y") in ("y", "Y"):
201-
kb.skipOthersDbms = Backend.getErrorParsedDBMSes()
202-
else:
203-
kb.skipOthersDbms = []
204-
205-
if kb.skipOthersDbms and not intersect(dbms, kb.skipOthersDbms):
214+
if kb.reduceTests and not intersect(dbms, kb.reduceTests):
206215
debugMsg = "skipping test '%s' because " % title
207216
debugMsg += "the parsed error message(s) showed "
208217
debugMsg += "that the back-end DBMS could be "
@@ -444,10 +453,7 @@ def genCmpPayload():
444453
configUnion(test.request.char, test.request.columns)
445454

446455
if not Backend.getIdentifiedDbms():
447-
if not kb.heuristicDbms:
448-
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
449-
450-
if kb.heuristicDbms == UNKNOWN_DBMS:
456+
if kb.heuristicDbms in (None, UNKNOWN_DBMS):
451457
warnMsg = "using unescaped version of the test "
452458
warnMsg += "because of zero knowledge of the "
453459
warnMsg += "back-end DBMS. You can try to "
@@ -556,8 +562,8 @@ def genCmpPayload():
556562
warnMsg = "user aborted during detection phase"
557563
logger.warn(warnMsg)
558564

559-
message = "How do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(q)uit]"
560-
choice = readInput(message, default="S", checkBatch=False)
565+
msg = "How do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(q)uit]"
566+
choice = readInput(msg, default="S", checkBatch=False)
561567

562568
if choice[0] in ("s", "S"):
563569
pass
@@ -594,24 +600,23 @@ def genCmpPayload():
594600
def heuristicCheckDbms(injection):
595601
retVal = None
596602

597-
if not Backend.getIdentifiedDbms() and len(injection.data) == 1 and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
598-
pushValue(kb.injection)
599-
kb.injection = injection
600-
randStr1, randStr2 = randomStr(), randomStr()
603+
pushValue(kb.injection)
604+
kb.injection = injection
605+
randStr1, randStr2 = randomStr(), randomStr()
601606

602-
for dbms in getPublicTypeMembers(DBMS, True):
603-
Backend.forceDbms(dbms)
607+
for dbms in getPublicTypeMembers(DBMS, True):
608+
Backend.forceDbms(dbms)
604609

605-
if checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr1)):
606-
if not checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr2)):
607-
retVal = dbms
608-
break
610+
if checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr1)):
611+
if not checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr2)):
612+
retVal = dbms
613+
break
609614

610-
Backend.flushForcedDbms()
611-
kb.injection = popValue()
615+
Backend.flushForcedDbms()
616+
kb.injection = popValue()
612617

613618
if retVal:
614-
infoMsg = "heuristic test showed that the back-end DBMS "
619+
infoMsg = "heuristic (extended) test shows that the back-end DBMS " # not as important as "parsing" counter-part (because of false-positives)
615620
infoMsg += "could be '%s' " % retVal
616621
logger.info(infoMsg)
617622

@@ -725,7 +730,7 @@ def heuristicCheckSqlInjection(place, parameter):
725730
parseFilePaths(page)
726731
result = wasLastResponseDBMSError()
727732

728-
infoMsg = "heuristic test shows that %s " % place
733+
infoMsg = "heuristic (parsing) test shows that %s " % place
729734
infoMsg += "parameter '%s' might " % parameter
730735

731736
def _(page):
@@ -758,7 +763,7 @@ def _(page):
758763
kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N').upper() != 'N'
759764

760765
elif result:
761-
infoMsg += "be injectable (possible DBMS: %s)" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS)
766+
infoMsg += "be injectable (possible DBMS: '%s')" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS)
762767
logger.info(infoMsg)
763768

764769
else:

lib/core/agent.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ def getFields(self, query):
426426
fieldsMinMaxstr = re.search(r"(?:MIN|MAX)\(([^\(\)]+)\)", query, re.I)
427427
fieldsNoSelect = query
428428

429+
_ = zeroDepthSearch(query, " FROM ")
430+
if not _:
431+
fieldsSelectFrom = None
432+
429433
if fieldsSubstr:
430434
fieldsToCastStr = query
431435
elif fieldsMinMaxstr:
@@ -441,7 +445,6 @@ def getFields(self, query):
441445
elif fieldsSelectCase:
442446
fieldsToCastStr = fieldsSelectCase.groups()[0]
443447
elif fieldsSelectFrom:
444-
_ = zeroDepthSearch(query, " FROM ")
445448
fieldsToCastStr = query[:unArrayizeValue(_)] if _ else query
446449
fieldsToCastStr = re.sub(r"\ASELECT%s\s+" % prefixRegex, "", fieldsToCastStr)
447450
elif fieldsSelect:
@@ -888,23 +891,17 @@ def forgeQueryOutputLength(self, expression):
888891
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
889892
select = re.search("\ASELECT\s+", expression, re.I)
890893
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
891-
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
892894
selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
893895
selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
894896

895897
_, _, _, _, _, _, fieldsStr, _ = self.getFields(expression)
896898

897-
if any((selectTopExpr, selectDistinctExpr, selectFromExpr, selectExpr)):
899+
if any((selectTopExpr, selectFromExpr, selectExpr)):
898900
query = fieldsStr
899901
else:
900902
query = expression
901903

902-
if selectDistinctExpr:
903-
lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % query, expression)
904-
905-
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
906-
lengthExpr += " AS %s" % randomStr(lowercase=True)
907-
elif select:
904+
if select:
908905
lengthExpr = expression.replace(query, lengthQuery % query, 1)
909906
else:
910907
lengthExpr = lengthQuery % expression

lib/core/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,6 @@ def setPaths():
974974
paths.SMALL_DICT = os.path.join(paths.SQLMAP_TXT_PATH, "smalldict.txt")
975975
paths.USER_AGENTS = os.path.join(paths.SQLMAP_TXT_PATH, "user-agents.txt")
976976
paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.zip")
977-
paths.PHPIDS_RULES_XML = os.path.join(paths.SQLMAP_XML_PATH, "phpids_rules.xml")
978977
paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
979978
paths.PAYLOADS_XML = os.path.join(paths.SQLMAP_XML_PATH, "payloads.xml")
980979
paths.INJECTIONS_XML = os.path.join(paths.SQLMAP_XML_PATH, "injections.xml")
@@ -1376,6 +1375,8 @@ def safeStringFormat(format_, params):
13761375

13771376
if isinstance(params, basestring):
13781377
retVal = retVal.replace("%s", params)
1378+
elif not isListLike(params):
1379+
retVal = retVal.replace("%s", str(params))
13791380
else:
13801381
count, index = 0, 0
13811382
while index != -1:

lib/core/dicts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@
205205
DEPRECATED_OPTIONS = {
206206
"--replicate": "use '--dump-format=SQLITE' instead",
207207
"--no-unescape": "use '--no-escape' instead",
208+
"--check-payload": None,
208209
}
209210

210211
DUMP_DATA_PREPROCESS = {

lib/core/option.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,10 @@ def _parseBurpLog(content):
324324
scheme = "https"
325325
port = port or "443"
326326

327+
if not host:
328+
errMsg = "invalid format of a request file"
329+
raise SqlmapSyntaxException, errMsg
330+
327331
if not url.startswith("http"):
328332
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
329333
scheme = None
@@ -1521,6 +1525,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
15211525
kb.dynamicParameter = False
15221526
kb.endDetection = False
15231527
kb.explicitSettings = set()
1528+
kb.extendTests = None
15241529
kb.errorIsNone = True
15251530
kb.fileReadMode = False
15261531
kb.forcedDbms = None
@@ -1548,12 +1553,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
15481553
kb.multiThreadMode = False
15491554
kb.negativeLogic = False
15501555
kb.nullConnection = None
1551-
kb.pageCompress = True
1552-
kb.pageTemplate = None
1553-
kb.pageTemplates = dict()
1554-
kb.postHint = None
1555-
kb.previousMethod = None
1556-
kb.processUserMarks = None
15571556
kb.orderByColumns = None
15581557
kb.originalCode = None
15591558
kb.originalPage = None
@@ -1566,12 +1565,19 @@ def _setKnowledgeBaseAttributes(flushAll=True):
15661565
kb.osVersion = None
15671566
kb.osSP = None
15681567

1568+
kb.pageCompress = True
1569+
kb.pageTemplate = None
1570+
kb.pageTemplates = dict()
15691571
kb.pageEncoding = DEFAULT_PAGE_ENCODING
15701572
kb.pageStable = None
15711573
kb.partRun = None
15721574
kb.permissionFlag = False
1575+
kb.postHint = None
1576+
kb.postSpaceToPlus = False
15731577
kb.prependFlag = False
15741578
kb.processResponseCounter = 0
1579+
kb.previousMethod = None
1580+
kb.processUserMarks = None
15751581
kb.proxyAuthHeader = None
15761582
kb.queryCounter = 0
15771583
kb.redirectChoice = None
@@ -1584,8 +1590,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
15841590
kb.resumeValues = True
15851591
kb.safeCharEncode = False
15861592
kb.singleLogFlags = set()
1587-
kb.skipOthersDbms = None
1588-
kb.postSpaceToPlus = False
1593+
kb.reduceTests = None
15891594
kb.stickyDBMS = False
15901595
kb.stickyLevel = None
15911596
kb.suppressResumeInfo = False

lib/core/optiondict.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@
195195
"alert": "string",
196196
"answers": "string",
197197
"beep": "boolean",
198-
"checkPayload": "boolean",
199198
"checkWaf": "boolean",
200199
"cleanup": "boolean",
201200
"dependencies": "boolean",

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@
466466
CHECK_ZERO_COLUMNS_THRESHOLD = 10
467467

468468
# Boldify all logger messages containing these "patterns"
469-
BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "heuristic test showed")
469+
BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that")
470470

471471
# Generic www root directory names
472472
GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "wwwroot", "www")

lib/parse/cmdline.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,10 +612,6 @@ def cmdLineParser():
612612
miscellaneous.add_option("--beep", dest="beep", action="store_true",
613613
help="Make a beep sound when SQL injection is found")
614614

615-
miscellaneous.add_option("--check-payload", dest="checkPayload",
616-
action="store_true",
617-
help="Offline WAF/IPS/IDS payload detection testing")
618-
619615
miscellaneous.add_option("--check-waf", dest="checkWaf",
620616
action="store_true",
621617
help="Check for existence of WAF/IPS/IDS protection")

lib/request/basic.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,7 @@ def decodePage(page, contentEncoding, contentType):
256256
def processResponse(page, responseHeaders):
257257
kb.processResponseCounter += 1
258258

259-
if not kb.dumpTable:
260-
parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
259+
parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
261260

262261
if conf.parseErrors:
263262
msg = extractErrorMessage(page)

lib/request/connect.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
from lib.request.direct import direct
8080
from lib.request.comparison import comparison
8181
from lib.request.methodrequest import MethodRequest
82-
from lib.utils.checkpayload import checkPayload
8382
from thirdparty.socks.socks import ProxyError
8483
from thirdparty.multipart import multipartpost
8584

@@ -658,9 +657,6 @@ def queryPage(value=None, place=None, content=False, getRatioValue=False, silent
658657
if place:
659658
value = agent.removePayloadDelimiters(value)
660659

661-
if conf.checkPayload:
662-
checkPayload(value)
663-
664660
if PLACE.GET in conf.parameters:
665661
get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value
666662

0 commit comments

Comments
 (0)