sqlmap/lib/utils/hashdb.py

221 lines
8.3 KiB
Python
Raw Permalink Normal View History

2019-05-08 13:47:52 +03:00
#!/usr/bin/env python
"""
2023-01-03 01:24:59 +03:00
Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/)
2017-10-11 15:50:46 +03:00
See the file 'LICENSE' for copying permission
"""
import hashlib
2012-07-26 17:42:04 +04:00
import os
import sqlite3
import threading
2012-02-27 15:15:53 +04:00
import time
from lib.core.common import getSafeExString
2011-12-28 17:50:03 +04:00
from lib.core.common import serializeObject
from lib.core.common import singleTimeWarnMessage
2011-12-28 17:50:03 +04:00
from lib.core.common import unserializeObject
2019-03-28 18:04:38 +03:00
from lib.core.compat import xrange
2019-05-03 14:20:15 +03:00
from lib.core.convert import getBytes
2019-05-06 01:54:21 +03:00
from lib.core.convert import getUnicode
2012-09-25 13:21:39 +04:00
from lib.core.data import logger
2016-11-09 14:20:54 +03:00
from lib.core.exception import SqlmapConnectionException
2014-03-24 13:46:23 +04:00
from lib.core.settings import HASHDB_END_TRANSACTION_RETRIES
2012-09-25 13:21:39 +04:00
from lib.core.settings import HASHDB_FLUSH_RETRIES
2011-11-22 14:54:29 +04:00
from lib.core.settings import HASHDB_FLUSH_THRESHOLD
2016-10-15 01:51:35 +03:00
from lib.core.settings import HASHDB_RETRIEVE_RETRIES
2011-09-26 17:36:08 +04:00
from lib.core.threads import getCurrentThreadData
from lib.core.threads import getCurrentThreadName
2019-04-18 17:06:19 +03:00
from thirdparty import six
2011-09-26 17:36:08 +04:00
class HashDB(object):
def __init__(self, filepath):
2011-09-26 17:36:08 +04:00
self.filepath = filepath
self._write_cache = {}
self._cache_lock = threading.Lock()
2021-09-30 00:01:32 +03:00
self._connections = []
2011-09-26 17:36:08 +04:00
def _get_cursor(self):
threadData = getCurrentThreadData()
if threadData.hashDBCursor is None:
2012-11-08 22:16:37 +04:00
try:
connection = sqlite3.connect(self.filepath, timeout=3, isolation_level=None)
2021-09-30 00:01:32 +03:00
self._connections.append(connection)
2012-11-08 22:16:37 +04:00
threadData.hashDBCursor = connection.cursor()
threadData.hashDBCursor.execute("CREATE TABLE IF NOT EXISTS storage (id INTEGER PRIMARY KEY, value TEXT)")
2015-12-30 15:39:08 +03:00
connection.commit()
2019-01-22 02:40:48 +03:00
except Exception as ex:
2012-11-08 22:16:37 +04:00
errMsg = "error occurred while opening a session "
2016-01-12 12:27:04 +03:00
errMsg += "file '%s' ('%s')" % (self.filepath, getSafeExString(ex))
2016-11-09 14:20:54 +03:00
raise SqlmapConnectionException(errMsg)
2011-09-26 17:36:08 +04:00
return threadData.hashDBCursor
2014-03-24 13:46:23 +04:00
def _set_cursor(self, cursor):
threadData = getCurrentThreadData()
threadData.hashDBCursor = cursor
cursor = property(_get_cursor, _set_cursor)
def close(self):
2011-10-25 15:20:42 +04:00
threadData = getCurrentThreadData()
try:
2011-10-25 15:20:42 +04:00
if threadData.hashDBCursor:
2022-04-06 23:41:12 +03:00
threadData.hashDBCursor.connection.commit()
2011-10-25 15:20:42 +04:00
threadData.hashDBCursor.close()
threadData.hashDBCursor.connection.close()
threadData.hashDBCursor = None
except:
pass
2021-09-30 00:01:32 +03:00
def closeAll(self):
for connection in self._connections:
try:
connection.commit()
connection.close()
except:
pass
@staticmethod
def hashKey(key):
2020-05-20 17:11:51 +03:00
key = getBytes(key if isinstance(key, six.text_type) else repr(key), errors="xmlcharrefreplace")
2016-04-11 10:43:50 +03:00
retVal = int(hashlib.md5(key).hexdigest(), 16) & 0x7fffffffffffffff # Reference: http://stackoverflow.com/a/4448400
return retVal
2011-12-28 17:50:03 +04:00
def retrieve(self, key, unserialize=False):
retVal = None
2015-10-24 00:48:41 +03:00
2012-07-26 17:42:04 +04:00
if key and (self._write_cache or os.path.isfile(self.filepath)):
hash_ = HashDB.hashKey(key)
2012-08-21 12:28:25 +04:00
retVal = self._write_cache.get(hash_)
2011-11-22 14:54:29 +04:00
if not retVal:
2016-10-15 01:51:35 +03:00
for _ in xrange(HASHDB_RETRIEVE_RETRIES):
2011-11-22 14:54:29 +04:00
try:
for row in self.cursor.execute("SELECT value FROM storage WHERE id=?", (hash_,)):
retVal = row[0]
2019-01-29 14:30:51 +03:00
except (sqlite3.OperationalError, sqlite3.DatabaseError) as ex:
2016-10-15 01:51:35 +03:00
if any(_ in getSafeExString(ex) for _ in ("locked", "no such table")):
warnMsg = "problem occurred while accessing session file '%s' ('%s')" % (self.filepath, getSafeExString(ex))
singleTimeWarnMessage(warnMsg)
2016-10-15 01:51:35 +03:00
elif "Could not decode" in getSafeExString(ex):
break
else:
2019-01-29 14:30:51 +03:00
errMsg = "error occurred while accessing session file '%s' ('%s'). " % (self.filepath, getSafeExString(ex))
errMsg += "If the problem persists please rerun with '--flush-session'"
raise SqlmapConnectionException(errMsg)
2011-11-22 14:54:29 +04:00
else:
break
2015-10-24 00:48:41 +03:00
time.sleep(1)
2016-10-28 12:52:48 +03:00
if retVal and unserialize:
2015-10-24 00:48:41 +03:00
try:
retVal = unserializeObject(retVal)
except:
2016-03-28 20:55:33 +03:00
retVal = None
2015-10-24 00:48:41 +03:00
warnMsg = "error occurred while unserializing value for session key '%s'. " % key
2018-11-02 18:18:08 +03:00
warnMsg += "If the problem persists please rerun with '--flush-session'"
logger.warning(warnMsg)
2015-10-24 00:48:41 +03:00
return retVal
2011-12-28 17:50:03 +04:00
def write(self, key, value, serialize=False):
if key:
hash_ = HashDB.hashKey(key)
self._cache_lock.acquire()
2012-04-02 16:58:10 +04:00
self._write_cache[hash_] = getUnicode(value) if not serialize else serializeObject(value)
self._cache_lock.release()
2020-12-10 16:22:44 +03:00
if getCurrentThreadName() in ('0', "MainThread"):
self.flush()
2011-11-22 14:54:29 +04:00
def flush(self, forced=False):
2011-11-22 14:41:56 +04:00
if not self._write_cache:
return
2011-11-22 14:54:29 +04:00
if not forced and len(self._write_cache) < HASHDB_FLUSH_THRESHOLD:
return
self._cache_lock.acquire()
2011-11-22 16:44:28 +04:00
_ = self._write_cache
self._write_cache = {}
self._cache_lock.release()
2011-11-22 15:04:43 +04:00
try:
self.beginTransaction()
2011-11-22 16:44:28 +04:00
for hash_, value in _.items():
2012-09-25 13:21:39 +04:00
retries = 0
2011-11-22 15:04:43 +04:00
while True:
2011-10-10 18:23:17 +04:00
try:
2011-11-22 15:04:43 +04:00
try:
self.cursor.execute("INSERT INTO storage VALUES (?, ?)", (hash_, value,))
except sqlite3.IntegrityError:
self.cursor.execute("UPDATE storage SET value=? WHERE id=?", (value, hash_,))
2021-10-26 11:24:21 +03:00
except (UnicodeError, OverflowError): # e.g. surrogates not allowed (Issue #3851)
2019-07-25 00:43:08 +03:00
break
2019-01-22 02:40:48 +03:00
except sqlite3.DatabaseError as ex:
if not os.path.exists(self.filepath):
debugMsg = "session file '%s' does not exist" % self.filepath
logger.debug(debugMsg)
break
2012-09-25 13:21:39 +04:00
if retries == 0:
warnMsg = "there has been a problem while writing to "
warnMsg += "the session file ('%s')" % getSafeExString(ex)
logger.warning(warnMsg)
2012-09-25 13:21:39 +04:00
if retries >= HASHDB_FLUSH_RETRIES:
return
2012-02-27 15:15:53 +04:00
else:
2012-09-25 13:21:39 +04:00
retries += 1
2012-02-27 15:15:53 +04:00
time.sleep(1)
2011-11-22 15:04:43 +04:00
else:
break
finally:
self.endTransaction()
2011-11-02 13:57:42 +04:00
def beginTransaction(self):
2011-11-23 18:26:40 +04:00
threadData = getCurrentThreadData()
if not threadData.inTransaction:
2014-12-05 13:46:03 +03:00
try:
self.cursor.execute("BEGIN TRANSACTION")
except:
2023-08-01 12:33:13 +03:00
try:
# Reference: http://stackoverflow.com/a/25245731
self.cursor.close()
except sqlite3.ProgrammingError:
pass
2014-12-05 13:46:03 +03:00
threadData.hashDBCursor = None
self.cursor.execute("BEGIN TRANSACTION")
finally:
threadData.inTransaction = True
2011-11-02 13:57:42 +04:00
def endTransaction(self):
2011-11-23 18:26:40 +04:00
threadData = getCurrentThreadData()
if threadData.inTransaction:
2014-03-24 13:46:23 +04:00
retries = 0
while retries < HASHDB_END_TRANSACTION_RETRIES:
try:
self.cursor.execute("END TRANSACTION")
threadData.inTransaction = False
except sqlite3.OperationalError:
pass
2022-06-04 01:10:24 +03:00
except sqlite3.ProgrammingError:
self.cursor = None
threadData.inTransaction = False
return
2014-03-24 13:46:23 +04:00
else:
return
retries += 1
time.sleep(1)
2011-12-21 15:50:49 +04:00
try:
2014-03-24 13:46:23 +04:00
self.cursor.execute("ROLLBACK TRANSACTION")
2011-12-22 02:59:23 +04:00
except sqlite3.OperationalError:
2014-03-24 13:46:23 +04:00
self.cursor.close()
self.cursor = None
2011-12-21 15:50:49 +04:00
finally:
threadData.inTransaction = False