diff --git a/lib/controller/checks.py b/lib/controller/checks.py index 9ab616931..59c275558 100644 --- a/lib/controller/checks.py +++ b/lib/controller/checks.py @@ -280,32 +280,53 @@ def checkDynParam(place, parameter, value): return condition -def checkDynamicContent(firstPage, secondPage): +def checkDynamicContent(*pages): + """ + This function checks if the provided pages have dynamic content. If they + are dynamic, their content differs at specific lines. + """ infoMsg = "searching for dynamic content" logger.info(infoMsg) - linesFirst = preparePageForLineComparison(firstPage) - linesSecond = preparePageForLineComparison(secondPage) + for i in xrange(len(pages)): + firstPage = pages[i] + linesFirst = preparePageForLineComparison(firstPage) + pageLinesNumber = len(linesFirst) + for j in xrange(i+1, len(pages)): + secondPage = pages[j] + linesSecond = preparePageForLineComparison(secondPage) + 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(linesFirst) == len(linesSecond): - lastLineNumber = None - pageLinesNumber = len(linesFirst) - for i in range(0, pageLinesNumber): - if (linesFirst[i] != linesSecond[i]): - if lastLineNumber == i - 1: - item = kb.dynamicContent[-1] - if isinstance(item.lineNumber, int): - item.lineNumber = [item.lineNumber] - item.lineNumber.append(i) - else: - kb.dynamicContent.append(DynamicContentItem(i, pageLinesNumber, linesFirst[i-1] if i > 0 else None, linesFirst[i+1] if i < pageLinesNumber - 1 else None)) - lastLineNumber = i - - randInt = getUnicode(randomInt(1)) - payload = agent.fullPayload(" AND %s=%s" % (randInt, randInt)) - result = Request.queryPage(payload) - if result: - pass #TODO: the same as above + 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" diff --git a/lib/core/common.py b/lib/core/common.py index 5858a6ab9..de85273c7 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -163,7 +163,7 @@ def formatDBMSfp(versions=None): while versions and None in versions: versions.remove(None) - + if not versions and kb.dbmsVersion and kb.dbmsVersion[0] != "Unknown" and kb.dbmsVersion[0] != None: versions = kb.dbmsVersion @@ -331,7 +331,7 @@ def getDirs(webApi=None): infoMsg = "retrieved web server full paths: " infoMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths) logger.info(infoMsg) - + for absFilePath in kb.absFilePaths: if absFilePath: directory = directoryPath(absFilePath) @@ -423,7 +423,7 @@ def strToHex(inpStr): hexStr += hexChar return hexStr - + def fileToStr(fileName): """ @param fileName: file path to read the content and return as a no @@ -481,7 +481,7 @@ def readInput(message, default=None): data = default return data - + def randomRange(start=0, stop=1000): """ @param start: starting number. @@ -767,7 +767,7 @@ def parseTargetUrl(): conf.parameters["GET"] = __urlSplit[3] conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path) - + def expandAsteriskForColumns(expression): # If the user provided an asterisk rather than the column(s) # name, sqlmap will retrieve the columns itself and reprocess @@ -819,7 +819,7 @@ def getRange(count, dump=False, plusOne=False): indexRange = range(limitStart - 1, limitStop) return indexRange - + def parseUnionPage(output, expression, partial=False, condition=None, sort=True): data = [] @@ -896,7 +896,7 @@ def getDelayQuery(andCond=False): query = "(%s)>0" % query return query - + def getLocalIP(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((conf.hostname, conf.port)) @@ -918,7 +918,7 @@ def getFileType(filePath): return "text" else: return "binary" - + def pollProcess(process): while True: dataToStdout(".") @@ -935,7 +935,7 @@ def pollProcess(process): dataToStdout(" quit unexpectedly with return code %d\n" % returncode) break - + def getCharset(charsetType=None): asciiTbl = [] @@ -973,7 +973,7 @@ def getCharset(charsetType=None): asciiTbl.extend(range(96, 123)) return asciiTbl - + def searchEnvPath(fileName): envPaths = os.environ["PATH"] result = None @@ -1137,7 +1137,7 @@ def isBase64EncodedString(subject): False """ return re.match(r"\A(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\Z", subject) is not None - + def isHexEncodedString(subject): """ Checks if the provided string is hex encoded @@ -1249,7 +1249,7 @@ def parseXmlFile(xmlFile, handler): def calculateDeltaSeconds(start, epsilon=0.05): """ - Returns elapsed time from start till now (including expected + Returns elapsed time from start till now (including expected error set by epsilon parameter) """ return int(time.time() - start + epsilon) @@ -1470,6 +1470,7 @@ def smokeTest(): logger.error(infoMsg) return retVal + class UnicodeRawConfigParser(RawConfigParser): def write(self, fp): """ @@ -1496,6 +1497,7 @@ class UnicodeRawConfigParser(RawConfigParser): fp.write("\n") + class DynamicContentItem: """ Represents line in content page with dynamic properties (candidate for removal prior detection phase)