sqlmap/lib/core/update.py

250 lines
9.0 KiB
Python
Raw Normal View History

2008-10-15 19:38:22 +04:00
#!/usr/bin/env python
"""
2008-10-15 19:56:32 +04:00
$Id$
2008-10-15 19:38:22 +04:00
Copyright (c) 2006-2010 sqlmap developers (http://sqlmap.sourceforge.net/)
2010-10-15 03:18:29 +04:00
See the file 'doc/COPYING' for copying permission
2008-10-15 19:38:22 +04:00
"""
import codecs
2008-10-15 19:38:22 +04:00
import difflib
import os
import re
import shutil
import sys
2010-01-18 17:59:24 +03:00
import time
2008-10-15 19:38:22 +04:00
import urlparse
from distutils.dir_util import mkpath
from xml.dom.minidom import Document
2010-01-18 17:05:23 +03:00
from subprocess import PIPE
from subprocess import Popen as execute
from lib.core.common import dataToStdout
2010-10-21 02:09:03 +04:00
from lib.core.common import getUnicode
2010-01-18 17:59:24 +03:00
from lib.core.common import readInput
2008-10-15 19:38:22 +04:00
from lib.core.data import conf
from lib.core.data import logger
from lib.core.data import paths
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapFilePathException
from lib.core.settings import MSSQL_VERSIONS_URL
2011-01-30 14:36:03 +03:00
from lib.core.settings import UNICODE_ENCODING
2010-10-29 14:51:09 +04:00
from lib.core.subprocessng import pollProcess
2008-10-15 19:38:22 +04:00
from lib.request.connect import Connect as Request
def __updateMSSQLXML():
infoMsg = "updating Microsoft SQL Server XML versions file"
logger.info(infoMsg)
try:
mssqlVersionsHtmlString, _ = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
2008-10-15 19:38:22 +04:00
except sqlmapConnectionException, _:
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
__mssqlHostname = __mssqlPath[1]
warnMsg = "sqlmap was unable to connect to %s," % __mssqlHostname
warnMsg += " check your Internet connection and retry"
logger.warn(warnMsg)
return
releases = re.findall("class=\"BCC_DV_01DarkBlueTitle\">SQL Server ([\d\.]+) Builds", mssqlVersionsHtmlString, re.I | re.M)
releasesCount = len(releases)
# Create the minidom document
doc = Document()
# Create the <root> base element
root = doc.createElement("root")
doc.appendChild(root)
for index in range(0, releasesCount):
release = releases[index]
# Skip Microsoft SQL Server 6.5 because the HTML
# table is in another format
if release == "6.5":
continue
# Create the <signatures> base element
signatures = doc.createElement("signatures")
signatures.setAttribute("release", release)
root.appendChild(signatures)
startIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index])
if index == releasesCount - 1:
stopIdx = len(mssqlVersionsHtmlString)
else:
stopIdx = mssqlVersionsHtmlString.index("SQL Server %s Builds" % releases[index + 1])
mssqlVersionsReleaseString = mssqlVersionsHtmlString[startIdx:stopIdx]
servicepackVersion = re.findall("</td><td>[7\.0|2000|2005|2008]*(.*?)</td><td.*?([\d\.]+)</td>[\r]*\n", mssqlVersionsReleaseString, re.I | re.M)
for servicePack, version in servicepackVersion:
if servicePack.startswith(" "):
servicePack = servicePack[1:]
if "/" in servicePack:
servicePack = servicePack[:servicePack.index("/")]
if "(" in servicePack:
servicePack = servicePack[:servicePack.index("(")]
if "-" in servicePack:
servicePack = servicePack[:servicePack.index("-")]
if "*" in servicePack:
servicePack = servicePack[:servicePack.index("*")]
if servicePack.startswith("+"):
servicePack = "0%s" % servicePack
2008-10-15 19:38:22 +04:00
servicePack = servicePack.replace("\t", " ")
servicePack = servicePack.replace("No SP", "0")
servicePack = servicePack.replace("RTM", "0")
servicePack = servicePack.replace("SP", "")
servicePack = servicePack.replace("Service Pack", "")
2008-10-15 19:38:22 +04:00
servicePack = servicePack.replace("<a href=\"http:", "")
2011-01-31 13:54:13 +03:00
servicePack = servicePack.replace(" ", " ")
2011-01-31 13:59:51 +03:00
servicePack = servicePack.replace("+ ", "+")
servicePack = servicePack.replace(" +", "+")
2008-10-15 19:38:22 +04:00
if servicePack.endswith(" "):
servicePack = servicePack[:-1]
if servicePack and version:
# Create the main <card> element
signature = doc.createElement("signature")
signatures.appendChild(signature)
# Create a <version> element
versionElement = doc.createElement("version")
signature.appendChild(versionElement)
# Give the <version> elemenet some text
versionText = doc.createTextNode(version)
versionElement.appendChild(versionText)
# Create a <servicepack> element
servicepackElement = doc.createElement("servicepack")
signature.appendChild(servicepackElement)
# Give the <servicepack> elemenet some text
servicepackText = doc.createTextNode(servicePack)
servicepackElement.appendChild(servicepackText)
# Get the XML old file content to a local variable
2011-01-30 14:36:03 +03:00
mssqlXml = codecs.open(paths.MSSQL_XML, "r", UNICODE_ENCODING)
2008-10-15 19:38:22 +04:00
oldMssqlXml = mssqlXml.read()
oldMssqlXmlSignatures = oldMssqlXml.count("<signature>")
oldMssqlXmlList = oldMssqlXml.splitlines(1)
mssqlXml.close()
# Backup the XML old file
shutil.copy(paths.MSSQL_XML, "%s.bak" % paths.MSSQL_XML)
# Save our newly created XML to the signatures file
2011-01-30 14:36:03 +03:00
mssqlXml = codecs.open(paths.MSSQL_XML, "w", UNICODE_ENCODING)
2008-10-15 19:38:22 +04:00
doc.writexml(writer=mssqlXml, addindent=" ", newl="\n")
mssqlXml.close()
# Get the XML new file content to a local variable
2011-01-30 14:36:03 +03:00
mssqlXml = codecs.open(paths.MSSQL_XML, "r", UNICODE_ENCODING)
2008-10-15 19:38:22 +04:00
newMssqlXml = mssqlXml.read()
newMssqlXmlSignatures = newMssqlXml.count("<signature>")
newMssqlXmlList = newMssqlXml.splitlines(1)
mssqlXml.close()
# If the new XML versions file differs from the old one it probably
# means that we have got new Microsoft SQL Server versions
if oldMssqlXmlSignatures != newMssqlXmlSignatures:
infoMsg = "Microsoft SQL Server XML versions file updated successfully. "
if oldMssqlXmlSignatures < newMssqlXmlSignatures:
infoMsg += "%d " % (newMssqlXmlSignatures - oldMssqlXmlSignatures)
infoMsg += "new signatures added since the last update"
# NOTE: This should never happen, in this rare case it might
# be that the Microsoft SQL Server versions database
# (MSSQL_VERSIONS_URL) changed its structure
else:
infoMsg += "%d " % (oldMssqlXmlSignatures - newMssqlXmlSignatures)
infoMsg += "signatures removed since the last update"
logger.info(infoMsg)
message = "Do you want to see the differences? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
infoMsg = "Differences:"
logger.info(infoMsg)
# Compare the old XML file with the new one
diff = difflib.unified_diff(oldMssqlXmlList, newMssqlXmlList, "%s.bak" % paths.MSSQL_XML, paths.MSSQL_XML)
sys.stdout.writelines(diff)
2008-10-15 19:38:22 +04:00
else:
infoMsg = "no new Microsoft SQL Server versions since the "
infoMsg += "last update"
logger.info(infoMsg)
def __updateSqlmap():
2010-01-18 17:59:24 +03:00
rootDir = paths.SQLMAP_ROOT_PATH
infoMsg = "updating sqlmap to latest development version from the "
infoMsg += "subversion repository"
2010-01-18 17:05:23 +03:00
logger.info(infoMsg)
2010-01-18 17:59:24 +03:00
2010-01-18 17:05:23 +03:00
try:
import pysvn
2010-01-18 17:59:24 +03:00
debugMsg = "sqlmap will update itself using installed python-svn "
debugMsg += "third-party library, http://pysvn.tigris.org/"
logger.debug(debugMsg)
2010-01-18 17:05:23 +03:00
def notify(event_dict):
2011-01-30 14:36:03 +03:00
action = getUnicode(event_dict['action'])
2010-01-18 18:20:50 +03:00
index = action.find('_')
prefix = action[index + 1].upper() if index != -1 else action.capitalize()
2010-01-18 17:59:24 +03:00
2010-01-18 17:05:23 +03:00
if action.find('_update') != -1:
return
2010-01-18 17:59:24 +03:00
2010-01-18 17:05:23 +03:00
if action.find('_completed') == -1:
2010-10-21 02:09:03 +04:00
dataToStdout("%s\t%s\n" % (prefix, event_dict['path']))
2010-01-18 17:05:23 +03:00
else:
2011-01-30 14:36:03 +03:00
revision = getUnicode(event_dict['revision'], UNICODE_ENCODING)
2010-01-18 17:05:23 +03:00
index = revision.find('number ')
2010-01-18 17:59:24 +03:00
2010-01-18 17:05:23 +03:00
if index != -1:
revision = revision[index+7:].strip('>')
2010-01-18 17:59:24 +03:00
2010-01-18 17:05:23 +03:00
logger.info('updated to the latest revision %s' % revision)
2010-01-18 17:59:24 +03:00
2010-01-18 17:05:23 +03:00
client = pysvn.Client()
client.callback_notify = notify
client.update(rootDir)
2010-01-18 17:59:24 +03:00
except ImportError, _:
debugMsg = "sqlmap will try to update itself using 'svn' command"
logger.debug(debugMsg)
process = execute("svn update %s" % rootDir, shell=True, stdout=PIPE, stderr=PIPE)
2010-01-18 17:05:23 +03:00
2010-01-18 17:59:24 +03:00
dataToStdout("\r[%s] [INFO] update in progress " % time.strftime("%X"))
2010-01-18 17:05:23 +03:00
pollProcess(process)
svnStdout, svnStderr = process.communicate()
if svnStderr:
errMsg = svnStderr.strip()
logger.error(errMsg)
2010-01-18 17:59:24 +03:00
elif svnStdout:
revision = re.search("revision\s+([\d]+)", svnStdout, re.I)
if revision:
logger.info('updated to the latest revision %s' % revision.group(1))
2008-10-15 19:38:22 +04:00
def update():
if not conf.updateAll:
return
__updateSqlmap()
__updateMSSQLXML()