Skip to content

Commit 3a680be

Browse files
committed
Minor patches
1 parent 39d22d2 commit 3a680be

11 files changed

Lines changed: 44 additions & 30 deletions

File tree

lib/core/common.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,19 +1967,21 @@ def getLimitRange(count, plusOne=False):
19671967

19681968
if kb.dumpTable:
19691969
if conf.limitStart and conf.limitStop and conf.limitStart > conf.limitStop:
1970-
limitStop = conf.limitStart
1970+
limitStop = min(conf.limitStart, count) # a '--start' beyond the table must not request out-of-range offsets (phantom rows)
19711971
limitStart = conf.limitStop
19721972
reverse = True
19731973
else:
19741974
if isinstance(conf.limitStop, int) and conf.limitStop > 0 and conf.limitStop < limitStop:
19751975
limitStop = conf.limitStop
19761976

1977-
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
1977+
# NOTE: no '<= limitStop' gate - a '--start' past the row count must yield an EMPTY range
1978+
# (correctly skipping past every row), not silently fall back to dumping the whole table
1979+
if isinstance(conf.limitStart, int) and conf.limitStart > 0:
19781980
limitStart = conf.limitStart
19791981

19801982
retVal = xrange(limitStart, limitStop + 1) if plusOne else xrange(limitStart - 1, limitStop)
19811983

1982-
if reverse:
1984+
if reverse and len(retVal): # len() guard: a clamped out-of-range '--start' can leave the range empty
19831985
retVal = xrange(retVal[-1], retVal[0] - 1, -1)
19841986

19851987
return retVal

lib/core/convert.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ def getUnicode(value, encoding=None, noneToNull=False):
577577

578578
try:
579579
return six.text_type(value, encoding or (kb.get("pageEncoding") if kb.get("originalPage") else None) or UNICODE_ENCODING)
580-
except UnicodeDecodeError:
580+
except (UnicodeDecodeError, LookupError): # LookupError: an unknown/invalid encoding name must fall back, not crash
581581
return six.text_type(value, UNICODE_ENCODING, errors="reversible")
582582
elif isListLike(value):
583583
value = list(getUnicode(_, encoding, noneToNull) for _ in value)

lib/core/option.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ def _setOpenApiTargets():
520520
checkFile(conf.openApiFile)
521521
infoMsg = "parsing OpenAPI/Swagger specification from '%s'" % conf.openApiFile
522522
logger.info(infoMsg)
523-
content = openFile(conf.openApiFile).read()
523+
with openFile(conf.openApiFile) as f:
524+
content = f.read()
524525

525526
tags = [_.strip() for _ in re.split(PARAMETER_SPLITTING_REGEX, conf.openApiTags) if _.strip()] if conf.openApiTags else None
526527
if tags:
@@ -835,7 +836,8 @@ def _listTamperingFunctions():
835836
logger.info(infoMsg)
836837

837838
for script in sorted(glob.glob(os.path.join(paths.SQLMAP_TAMPER_PATH, "*.py"))):
838-
content = openFile(script, 'r').read()
839+
with openFile(script, 'r') as f:
840+
content = f.read()
839841
match = re.search(r'(?s)__priority__.+"""(.+)"""', content)
840842
if match:
841843
comment = match.group(1).strip()

lib/core/settings.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.7.242"
23+
VERSION = "1.10.7.243"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
@@ -533,8 +533,11 @@
533533
r'"(?:errmsg|errorMessage|reason|msg)"\s*:\s*"(?P<result>[^"]+)"' # generic JSON error-message field (NoSQL document/REST back-ends)
534534
)
535535

536-
# Regular expression used for parsing charset info from meta html headers
537-
META_CHARSET_REGEX = r"""(?si)<head\b[^>]*>.*<meta[^>]+charset\s*=\s*["']?(?P<result>[^"'> ]+).*</head>"""
536+
# Regular expression used for parsing charset info from meta html headers (Note: the tempered token
537+
# '(?:(?!</head>).)*?' keeps the meta strictly INSIDE <head> - as the old trailing '.*</head>' did -
538+
# while the bounded meta-attr scan '{0,300}?' keeps it LINEAR; the old greedy form went quadratic and
539+
# hung for many minutes on an attacker-controlled body full of '<meta' tokens lacking '>'/'</head>')
540+
META_CHARSET_REGEX = r"""(?si)<head\b[^>]*>(?:(?!</head>).)*?<meta[^>]{0,300}?charset\s*=\s*["']?(?P<result>[^"'> ]+)"""
538541

539542
# Regular expression used for parsing refresh info from meta html headers
540543
META_REFRESH_REGEX = r'(?i)<meta http-equiv="?refresh"?[^>]+content="?[^">]+;\s*(url=)?["\']?(?P<result>[^\'">]+)'

