diff --git a/lib/controller/checks.py b/lib/controller/checks.py index ba439b26a..5be5dde24 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -147,65 +147,41 @@ def checkDynParam(place, parameter, value): return condition -def checkDynamicContent(*pages): +def checkDynamicContent(firstPage, secondPage): """ This function checks if the provided pages have dynamic content. If they - are dynamic, their content differs at specific lines. + are dynamic, proper markings will be made. """ infoMsg = "searching for dynamic content" logger.info(infoMsg) - for i in xrange(len(pages)): - firstPage = pages[i] - linesFirst = preparePageForLineComparison(firstPage) - pageLinesNumber = len(linesFirst) + blocks = SequenceMatcher(None, firstPage, secondPage).get_matching_blocks() + kb.dynamicMarkings = [] - for j in xrange(i+1, len(pages)): - secondPage = pages[j] - linesSecond = preparePageForLineComparison(secondPage) + i = 0 + while i < len(blocks): + block = blocks[i] + (_, _, length) = block + if length <= conf.minMatchBlock: + blocks.remove(block) + else: + i += 1 - if pageLinesNumber == len(linesSecond): - for k in xrange(0, pageLinesNumber): - if (linesFirst[k] != linesSecond[k]): - item = DynamicContentItem(k, pageLinesNumber, \ - linesFirst[k-1] if k > 0 else None, \ - linesFirst[k+1] if k < pageLinesNumber - 1 else None) + if len(blocks) > 0: + blocks.insert(0, None) + blocks.append(None) + for i in xrange(len(blocks) - 1): + prefix = firstPage[blocks[i][0]:blocks[i][0] + blocks[i][2]] if blocks[i] else None + postfix = firstPage[blocks[i + 1][0]:blocks[i + 1][0] + blocks[i + 1][2]] if blocks[i + 1] else None + if prefix is None and blocks[i + 1][0] == 0: + continue + if postfix is None and (blocks[i][0] + blocks[i][2] >= len(firstPage)): + continue + kb.dynamicMarkings.append((prefix[-conf.dynMarkLength:] if prefix else None, postfix[:conf.dynMarkLength] if postfix else None)) - found = None - - for other in kb.dynamicContent: - found = True - - if other.pageTotal == item.pageTotal: - if isinstance(other.lineNumber, int): - if other.lineNumber == item.lineNumber - 1: - other.lineNumber = [other.lineNumber, item.lineNumber] - other.lineContentAfter = item.lineContentAfter - break - - elif other.lineNumber == item.lineNumber + 1: - other.lineNumber = [item.lineNumber, other.lineNumber] - other.lineContentBefore = item.lineContentBefore - break - - elif item.lineNumber - 1 == other.lineNumber[-1]: - other.lineNumber.append(item.lineNumber) - other.lineContentAfter = item.lineContentAfter - break - - elif item.lineNumber + 1 == other.lineNumber[0]: - other.lineNumber.insert(0, item.lineNumber) - other.lineContentBefore = item.lineContentBefore - break - - found = False - - if not found: - kb.dynamicContent.append(item) - - if kb.dynamicContent: - infoMsg = "found probably removable dynamic lines" + if len(kb.dynamicMarkings) > 0: + infoMsg = "dynamic content marked for removal (%d region%s)" % (len(kb.dynamicMarkings), 's' if len(kb.dynamicMarkings) > 1 else '') logger.info(infoMsg) def checkStability(): diff --git a/lib/core/common.py b/lib/core/common.py index 36944cb46..8d3eae7fe 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1079,8 +1079,6 @@ def safeStringFormat(formatStr, params): if count < len(params): retVal = retVal[:index] + getUnicode(params[count]) + retVal[index+2:] else: - import pdb - pdb.set_trace() raise sqlmapNoneDataException, "wrong number of parameters during string formatting" count += 1 diff --git a/lib/core/option.py b/lib/core/option.py index d00072d44..06bc58246 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -1005,6 +1005,8 @@ def __setConfAttributes(): conf.dbmsConnector = None conf.dbmsHandler = None conf.dumpPath = None + conf.minMatchBlock = 8 + conf.dynMarkLength = 32 conf.httpHeaders = [] conf.hostname = None conf.loggedToOut = None @@ -1058,7 +1060,7 @@ def __setKnowledgeBaseAttributes(): kb.dep = None kb.docRoot = None - kb.dynamicContent = [] + kb.dynamicMarkings = [] kb.errorTest = None kb.headersCount = 0 kb.headersFp = {} diff --git a/lib/core/target.py b/lib/core/target.py index 5daa30f52..061f5d4b5 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -290,7 +290,8 @@ def initTargetEnv(): kb.dbms = None kb.dbmsDetected = False kb.dbmsVersion = [ "Unknown" ] - kb.errorTest = None + kb.dynamicMarkings = [] + kb.errorTest = None kb.htmlFp = [] kb.lastErrorPage = None kb.injParameter = None diff --git a/lib/request/comparison.py b/lib/request/comparison.py index 7ee1ca821..2b5b5902c 100644 --- a/lib/request/comparison.py +++ b/lib/request/comparison.py @@ -48,19 +48,14 @@ def comparison(page, headers=None, getSeqMatcher=False, pageLength=None): return re.search(conf.regexp, page, re.I | re.M) is not None # Dynamic content lines to be excluded before calculating page hash - if kb.dynamicContent: - lines = preparePageForLineComparison(page) - for item in kb.dynamicContent: - if len(lines) == item.pageTotal: - before = item.lineNumber - 1 if isinstance(item.lineNumber, int) else item.lineNumber[0] - 1 - after = item.lineNumber + 1 if isinstance(item.lineNumber, int) else item.lineNumber[-1] + 1 - if (item.lineContentBefore and lines[before] != item.lineContentBefore) or (item.lineContentAfter and lines[after] != item.lineContentAfter): - continue - if isinstance(item.lineNumber, int): - page = page.replace(lines[item.lineNumber], '') - else: - for i in item.lineNumber: - page = page.replace(lines[i], '') + for item in kb.dynamicMarkings: + prefix, postfix = item + if prefix is None: + page = re.sub('(?s)^.+%s' % postfix, postfix, page) + elif postfix is None: + page = re.sub('(?s)%s.+$' % prefix, prefix, page) + else: + page = re.sub('(?s)%s.+%s' % (prefix, postfix), '%s%s' % (prefix, postfix), page) if conf.seqLock: conf.seqLock.acquire()