Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/lib/utils/pivotdumptable.py
2989 views
1
#!/usr/bin/env python
2
3
"""
4
Copyright (c) 2006-2025 sqlmap developers (https://sqlmap.org)
5
See the file 'LICENSE' for copying permission
6
"""
7
8
import re
9
10
from lib.core.agent import agent
11
from lib.core.bigarray import BigArray
12
from lib.core.common import Backend
13
from lib.core.common import filterNone
14
from lib.core.common import getSafeExString
15
from lib.core.common import isNoneValue
16
from lib.core.common import isNumPosStrValue
17
from lib.core.common import singleTimeWarnMessage
18
from lib.core.common import unArrayizeValue
19
from lib.core.common import unsafeSQLIdentificatorNaming
20
from lib.core.compat import xrange
21
from lib.core.convert import getUnicode
22
from lib.core.data import conf
23
from lib.core.data import kb
24
from lib.core.data import logger
25
from lib.core.data import queries
26
from lib.core.dicts import DUMP_REPLACEMENTS
27
from lib.core.enums import CHARSET_TYPE
28
from lib.core.enums import EXPECTED
29
from lib.core.exception import SqlmapConnectionException
30
from lib.core.exception import SqlmapNoneDataException
31
from lib.core.settings import MAX_INT
32
from lib.core.settings import NULL
33
from lib.core.settings import SINGLE_QUOTE_MARKER
34
from lib.core.unescaper import unescaper
35
from lib.request import inject
36
from lib.utils.safe2bin import safechardecode
37
from thirdparty.six import unichr as _unichr
38
39
def pivotDumpTable(table, colList, count=None, blind=True, alias=None):
40
lengths = {}
41
entries = {}
42
43
dumpNode = queries[Backend.getIdentifiedDbms()].dump_table.blind
44
45
validColumnList = False
46
validPivotValue = False
47
48
if count is None:
49
query = dumpNode.count % table
50
query = agent.whereQuery(query)
51
count = inject.getValue(query, union=False, error=False, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS) if blind else inject.getValue(query, blind=False, time=False, expected=EXPECTED.INT)
52
53
if hasattr(count, "isdigit") and count.isdigit():
54
count = int(count)
55
56
if count == 0:
57
infoMsg = "table '%s' appears to be empty" % unsafeSQLIdentificatorNaming(table)
58
logger.info(infoMsg)
59
60
for column in colList:
61
lengths[column] = len(column)
62
entries[column] = []
63
64
return entries, lengths
65
66
elif not isNumPosStrValue(count):
67
return None
68
69
for column in colList:
70
lengths[column] = 0
71
entries[column] = BigArray()
72
73
colList = filterNone(sorted(colList, key=lambda x: len(x) if x else MAX_INT))
74
75
if conf.pivotColumn:
76
for _ in colList:
77
if re.search(r"(.+\.)?%s" % re.escape(conf.pivotColumn), _, re.I):
78
infoMsg = "using column '%s' as a pivot " % conf.pivotColumn
79
infoMsg += "for retrieving row data"
80
logger.info(infoMsg)
81
82
colList.remove(_)
83
colList.insert(0, _)
84
85
validPivotValue = True
86
break
87
88
if not validPivotValue:
89
warnMsg = "column '%s' not " % conf.pivotColumn
90
warnMsg += "found in table '%s'" % table
91
logger.warning(warnMsg)
92
93
if not validPivotValue:
94
for column in colList:
95
infoMsg = "fetching number of distinct "
96
infoMsg += "values for column '%s'" % column.replace(("%s." % alias) if alias else "", "")
97
logger.info(infoMsg)
98
99
query = dumpNode.count2 % (column, table)
100
query = agent.whereQuery(query)
101
value = inject.getValue(query, blind=blind, union=not blind, error=not blind, expected=EXPECTED.INT, charsetType=CHARSET_TYPE.DIGITS)
102
103
if isNumPosStrValue(value):
104
validColumnList = True
105
106
if value == count:
107
infoMsg = "using column '%s' as a pivot " % column.replace(("%s." % alias) if alias else "", "")
108
infoMsg += "for retrieving row data"
109
logger.info(infoMsg)
110
111
validPivotValue = True
112
colList.remove(column)
113
colList.insert(0, column)
114
break
115
116
if not validColumnList:
117
errMsg = "all provided column name(s) are non-existent"
118
raise SqlmapNoneDataException(errMsg)
119
120
if not validPivotValue:
121
warnMsg = "no proper pivot column provided (with unique values)."
122
warnMsg += " It won't be possible to retrieve all rows"
123
logger.warning(warnMsg)
124
125
pivotValue = " "
126
breakRetrieval = False
127
128
def _(column, pivotValue):
129
if column == colList[0]:
130
query = dumpNode.query.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, column), unescaper.escape(pivotValue, False))
131
else:
132
query = dumpNode.query2.replace("'%s'" if unescaper.escape(pivotValue, False) != pivotValue else "%s", "%s") % (agent.preprocessField(table, column), table, agent.preprocessField(table, colList[0]), unescaper.escape(pivotValue, False) if SINGLE_QUOTE_MARKER not in dumpNode.query2 else pivotValue)
133
134
query = agent.whereQuery(query)
135
return unArrayizeValue(inject.getValue(query, blind=blind, time=blind, union=not blind, error=not blind))
136
137
try:
138
for i in xrange(count):
139
if breakRetrieval:
140
break
141
142
for column in colList:
143
value = _(column, pivotValue)
144
if column == colList[0]:
145
if isNoneValue(value):
146
try:
147
for pivotValue in filterNone((" " if pivotValue == " " else None, "%s%s" % (pivotValue[0], _unichr(ord(pivotValue[1]) + 1)) if len(pivotValue) > 1 else None, _unichr(ord(pivotValue[0]) + 1))):
148
value = _(column, pivotValue)
149
if not isNoneValue(value):
150
break
151
except ValueError:
152
pass
153
154
if isNoneValue(value) or value == NULL:
155
breakRetrieval = True
156
break
157
158
pivotValue = safechardecode(value)
159
160
if conf.limitStart or conf.limitStop:
161
if conf.limitStart and (i + 1) < conf.limitStart:
162
warnMsg = "skipping first %d pivot " % conf.limitStart
163
warnMsg += "point values"
164
singleTimeWarnMessage(warnMsg)
165
break
166
elif conf.limitStop and (i + 1) > conf.limitStop:
167
breakRetrieval = True
168
break
169
170
value = "" if isNoneValue(value) else unArrayizeValue(value)
171
172
lengths[column] = max(lengths[column], len(DUMP_REPLACEMENTS.get(getUnicode(value), getUnicode(value))))
173
entries[column].append(value)
174
175
except KeyboardInterrupt:
176
kb.dumpKeyboardInterrupt = True
177
178
warnMsg = "user aborted during enumeration. sqlmap "
179
warnMsg += "will display partial output"
180
logger.warning(warnMsg)
181
182
except SqlmapConnectionException as ex:
183
errMsg = "connection exception detected ('%s'). sqlmap " % getSafeExString(ex)
184
errMsg += "will display partial output"
185
186
logger.critical(errMsg)
187
188
return entries, lengths
189
190