lib/request/comparison.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def comparison(page, headers, code=None, getRatioValue=False, pageLength=None):
6767
return _
6868

6969
def _adjust(condition, getRatioValue):
70-
if not any((conf.string, conf.notString, conf.regexp, conf.code)):
70+
if not any((conf.string, conf.notString, conf.regexp, conf.code, conf.lengths)):
7171
# Negative logic approach is used in raw page comparison scheme as that what is "different" than original
7272
# PAYLOAD.WHERE.NEGATIVE response is considered as True; in switch based approach negative logic is not
7373
# applied as that what is by user considered as True is that what is returned by the comparison mechanism

lib/request/connect.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ def getPage(**kwargs):
406406
errMsg = "problem occurred while loading cookies from file '%s'" % conf.liveCookies
407407
raise SqlmapValueException(errMsg)
408408

409-
cookie = openFile(conf.liveCookies).read().strip()
409+
with openFile(conf.liveCookies) as f:
410+
cookie = f.read().strip()
410411
cookie = re.sub(r"(?i)\ACookie:\s*", "", cookie)
411412

412413
if multipart:
@@ -545,7 +546,8 @@ def getPage(**kwargs):
545546
headers = forgeHeaders(auxHeaders, headers)
546547

547548
if kb.headersFile:
548-
content = openFile(kb.headersFile, 'r').read()
549+
with openFile(kb.headersFile, 'r') as f:
550+
content = f.read()
549551
for line in content.split("\n"):
550552
line = getText(line.strip())
551553
if ':' in line:

lib/utils/api.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,8 @@ def download(taskid, target, filename):
875875

876876
if os.path.isfile(path):
877877
logger.debug("(%s) Retrieved content of file %s" % (taskid, target))
878-
content = openFile(path, "rb").read()
878+
with openFile(path, "rb") as f:
879+
content = f.read()
879880
return jsonize({"success": True, "file": encodeBase64(content, binary=False)})
880881
else:
881882
logger.warning("[%s] File does not exist %s" % (taskid, target))

lib/utils/hash.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ def _bruteProcessVariantA(attack_info, hash_regex, suffix, retVal, proc_id, proc
11171117
word = word + suffix
11181118

11191119
try:
1120-
current = __functions__[hash_regex](password=word, uppercase=False)
1120+
current = __functions__[hash_regex](password=getBytes(word, unsafe=False), uppercase=False)
11211121

11221122
if current in hashes:
11231123
for item in attack_info[:]:
@@ -1195,7 +1195,7 @@ def _bruteProcessVariantB(user, hash_, kwargs, hash_regex, suffix, retVal, found
11951195
word = word + suffix
11961196

11971197
try:
1198-
current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
1198+
current = __functions__[hash_regex](password=getBytes(word, unsafe=False), uppercase=False, **kwargs)
11991199

12001200
if hash_ == current:
12011201
if hash_regex == HASH.ORACLE_OLD: # only for cosmetic purposes
@@ -1285,7 +1285,7 @@ def _bruteProcessVariantSalted(attack_info, hash_regex, suffix, retVal, proc_id,
12851285
((user, hash_), kwargs) = item
12861286

12871287
try:
1288-
current = __functions__[hash_regex](password=word, uppercase=False, **kwargs)
1288+
current = __functions__[hash_regex](password=getBytes(word, unsafe=False), uppercase=False, **kwargs)
12891289

12901290
if hash_ == current:
12911291
retVal.put((user, hash_, word))

plugins/generic/entries.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ def _dumpCountQuery():
333333
kb.data.dumpedTable[column] = {"length": len(column), "values": BigArray()}
334334

335335
for entry in entries:
336-
if entry is None or len(entry) == 0:
336+
# skip a missing/empty ROW container, but NOT an empty-string CELL value
337+
# (single-column dumps yield bare strings; len("")==0 must not drop the row)
338+
if entry is None or (isListLike(entry) and len(entry) == 0):
337339
continue
338340

339341
if isinstance(entry, six.string_types):

plugins/generic/search.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,9 @@ def searchDb(self):
135135
query = agent.limitQuery(index, query, dbCond)
136136

137137
value = unArrayizeValue(inject.getValue(query, union=False, error=False))
138-
value = safeSQLIdentificatorNaming(value)
139-
foundDbs.append(value)
138+
if not isNoneValue(value): # guard (mirrors searchTable) so a failed retrieval can't push a None/garbage name
139+
value = safeSQLIdentificatorNaming(value)
140+
foundDbs.append(value)
140141

141142
conf.dumper.lister("found databases", foundDbs)
142143

0 commit comments

Comments
 (0)