diff --git a/lib/core/option.py b/lib/core/option.py index 431139e16..fc3b9dd62 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1449,7 +1449,7 @@ def __setKnowledgeBaseAttributes(flushAll=True): kb.dnsMode = False kb.dnsTest = None kb.docRoot = None - kb.dumpMode = False + kb.dumpTable = None kb.dynamicMarkings = [] kb.dynamicParameters = False kb.endDetection = False diff --git a/lib/core/settings.py b/lib/core/settings.py index 02ebd8cd5..dc6dbbb77 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -506,3 +506,6 @@ GENERIC_SQL_COMMENT = "-- " # Threshold value for turning back on time auto-adjustment mechanism VALID_TIME_CHARS_RUN_THRESHOLD = 100 + +# Check for empty columns only if table is sufficiently large +CHECK_ZERO_COLUMNS_THRESHOLD = 10 diff --git a/lib/request/basic.py b/lib/request/basic.py index ef745fb4b..69fd06d93 100644 --- a/lib/request/basic.py +++ b/lib/request/basic.py @@ -218,7 +218,7 @@ def decodePage(page, contentEncoding, contentType): def processResponse(page, responseHeaders): kb.processResponseCounter += 1 - if not kb.dumpMode: + if not kb.dumpTable: parseResponse(page, responseHeaders if kb.processResponseCounter < PARSE_HEADERS_LIMIT else None) if conf.parseErrors: diff --git a/lib/techniques/error/use.py b/lib/techniques/error/use.py index 93863c813..a8a508ffd 100644 --- a/lib/techniques/error/use.py +++ b/lib/techniques/error/use.py @@ -32,9 +32,11 @@ from lib.core.data import logger from lib.core.data import queries from lib.core.enums import DBMS from lib.core.enums import PAYLOAD +from lib.core.settings import CHECK_ZERO_COLUMNS_THRESHOLD from lib.core.settings import FROM_DUMMY_TABLE from lib.core.settings import MYSQL_ERROR_CHUNK_LENGTH from lib.core.settings import MSSQL_ERROR_CHUNK_LENGTH +from lib.core.settings import NULL from lib.core.settings import PARTIAL_VALUE_MARKER from lib.core.settings import SLOW_ORDER_COUNT_THRESHOLD from lib.core.settings import SQL_SCALAR_REGEX @@ -44,7 +46,7 @@ from lib.core.threads import runThreads from lib.core.unescaper import unescaper from lib.request.connect import Connect as Request -def __oneShotErrorUse(expression, field): +def __oneShotErrorUse(expression, field=None): offset = 1 partialValue = None threadData = getCurrentThreadData() @@ -56,7 +58,13 @@ def __oneShotErrorUse(expression, field): offset += len(partialValue) threadData.resumed = retVal is not None and not partialValue - chunk_length = None + + if Backend.isDbms(DBMS.MYSQL): + chunk_length = MYSQL_ERROR_CHUNK_LENGTH + elif Backend.isDbms(DBMS.MSSQL): + chunk_length = MSSQL_ERROR_CHUNK_LENGTH + else: + chunk_length = None if retVal is None or partialValue: try: @@ -64,20 +72,17 @@ def __oneShotErrorUse(expression, field): check = "%s(?P.*?)%s" % (kb.chars.start, kb.chars.stop) trimcheck = "%s(?P.*?) CHECK_ZERO_COLUMNS_THRESHOLD): + for field in expressionFieldsList: + if __oneShotErrorUse("SELECT COUNT(%s) FROM %s" % (field, kb.dumpTable)) == '0': + emptyFields.append(field) + debugMsg = "column '%s' for table '%s' appears to be empty. " + debugMsg += "It's values will not be dumped" + logger.debug(debugMsg) + if stopLimit > TURN_OFF_RESUME_INFO_LIMIT: kb.suppressResumeInfo = True debugMsg = "suppressing possible resume console info because of " @@ -366,7 +380,7 @@ def errorUse(expression, expected=None, dump=False): except StopIteration: break - output = __errorFields(expression, expressionFields, expressionFieldsList, expected, num) + output = __errorFields(expression, expressionFields, expressionFieldsList, expected, num, emptyFields) if not kb.threadContinue: break diff --git a/plugins/generic/enumeration.py b/plugins/generic/enumeration.py index 3610086d8..6de7b2be7 100644 --- a/plugins/generic/enumeration.py +++ b/plugins/generic/enumeration.py @@ -1573,7 +1573,7 @@ class Enumeration: kb.data.cachedColumns = foundData try: - kb.dumpMode = True + kb.dumpTable = "%s.%s" % (conf.db, tbl) if not safeSQLIdentificatorNaming(conf.db) in kb.data.cachedColumns \ or safeSQLIdentificatorNaming(tbl, True) not in \ @@ -1782,7 +1782,7 @@ class Enumeration: logger.critical(errMsg) finally: - kb.dumpMode = False + kb.dumpTable = None def dumpAll(self): if conf.db is not None and conf.tbl is None: