Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cb43c03

Browse files
committed
Definite patch for MemoryError(s) (fixes #1991)
1 parent 65a0f15 commit cb43c03

4 files changed

Lines changed: 42 additions & 50 deletions

File tree

lib/controller/checks.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
from lib.core.settings import IDS_WAF_CHECK_PAYLOAD
7373
from lib.core.settings import IDS_WAF_CHECK_RATIO
7474
from lib.core.settings import IDS_WAF_CHECK_TIMEOUT
75+
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
7576
from lib.core.settings import NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH
7677
from lib.core.settings import SUHOSIN_MAX_VALUE_LENGTH
7778
from lib.core.settings import SUPPORTED_DBMS
@@ -1058,12 +1059,22 @@ def checkDynamicContent(firstPage, secondPage):
10581059
logger.critical(warnMsg)
10591060
return
10601061

1061-
seqMatcher = getCurrentThreadData().seqMatcher
1062-
seqMatcher.set_seq1(firstPage)
1063-
seqMatcher.set_seq2(secondPage)
1062+
if firstPage and secondPage and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (firstPage, secondPage)):
1063+
ratio = None
1064+
else:
1065+
try:
1066+
seqMatcher = getCurrentThreadData().seqMatcher
1067+
seqMatcher.set_seq1(firstPage)
1068+
seqMatcher.set_seq2(secondPage)
1069+
ratio = seqMatcher.quick_ratio()
1070+
except MemoryError:
1071+
ratio = None
1072+
1073+
if ratio is None:
1074+
kb.skipSeqMatcher = True
10641075

10651076
# In case of an intolerable difference turn on dynamicity removal engine
1066-
if seqMatcher.quick_ratio() <= UPPER_RATIO_BOUND:
1077+
elif ratio <= UPPER_RATIO_BOUND:
10671078
findDynamicContent(firstPage, secondPage)
10681079

10691080
count = 0

lib/core/option.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,6 +1944,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
19441944
kb.safeCharEncode = False
19451945
kb.safeReq = AttribDict()
19461946
kb.singleLogFlags = set()
1947+
kb.skipSeqMatcher = False
19471948
kb.reduceTests = None
19481949
kb.tlsSNI = {}
19491950
kb.stickyDBMS = False

lib/core/settings.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from lib.core.revision import getRevisionNumber
2020

2121
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
22-
VERSION = "1.0.6.65"
22+
VERSION = "1.0.6.66"
2323
REVISION = getRevisionNumber()
2424
STABLE = VERSION.count('.') <= 2
2525
VERSION_STRING = "sqlmap/%s#%s" % (VERSION, "stable" if STABLE else "dev")
@@ -581,6 +581,9 @@
581581
# Maximum response total page size (trimmed if larger)
582582
MAX_CONNECTION_TOTAL_SIZE = 100 * 1024 * 1024
583583

584+
# For preventing MemoryError exceptions (caused when using large sequences in difflib.SequenceMatcher)
585+
MAX_DIFFLIB_SEQUENCE_LENGTH = 10 * 1024 * 1024
586+
584587
# Maximum (multi-threaded) length of entry in bisection algorithm
585588
MAX_BISECTION_LENGTH = 50 * 1024 * 1024
586589

lib/request/comparison.py

Lines changed: 22 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from lib.core.settings import DIFF_TOLERANCE
2222
from lib.core.settings import HTML_TITLE_REGEX
2323
from lib.core.settings import MIN_RATIO
24+
from lib.core.settings import MAX_DIFFLIB_SEQUENCE_LENGTH
2425
from lib.core.settings import MAX_RATIO
2526
from lib.core.settings import REFLECTED_VALUE_MARKER
2627
from lib.core.settings import LOWER_RATIO_BOUND
@@ -54,8 +55,6 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
5455
if page is None and pageLength is None:
5556
return None
5657

57-
count = 0
58-
5958
seqMatcher = threadData.seqMatcher
6059
seqMatcher.set_seq1(kb.pageTemplate)
6160

@@ -110,59 +109,37 @@ def _comparison(page, headers, code, getRatioValue, pageLength):
110109
elif isinstance(seqMatcher.a, unicode) and isinstance(page, str):
111110
seqMatcher.a = seqMatcher.a.encode(kb.pageEncoding or DEFAULT_PAGE_ENCODING, 'ignore')
112111

113-
seq1, seq2 = None, None
114-
115-
if conf.titles:
116-
seq1 = extractRegexResult(HTML_TITLE_REGEX, seqMatcher.a)
117-
seq2 = extractRegexResult(HTML_TITLE_REGEX, page)
112+
if seqMatcher.a and page and seqMatcher.a == page:
113+
ratio = 1
114+
elif kb.skipSeqMatcher or seqMatcher.a and page and any(len(_) > MAX_DIFFLIB_SEQUENCE_LENGTH for _ in (seqMatcher.a, page)):
115+
ratio = 1.0 * len(seqMatcher.a) / len(page)
116+
if ratio > 1:
117+
ratio = 1. / ratio
118118
else:
119-
seq1 = getFilteredPageContent(seqMatcher.a, True) if conf.textOnly else seqMatcher.a
120-
seq2 = getFilteredPageContent(page, True) if conf.textOnly else page
119+
seq1, seq2 = None, None
121120

122-
if seq1 is None or seq2 is None:
123-
return None
121+
if conf.titles:
122+
seq1 = extractRegexResult(HTML_TITLE_REGEX, seqMatcher.a)
123+
seq2 = extractRegexResult(HTML_TITLE_REGEX, page)
124+
else:
125+
seq1 = getFilteredPageContent(seqMatcher.a, True) if conf.textOnly else seqMatcher.a
126+
seq2 = getFilteredPageContent(page, True) if conf.textOnly else page
124127

125-
seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
126-
seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
128+
if seq1 is None or seq2 is None:
129+
return None
127130

128-
while count < min(len(seq1), len(seq2)):
129-
if seq1[count] == seq2[count]:
130-
count += 1
131-
else:
132-
break
133-
134-
if count:
135-
try:
136-
_seq1 = seq1[count:]
137-
_seq2 = seq2[count:]
138-
except MemoryError:
139-
pass
140-
else:
141-
seq1 = _seq1
142-
seq2 = _seq2
143-
144-
while True:
145-
try:
146-
seqMatcher.set_seq1(seq1)
147-
except MemoryError:
148-
seq1 = seq1[:len(seq1) / 1024]
149-
else:
150-
break
131+
seq1 = seq1.replace(REFLECTED_VALUE_MARKER, "")
132+
seq2 = seq2.replace(REFLECTED_VALUE_MARKER, "")
151133

152-
while True:
153-
try:
154-
seqMatcher.set_seq2(seq2)
155-
except MemoryError:
156-
seq2 = seq2[:len(seq2) / 1024]
157-
else:
158-
break
134+
seqMatcher.set_seq1(seq1)
135+
seqMatcher.set_seq2(seq2)
159136

160-
ratio = round(seqMatcher.quick_ratio(), 3)
137+
ratio = round(seqMatcher.quick_ratio(), 3)
161138

162139
# If the url is stable and we did not set yet the match ratio and the
163140
# current injected value changes the url page content
164141
if kb.matchRatio is None:
165-
if (count or ratio >= LOWER_RATIO_BOUND) and ratio <= UPPER_RATIO_BOUND:
142+
if ratio >= LOWER_RATIO_BOUND and ratio <= UPPER_RATIO_BOUND:
166143
kb.matchRatio = ratio
167144
logger.debug("setting match ratio for current parameter to %.3f" % kb.matchRatio)
168145

0 commit comments

Comments
 (0)