sqlmap/lib/techniques/brute/use.py

237 lines
8.5 KiB
Python
Raw Normal View History

2010-11-09 12:42:43 +03:00
#!/usr/bin/env python
"""
2012-07-12 21:38:03 +04:00
Copyright (c) 2006-2012 sqlmap developers (http://sqlmap.org/)
2010-11-09 12:42:43 +03:00
See the file 'doc/COPYING' for copying permission
"""
import time
2010-11-24 00:00:42 +03:00
from lib.core.common import clearConsoleLine
2010-11-09 12:42:43 +03:00
from lib.core.common import dataToStdout
from lib.core.common import filterListValue
2010-11-09 12:42:43 +03:00
from lib.core.common import getFileItems
from lib.core.common import Backend
from lib.core.common import getPageWordSet
from lib.core.common import hashDBRetrieve
from lib.core.common import hashDBWrite
2010-11-09 12:42:43 +03:00
from lib.core.common import randomInt
from lib.core.common import randomStr
2010-11-09 12:42:43 +03:00
from lib.core.common import safeStringFormat
2011-03-30 01:54:15 +04:00
from lib.core.common import safeSQLIdentificatorNaming
2010-11-09 12:42:43 +03:00
from lib.core.data import conf
from lib.core.data import kb
2010-11-09 12:42:43 +03:00
from lib.core.data import logger
2010-12-26 14:15:02 +03:00
from lib.core.enums import DBMS
2011-12-28 17:50:03 +04:00
from lib.core.enums import HASHDB_KEYS
from lib.core.exception import sqlmapDataException
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.settings import METADB_SUFFIX
from lib.core.settings import BRUTE_COLUMN_EXISTS_TEMPLATE
from lib.core.settings import BRUTE_TABLE_EXISTS_TEMPLATE
from lib.core.threads import getCurrentThreadData
from lib.core.threads import runThreads
2010-12-09 01:14:42 +03:00
from lib.request import inject
2010-11-09 12:42:43 +03:00
def __addPageTextWords():
wordsList = []
2011-02-08 03:02:54 +03:00
2010-12-26 12:40:40 +03:00
infoMsg = "adding words used on web page to the check list"
logger.info(infoMsg)
pageWords = getPageWordSet(kb.originalPage)
2011-01-07 19:36:32 +03:00
for word in pageWords:
word = word.lower()
2011-01-07 19:36:32 +03:00
if len(word) > 2 and not word[0].isdigit() and word not in wordsList:
wordsList.append(word)
2010-11-09 12:42:43 +03:00
return wordsList
def tableExists(tableFile, regex=None):
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), randomStr())))
if result:
errMsg = "can't use table existence check because of detected invalid results "
errMsg += "(most probably caused by inability of the used injection "
errMsg += "to distinguish errornous results)"
raise sqlmapDataException, errMsg
2012-06-16 00:49:28 +04:00
tables = getFileItems(tableFile, lowercase=Backend.getIdentifiedDbms() in (DBMS.ACCESS,), unique=True)
infoMsg = "checking table existence using items from '%s'" % tableFile
logger.info(infoMsg)
tables.extend(__addPageTextWords())
tables = filterListValue(tables, regex)
2011-06-07 14:08:12 +04:00
threadData = getCurrentThreadData()
threadData.shared.count = 0
threadData.shared.limit = len(tables)
threadData.shared.outputs = []
threadData.shared.unique = set()
2010-12-21 02:21:01 +03:00
def tableExistsThread():
2011-06-07 14:08:12 +04:00
threadData = getCurrentThreadData()
while kb.threadContinue:
2011-12-28 20:27:17 +04:00
kb.locks.count.acquire()
2011-06-07 14:08:12 +04:00
if threadData.shared.count < threadData.shared.limit:
2011-06-16 18:27:44 +04:00
table = safeSQLIdentificatorNaming(tables[threadData.shared.count], True)
2011-06-07 14:08:12 +04:00
threadData.shared.count += 1
2011-12-28 20:27:17 +04:00
kb.locks.count.release()
2011-06-07 14:08:12 +04:00
else:
2011-12-28 20:27:17 +04:00
kb.locks.count.release()
2011-06-07 14:08:12 +04:00
break
2010-11-09 12:42:43 +03:00
2011-05-31 03:15:29 +04:00
if conf.db and METADB_SUFFIX not in conf.db:
fullTableName = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', table)
else:
fullTableName = table
2011-01-07 19:36:32 +03:00
result = inject.checkBooleanExpression("%s" % safeStringFormat(BRUTE_TABLE_EXISTS_TEMPLATE, (randomInt(1), fullTableName)))
2010-11-09 12:42:43 +03:00
2011-12-28 20:27:17 +04:00
kb.locks.io.acquire()
2011-01-07 19:36:32 +03:00
2011-06-07 14:08:12 +04:00
if result and table.lower() not in threadData.shared.unique:
threadData.shared.outputs.append(table)
threadData.shared.unique.add(table.lower())
2011-04-11 01:52:08 +04:00
2010-12-21 02:21:01 +03:00
if conf.verbose in (1, 2):
clearConsoleLine(True)
infoMsg = "[%s] [INFO] retrieved: %s\r\n" % (time.strftime("%X"), table)
2010-12-21 02:21:01 +03:00
dataToStdout(infoMsg, True)
2010-11-09 12:42:43 +03:00
if conf.verbose in (1, 2):
2011-06-07 14:08:12 +04:00
status = '%d/%d items (%d%s)' % (threadData.shared.count, threadData.shared.limit, round(100.0*threadData.shared.count/threadData.shared.limit), '%')
2011-01-16 03:15:30 +03:00
dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True)
2011-01-07 19:36:32 +03:00
2011-12-28 20:27:17 +04:00
kb.locks.io.release()
2010-11-09 12:42:43 +03:00
2010-12-21 02:21:01 +03:00
try:
2011-06-07 14:08:12 +04:00
runThreads(conf.threads, tableExistsThread, threadChoice=True)
2011-01-07 19:36:32 +03:00
2010-12-21 02:21:01 +03:00
except KeyboardInterrupt:
2011-06-07 14:08:12 +04:00
warnMsg = "user aborted during table existence "
warnMsg += "check. sqlmap will display partial output"
logger.warn(warnMsg)
2010-11-24 00:00:42 +03:00
clearConsoleLine(True)
2011-01-16 03:15:30 +03:00
dataToStdout("\n")
2010-11-09 12:42:43 +03:00
2011-06-07 14:08:12 +04:00
if not threadData.shared.outputs:
2011-05-31 03:04:49 +04:00
warnMsg = "no table(s) found"
2010-11-09 12:42:43 +03:00
logger.warn(warnMsg)
else:
2011-06-07 14:08:12 +04:00
for item in threadData.shared.outputs:
2012-07-14 13:01:30 +04:00
if conf.db not in kb.data.cachedTables:
kb.data.cachedTables[conf.db] = [item]
else:
kb.data.cachedTables[conf.db].append(item)
2010-11-09 12:42:43 +03:00
2011-12-28 17:50:03 +04:00
for _ in map(lambda x: (conf.db, x), threadData.shared.outputs):
if _ not in kb.brute.tables:
kb.brute.tables.append(_)
hashDBWrite(HASHDB_KEYS.KB_BRUTE_TABLES, kb.brute.tables, True)
2011-12-28 17:50:03 +04:00
return kb.data.cachedTables
2010-11-09 12:42:43 +03:00
def columnExists(columnFile, regex=None):
if not conf.tbl:
errMsg = "missing table parameter"
raise sqlmapMissingMandatoryOptionException, errMsg
result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (randomStr(), randomStr())))
if result:
errMsg = "can't use column existence check because of detected invalid results "
errMsg += "(most probably caused by inability of the used injection "
errMsg += "to distinguish errornous results)"
raise sqlmapDataException, errMsg
infoMsg = "checking column existence using items from '%s'" % columnFile
logger.info(infoMsg)
2010-12-26 14:15:02 +03:00
columns = getFileItems(columnFile, unique=True)
columns.extend(__addPageTextWords())
columns = filterListValue(columns, regex)
2011-05-31 03:15:29 +04:00
if conf.db and METADB_SUFFIX not in conf.db:
2011-02-09 20:05:06 +03:00
table = "%s%s%s" % (conf.db, '..' if Backend.getIdentifiedDbms() in (DBMS.MSSQL, DBMS.SYBASE) else '.', conf.tbl)
2010-11-12 01:26:36 +03:00
else:
table = conf.tbl
2011-06-16 18:27:44 +04:00
table = safeSQLIdentificatorNaming(table, True)
2010-11-12 01:26:36 +03:00
kb.threadContinue = True
kb.bruteMode = True
threadData = getCurrentThreadData()
threadData.shared.count = 0
threadData.shared.limit = len(columns)
threadData.shared.outputs = []
def columnExistsThread():
threadData = getCurrentThreadData()
while kb.threadContinue:
2011-12-28 20:27:17 +04:00
kb.locks.count.acquire()
if threadData.shared.count < threadData.shared.limit:
column = safeSQLIdentificatorNaming(columns[threadData.shared.count])
threadData.shared.count += 1
2011-12-28 20:27:17 +04:00
kb.locks.count.release()
else:
2011-12-28 20:27:17 +04:00
kb.locks.count.release()
break
2010-11-09 12:42:43 +03:00
result = inject.checkBooleanExpression(safeStringFormat(BRUTE_COLUMN_EXISTS_TEMPLATE, (column, table)))
2010-11-09 12:42:43 +03:00
2011-12-28 20:27:17 +04:00
kb.locks.io.acquire()
2011-01-07 19:36:32 +03:00
if result:
threadData.shared.outputs.append(column)
if conf.verbose in (1, 2):
clearConsoleLine(True)
infoMsg = "[%s] [INFO] retrieved: %s\r\n" % (time.strftime("%X"), column)
dataToStdout(infoMsg, True)
2010-11-09 12:42:43 +03:00
if conf.verbose in (1, 2):
status = '%d/%d items (%d%s)' % (threadData.shared.count, threadData.shared.limit, round(100.0*threadData.shared.count/threadData.shared.limit), '%')
2011-01-16 03:15:30 +03:00
dataToStdout("\r[%s] [INFO] tried %s" % (time.strftime("%X"), status), True)
2011-01-07 19:36:32 +03:00
2011-12-28 20:27:17 +04:00
kb.locks.io.release()
2010-11-09 12:42:43 +03:00
try:
runThreads(conf.threads, columnExistsThread, threadChoice=True)
2011-01-07 19:36:32 +03:00
except KeyboardInterrupt:
warnMsg = "user aborted during column existence "
warnMsg += "check. sqlmap will display partial output"
logger.warn(warnMsg)
2010-11-24 00:00:42 +03:00
clearConsoleLine(True)
2011-01-16 03:15:30 +03:00
dataToStdout("\n")
2010-11-09 12:42:43 +03:00
if not threadData.shared.outputs:
2011-05-31 03:04:49 +04:00
warnMsg = "no column(s) found"
2010-11-09 12:42:43 +03:00
logger.warn(warnMsg)
else:
columns = {}
2010-11-09 12:42:43 +03:00
for column in threadData.shared.outputs:
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)=ROUND(%s))", (column, table, column, column)))
if result:
columns[column] = 'numeric'
else:
columns[column] = 'non-numeric'
kb.data.cachedColumns[conf.db] = {conf.tbl: columns}
2011-12-28 17:50:03 +04:00
for _ in map(lambda x: (conf.db, conf.tbl, x[0], x[1]), columns.items()):
if _ not in kb.brute.columns:
kb.brute.columns.append(_)
hashDBWrite(HASHDB_KEYS.KB_BRUTE_COLUMNS, kb.brute.columns, True)
2011-12-28 17:50:03 +04:00
return kb.data.cachedColumns