Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sqlmapproject
GitHub Repository: sqlmapproject/sqlmap
Path: blob/master/plugins/dbms/access/fingerprint.py
2992 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.common import Backend
11
from lib.core.common import Format
12
from lib.core.common import getCurrentThreadData
13
from lib.core.common import randomStr
14
from lib.core.common import wasLastResponseDBMSError
15
from lib.core.data import conf
16
from lib.core.data import kb
17
from lib.core.data import logger
18
from lib.core.enums import DBMS
19
from lib.core.session import setDbms
20
from lib.core.settings import ACCESS_ALIASES
21
from lib.core.settings import METADB_SUFFIX
22
from lib.request import inject
23
from plugins.generic.fingerprint import Fingerprint as GenericFingerprint
24
25
class Fingerprint(GenericFingerprint):
26
def __init__(self):
27
GenericFingerprint.__init__(self, DBMS.ACCESS)
28
29
def _sandBoxCheck(self):
30
# Reference: http://milw0rm.com/papers/198
31
retVal = None
32
table = None
33
34
if Backend.isVersionWithin(("97", "2000")):
35
table = "MSysAccessObjects"
36
elif Backend.isVersionWithin(("2002-2003", "2007")):
37
table = "MSysAccessStorage"
38
39
if table is not None:
40
result = inject.checkBooleanExpression("EXISTS(SELECT CURDIR() FROM %s)" % table)
41
retVal = "not sandboxed" if result else "sandboxed"
42
43
return retVal
44
45
def _sysTablesCheck(self):
46
infoMsg = "executing system table(s) existence fingerprint"
47
logger.info(infoMsg)
48
49
# Microsoft Access table reference updated on 01/2010
50
sysTables = {
51
"97": ("MSysModules2", "MSysAccessObjects"),
52
"2000": ("!MSysModules2", "MSysAccessObjects"),
53
"2002-2003": ("MSysAccessStorage", "!MSysNavPaneObjectIDs"),
54
"2007": ("MSysAccessStorage", "MSysNavPaneObjectIDs"),
55
}
56
57
# MSysAccessXML is not a reliable system table because it doesn't always exist
58
# ("Access through Access", p6, should be "normally doesn't exist" instead of "is normally empty")
59
60
for version, tables in sysTables.items():
61
exist = True
62
63
for table in tables:
64
negate = False
65
66
if table[0] == '!':
67
negate = True
68
table = table[1:]
69
70
result = inject.checkBooleanExpression("EXISTS(SELECT * FROM %s WHERE [RANDNUM]=[RANDNUM])" % table)
71
if result is None:
72
result = False
73
74
if negate:
75
result = not result
76
77
exist &= result
78
79
if not exist:
80
break
81
82
if exist:
83
return version
84
85
return None
86
87
def _getDatabaseDir(self):
88
retVal = None
89
90
infoMsg = "searching for database directory"
91
logger.info(infoMsg)
92
93
randStr = randomStr()
94
inject.checkBooleanExpression("EXISTS(SELECT * FROM %s.%s WHERE [RANDNUM]=[RANDNUM])" % (randStr, randStr))
95
96
if wasLastResponseDBMSError():
97
threadData = getCurrentThreadData()
98
match = re.search(r"Could not find file\s+'([^']+?)'", threadData.lastErrorPage[1])
99
100
if match:
101
retVal = match.group(1).rstrip("%s.mdb" % randStr)
102
103
if retVal.endswith('\\'):
104
retVal = retVal[:-1]
105
106
return retVal
107
108
def getFingerprint(self):
109
value = ""
110
wsOsFp = Format.getOs("web server", kb.headersFp)
111
112
if wsOsFp:
113
value += "%s\n" % wsOsFp
114
115
if kb.data.banner:
116
dbmsOsFp = Format.getOs("back-end DBMS", kb.bannerFp)
117
118
if dbmsOsFp:
119
value += "%s\n" % dbmsOsFp
120
121
value += "back-end DBMS: "
122
123
if not conf.extensiveFp:
124
value += DBMS.ACCESS
125
return value
126
127
actVer = Format.getDbms() + " (%s)" % (self._sandBoxCheck())
128
blank = " " * 15
129
value += "active fingerprint: %s" % actVer
130
131
if kb.bannerFp:
132
banVer = kb.bannerFp.get("dbmsVersion")
133
134
if banVer:
135
if re.search(r"-log$", kb.data.banner or ""):
136
banVer += ", logging enabled"
137
138
banVer = Format.getDbms([banVer])
139
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
140
141
htmlErrorFp = Format.getErrorParsedDBMSes()
142
143
if htmlErrorFp:
144
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
145
146
value += "\ndatabase directory: '%s'" % self._getDatabaseDir()
147
148
return value
149
150
def checkDbms(self):
151
if not conf.extensiveFp and Backend.isDbmsWithin(ACCESS_ALIASES):
152
setDbms(DBMS.ACCESS)
153
154
return True
155
156
infoMsg = "testing %s" % DBMS.ACCESS
157
logger.info(infoMsg)
158
159
result = inject.checkBooleanExpression("VAL(CVAR(1))=1")
160
161
if result:
162
infoMsg = "confirming %s" % DBMS.ACCESS
163
logger.info(infoMsg)
164
165
result = inject.checkBooleanExpression("IIF(ATN(2) IS NOT NULL,1,0) BETWEEN 2 AND 0")
166
167
if not result:
168
warnMsg = "the back-end DBMS is not %s" % DBMS.ACCESS
169
logger.warning(warnMsg)
170
return False
171
172
setDbms(DBMS.ACCESS)
173
174
if not conf.extensiveFp:
175
return True
176
177
infoMsg = "actively fingerprinting %s" % DBMS.ACCESS
178
logger.info(infoMsg)
179
180
version = self._sysTablesCheck()
181
182
if version is not None:
183
Backend.setVersion(version)
184
185
return True
186
else:
187
warnMsg = "the back-end DBMS is not %s" % DBMS.ACCESS
188
logger.warning(warnMsg)
189
190
return False
191
192
def forceDbmsEnum(self):
193
conf.db = ("%s%s" % (DBMS.ACCESS, METADB_SUFFIX)).replace(' ', '_')
194
195