mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-02-09 08:00:36 +03:00
resume of brute forced data is now available
This commit is contained in:
parent
c7a160bf72
commit
9fb0e0fc85
|
@ -1128,6 +1128,10 @@ def __setKnowledgeBaseAttributes(flushAll=True):
|
||||||
kb.authHeader = None
|
kb.authHeader = None
|
||||||
kb.bannerFp = advancedDict()
|
kb.bannerFp = advancedDict()
|
||||||
|
|
||||||
|
kb.brute = advancedDict()
|
||||||
|
kb.brute.tables = []
|
||||||
|
kb.brute.columns = []
|
||||||
|
|
||||||
kb.cache = advancedDict()
|
kb.cache = advancedDict()
|
||||||
kb.cache.content = {}
|
kb.cache.content = {}
|
||||||
kb.cache.regex = {}
|
kb.cache.regex = {}
|
||||||
|
|
|
@ -21,6 +21,7 @@ from lib.core.data import logger
|
||||||
from lib.core.datatype import injectionDict
|
from lib.core.datatype import injectionDict
|
||||||
from lib.core.enums import PAYLOAD
|
from lib.core.enums import PAYLOAD
|
||||||
from lib.core.enums import PLACE
|
from lib.core.enums import PLACE
|
||||||
|
from lib.core.settings import METADB_SUFFIX
|
||||||
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 PGSQL_ALIASES
|
from lib.core.settings import PGSQL_ALIASES
|
||||||
|
@ -357,6 +358,35 @@ def resumeConfKb(expression, url, value):
|
||||||
else:
|
else:
|
||||||
conf.os = os
|
conf.os = os
|
||||||
|
|
||||||
|
elif expression == "TABLE_EXISTS" and url == conf.url:
|
||||||
|
table = unSafeFormatString(value[:-1])
|
||||||
|
|
||||||
|
if '.' in table:
|
||||||
|
db, table = table.split('.')
|
||||||
|
else:
|
||||||
|
db = "%s%s" % (kb.dbms, METADB_SUFFIX)
|
||||||
|
|
||||||
|
logMsg = "resuming brute forced table name "
|
||||||
|
logMsg += "'%s' from session file" % table
|
||||||
|
logger.info(logMsg)
|
||||||
|
|
||||||
|
kb.brute.tables.append((db, table))
|
||||||
|
|
||||||
|
elif expression == "COLUMN_EXISTS" and url == conf.url:
|
||||||
|
table, column = unSafeFormatString(value[:-1]).split('..')
|
||||||
|
colName, colType = column.split(' ')
|
||||||
|
|
||||||
|
if '.' in table:
|
||||||
|
db, table = table.split('.')
|
||||||
|
else:
|
||||||
|
db = "%s%s" % (kb.dbms, METADB_SUFFIX)
|
||||||
|
|
||||||
|
logMsg = "resuming brute forced column name "
|
||||||
|
logMsg += "'%s' for table '%s' from session file" % (colName, table)
|
||||||
|
logger.info(logMsg)
|
||||||
|
|
||||||
|
kb.brute.columns.append((db, table, colName, colType))
|
||||||
|
|
||||||
elif expression == "Union comment" and url == conf.url:
|
elif expression == "Union comment" and url == conf.url:
|
||||||
kb.unionComment = unSafeFormatString(value[:-1])
|
kb.unionComment = unSafeFormatString(value[:-1])
|
||||||
|
|
||||||
|
|
|
@ -403,6 +403,7 @@ def getValue(expression, blind=True, inband=True, error=True, time=True, fromUse
|
||||||
query = expandAsteriskForColumns(query)
|
query = expandAsteriskForColumns(query)
|
||||||
value = None
|
value = None
|
||||||
found = False
|
found = False
|
||||||
|
if query and not 'COUNT(*)' in query:
|
||||||
query = query.replace("DISTINCT ", "")
|
query = query.replace("DISTINCT ", "")
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from lib.core.common import clearConsoleLine
|
from lib.core.common import clearConsoleLine
|
||||||
|
from lib.core.common import dataToSessionFile
|
||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
from lib.core.common import filterListValue
|
from lib.core.common import filterListValue
|
||||||
from lib.core.common import getFileItems
|
from lib.core.common import getFileItems
|
||||||
|
@ -26,6 +27,7 @@ from lib.core.enums import DBMS
|
||||||
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
||||||
from lib.core.exception import sqlmapThreadException
|
from lib.core.exception import sqlmapThreadException
|
||||||
from lib.core.settings import METADB_SUFFIX
|
from lib.core.settings import METADB_SUFFIX
|
||||||
|
from lib.core.session import safeFormatString
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
|
|
||||||
def tableExists(tableFile, regex=None):
|
def tableExists(tableFile, regex=None):
|
||||||
|
@ -59,13 +61,19 @@ def tableExists(tableFile, regex=None):
|
||||||
tbllock.release()
|
tbllock.release()
|
||||||
|
|
||||||
if conf.db and not conf.db.endswith(METADB_SUFFIX):
|
if conf.db and not conf.db.endswith(METADB_SUFFIX):
|
||||||
table = "%s.%s" % (conf.db, table)
|
fullTableName = "%s.%s" % (conf.db, table)
|
||||||
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %d FROM %s)", (randomInt(1), table)))
|
else:
|
||||||
|
fullTableName = table
|
||||||
|
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %d FROM %s)", (randomInt(1), fullTableName)))
|
||||||
|
|
||||||
iolock.acquire()
|
iolock.acquire()
|
||||||
if result:
|
if result:
|
||||||
retVal.append(table)
|
retVal.append(table)
|
||||||
|
|
||||||
|
dataToSessionFile("[%s][%s][%s][TABLE_EXISTS][%s]\n" % (conf.url,\
|
||||||
|
kb.injection.place, safeFormatString(conf.parameters[kb.injection.place]),\
|
||||||
|
safeFormatString(fullTableName)))
|
||||||
|
|
||||||
if conf.verbose in (1, 2):
|
if conf.verbose in (1, 2):
|
||||||
clearConsoleLine(True)
|
clearConsoleLine(True)
|
||||||
infoMsg = "\r[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), table)
|
infoMsg = "\r[%s] [INFO] retrieved: %s\n" % (time.strftime("%X"), table)
|
||||||
|
@ -227,13 +235,17 @@ def columnExists(columnFile, regex=None):
|
||||||
columns = {}
|
columns = {}
|
||||||
|
|
||||||
for column in retVal:
|
for column in retVal:
|
||||||
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE RND(%s)>0)", (column, table, column)))
|
result = inject.checkBooleanExpression("%s" % safeStringFormat("EXISTS(SELECT %s FROM %s WHERE ROUND(%s)>0)", (column, table, column)))
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
columns[column] = 'numeric'
|
columns[column] = 'numeric'
|
||||||
else:
|
else:
|
||||||
columns[column] = 'non-numeric'
|
columns[column] = 'non-numeric'
|
||||||
|
|
||||||
|
dataToSessionFile("[%s][%s][%s][COLUMN_EXISTS][%s..%s %s]\n" % (conf.url, kb.injection.place,\
|
||||||
|
safeFormatString(conf.parameters[kb.injection.place]), safeFormatString(table),\
|
||||||
|
safeFormatString(column), safeFormatString(columns[column])))
|
||||||
|
|
||||||
kb.data.cachedColumns[conf.db] = {conf.tbl: columns}
|
kb.data.cachedColumns[conf.db] = {conf.tbl: columns}
|
||||||
|
|
||||||
return kb.data.cachedColumns
|
return kb.data.cachedColumns
|
||||||
|
|
|
@ -725,6 +725,8 @@ class Enumeration:
|
||||||
def getTables(self):
|
def getTables(self):
|
||||||
bruteForce = False
|
bruteForce = False
|
||||||
|
|
||||||
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
|
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
|
||||||
errMsg = "information_schema not available, "
|
errMsg = "information_schema not available, "
|
||||||
errMsg += "back-end DBMS is MySQL < 5.0"
|
errMsg += "back-end DBMS is MySQL < 5.0"
|
||||||
|
@ -738,6 +740,22 @@ class Enumeration:
|
||||||
bruteForce = True
|
bruteForce = True
|
||||||
|
|
||||||
if bruteForce:
|
if bruteForce:
|
||||||
|
resumeAvailable = False
|
||||||
|
for db, table in kb.brute.tables:
|
||||||
|
if db == conf.db:
|
||||||
|
resumeAvailable = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if resumeAvailable:
|
||||||
|
for db, table in kb.brute.tables:
|
||||||
|
if db == conf.db:
|
||||||
|
if not kb.data.cachedTables.has_key(conf.db):
|
||||||
|
kb.data.cachedTables[conf.db] = [table]
|
||||||
|
else:
|
||||||
|
kb.data.cachedTables[conf.db].append(table)
|
||||||
|
|
||||||
|
return kb.data.cachedTables
|
||||||
|
|
||||||
message = "do you want to use common table existance check? [Y/n/q]"
|
message = "do you want to use common table existance check? [Y/n/q]"
|
||||||
test = readInput(message, default="Y")
|
test = readInput(message, default="Y")
|
||||||
|
|
||||||
|
@ -748,8 +766,6 @@ class Enumeration:
|
||||||
else:
|
else:
|
||||||
return tableExists(paths.COMMON_TABLES)
|
return tableExists(paths.COMMON_TABLES)
|
||||||
|
|
||||||
self.forceDbmsEnum()
|
|
||||||
|
|
||||||
infoMsg = "fetching tables"
|
infoMsg = "fetching tables"
|
||||||
if conf.db:
|
if conf.db:
|
||||||
infoMsg += " for database '%s'" % conf.db
|
infoMsg += " for database '%s'" % conf.db
|
||||||
|
@ -869,6 +885,11 @@ class Enumeration:
|
||||||
def getColumns(self, onlyColNames=False):
|
def getColumns(self, onlyColNames=False):
|
||||||
bruteForce = False
|
bruteForce = False
|
||||||
|
|
||||||
|
if "." in conf.tbl:
|
||||||
|
conf.db, conf.tbl = conf.tbl.split(".")
|
||||||
|
|
||||||
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
|
if kb.dbms == DBMS.MYSQL and not kb.data.has_information_schema:
|
||||||
errMsg = "information_schema not available, "
|
errMsg = "information_schema not available, "
|
||||||
errMsg += "back-end DBMS is MySQL < 5.0"
|
errMsg += "back-end DBMS is MySQL < 5.0"
|
||||||
|
@ -882,6 +903,21 @@ class Enumeration:
|
||||||
bruteForce = True
|
bruteForce = True
|
||||||
|
|
||||||
if bruteForce:
|
if bruteForce:
|
||||||
|
resumeAvailable = False
|
||||||
|
for db, table, colName, colType in kb.brute.columns:
|
||||||
|
if db == conf.db and table == conf.tbl:
|
||||||
|
resumeAvailable = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if resumeAvailable:
|
||||||
|
columns = {}
|
||||||
|
for db, table, colName, colType in kb.brute.columns:
|
||||||
|
if db == conf.db and table == conf.tbl:
|
||||||
|
columns[colName] = colType
|
||||||
|
|
||||||
|
kb.data.cachedColumns[conf.db] = {conf.tbl: columns}
|
||||||
|
return kb.data.cachedColumns
|
||||||
|
|
||||||
message = "do you want to use common columns existance check? [Y/n/q]"
|
message = "do you want to use common columns existance check? [Y/n/q]"
|
||||||
test = readInput(message, default="Y")
|
test = readInput(message, default="Y")
|
||||||
|
|
||||||
|
@ -896,11 +932,6 @@ class Enumeration:
|
||||||
errMsg = "missing table parameter"
|
errMsg = "missing table parameter"
|
||||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||||
|
|
||||||
if "." in conf.tbl:
|
|
||||||
conf.db, conf.tbl = conf.tbl.split(".")
|
|
||||||
|
|
||||||
self.forceDbmsEnum()
|
|
||||||
|
|
||||||
if not conf.db:
|
if not conf.db:
|
||||||
warnMsg = "missing database parameter, sqlmap is going to "
|
warnMsg = "missing database parameter, sqlmap is going to "
|
||||||
warnMsg += "use the current database to enumerate table "
|
warnMsg += "use the current database to enumerate table "
|
||||||
|
@ -1219,6 +1250,7 @@ class Enumeration:
|
||||||
|
|
||||||
if kb.dbms == DBMS.ACCESS:
|
if kb.dbms == DBMS.ACCESS:
|
||||||
validColumnList = False
|
validColumnList = False
|
||||||
|
validPivotValue = False
|
||||||
|
|
||||||
for column in colList:
|
for column in colList:
|
||||||
infoMsg = "fetching number of distinct "
|
infoMsg = "fetching number of distinct "
|
||||||
|
@ -1235,6 +1267,8 @@ class Enumeration:
|
||||||
infoMsg += "for retrieving row data"
|
infoMsg += "for retrieving row data"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
validPivotValue = True
|
||||||
|
|
||||||
colList.remove(column)
|
colList.remove(column)
|
||||||
colList.insert(0, column)
|
colList.insert(0, column)
|
||||||
break
|
break
|
||||||
|
@ -1243,8 +1277,16 @@ class Enumeration:
|
||||||
errMsg = "all column name(s) provided are non-existent"
|
errMsg = "all column name(s) provided are non-existent"
|
||||||
raise sqlmapNoneDataException, errMsg
|
raise sqlmapNoneDataException, errMsg
|
||||||
|
|
||||||
|
if not validPivotValue:
|
||||||
|
warnMsg = "no proper pivot column provided (with unique values)."
|
||||||
|
warnMsg += " all row data won't be retrieved."
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
pivotValue = " "
|
pivotValue = " "
|
||||||
|
breakRetrieval = False
|
||||||
for index in indexRange:
|
for index in indexRange:
|
||||||
|
if breakRetrieval:
|
||||||
|
break
|
||||||
for column in colList:
|
for column in colList:
|
||||||
if column not in lengths:
|
if column not in lengths:
|
||||||
lengths[column] = 0
|
lengths[column] = 0
|
||||||
|
@ -1264,6 +1306,7 @@ class Enumeration:
|
||||||
value = inject.getValue(query, inband=False)
|
value = inject.getValue(query, inband=False)
|
||||||
if column == colList[0]:
|
if column == colList[0]:
|
||||||
if not value:
|
if not value:
|
||||||
|
breakRetrieval = True
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
pivotValue = value
|
pivotValue = value
|
||||||
|
|
Loading…
Reference in New Issue
Block a user