mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-08-04 14:55:40 +00:00
Bug fix for dump format SQLITE
This commit is contained in:
parent
384ee1a91a
commit
109ce217ec
3 changed files with 45 additions and 3 deletions
|
|
@ -54,6 +54,8 @@ from lib.core.settings import HTML_DUMP_CSS_STYLE
|
|||
from lib.core.settings import IS_WIN
|
||||
from lib.core.settings import METADB_SUFFIX
|
||||
from lib.core.settings import MIN_BINARY_DISK_DUMP_SIZE
|
||||
from lib.core.settings import SQLITE_INT_MAX
|
||||
from lib.core.settings import SQLITE_INT_MIN
|
||||
from lib.core.settings import TRIM_STDOUT_DUMP_SIZE
|
||||
from lib.core.settings import UNICODE_ENCODING
|
||||
from lib.core.settings import UNSAFE_DUMP_FILEPATH_REPLACEMENT
|
||||
|
|
@ -558,7 +560,10 @@ class Dump(object):
|
|||
if not value or value == " ": # NULL
|
||||
continue
|
||||
|
||||
int(value)
|
||||
# Note: keep INTEGER only for values SQLite's affinity leaves untouched; leading zeros ('007'), signs ('+1') or 64-bit overflow would be silently rewritten on insert
|
||||
parsed = int(value)
|
||||
if str(parsed) != value or not (SQLITE_INT_MIN <= parsed <= SQLITE_INT_MAX):
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
colType = None
|
||||
break
|
||||
|
|
@ -572,7 +577,9 @@ class Dump(object):
|
|||
if not value or value == " ": # NULL
|
||||
continue
|
||||
|
||||
float(value)
|
||||
# Note: likewise REAL must round-trip textually ('2.00' or '1e5' would lose their exact form)
|
||||
if repr(float(value)) != value:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
colType = None
|
||||
break
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from lib.core.enums import OS
|
|||
from thirdparty import six
|
||||
|
||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||
VERSION = "1.10.7.119"
|
||||
VERSION = "1.10.7.120"
|
||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||
|
|
@ -683,6 +683,10 @@ HASH_EMPTY_PASSWORD_MARKER = "<empty>"
|
|||
# Maximum integer value
|
||||
MAX_INT = sys.maxsize
|
||||
|
||||
# Signed 64-bit range of SQLite's INTEGER storage class (used for safe --dump-format=SQLITE typing)
|
||||
SQLITE_INT_MIN = -0x8000000000000000
|
||||
SQLITE_INT_MAX = 0x7fffffffffffffff
|
||||
|
||||
# Replacement for unsafe characters in dump table filenames
|
||||
UNSAFE_DUMP_FILEPATH_REPLACEMENT = '_'
|
||||
|
||||
|
|
|
|||
|
|
@ -358,6 +358,37 @@ class TestSqliteDump(_FileDumpCase):
|
|||
finally:
|
||||
conn.close()
|
||||
|
||||
def test_non_roundtrip_numbers_stay_text(self):
|
||||
# Values that look numeric but would be silently rewritten by SQLite's INTEGER/REAL
|
||||
# affinity (leading zeros, sign prefix, 64-bit overflow, trailing-zero/exponent floats)
|
||||
# must be stored verbatim as TEXT, otherwise the export corrupts the dumped data
|
||||
tv = _PlainOrderedDict([
|
||||
("__infos__", {"count": 1, "db": "testdb", "table": "t"}),
|
||||
("zip", {"length": 5, "values": ["007"]}),
|
||||
("phone", {"length": 10, "values": ["0917123456"]}),
|
||||
("signed", {"length": 2, "values": ["+1"]}),
|
||||
("huge", {"length": 30, "values": ["123456789012345678901234567890"]}),
|
||||
("money", {"length": 4, "values": ["2.00"]}),
|
||||
("real_int", {"length": 1, "values": ["5"]}), # genuine ints still typed INTEGER
|
||||
])
|
||||
conf.dumpFormat = DUMP_FORMAT.SQLITE
|
||||
self.d.dbTableValues(tv)
|
||||
|
||||
import sqlite3
|
||||
conn = sqlite3.connect(os.path.join(self.tmp, "testdb.sqlite3"))
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT zip, phone, signed, huge, money, real_int FROM t")
|
||||
self.assertEqual(cur.fetchone(), ("007", "0917123456", "+1", "123456789012345678901234567890", "2.00", 5))
|
||||
cur.execute("PRAGMA table_info(t)")
|
||||
types = {name: ctype for (_cid, name, ctype, _nn, _dv, _pk) in cur.fetchall()}
|
||||
self.assertEqual(types["zip"], "TEXT")
|
||||
self.assertEqual(types["huge"], "TEXT")
|
||||
self.assertEqual(types["money"], "TEXT")
|
||||
self.assertEqual(types["real_int"], "INTEGER")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
# --- replication backend tests (pure sqlite3, no network/DBMS) -----------------------------------
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue