Skip to content

Commit 848ba68

Browse files
committed
Couple of fixes
1 parent 77ee160 commit 848ba68

11 files changed

Lines changed: 53 additions & 11 deletions

File tree

extra/esperanto/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def noisy(cond, _b=base, _r=rng):
105105
esp.discover()
106106
got = esp.extract("(SELECT name FROM users WHERE id=1)")
107107
assert got == "Admin-42", "quorum extraction (seed %d) failed: %r" % (seed, got)
108-
print(" quorum=6 under 20%% noisy oracle (12%% err + 8%% lies) -> 'Admin-42' across 4 seeds")
108+
print(" quorum=6 under 20% noisy oracle (12% err + 8% lies) -> 'Admin-42' across 4 seeds")
109109

110110
# -- integrity guards (peer-review round 4) --------------------------------
111111
# empty/NULL are falsey; a bounded prefix (incl. limit=0) is incomplete+truncated

lib/core/option.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2198,7 +2198,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
21982198

21992199
kb.chars = AttribDict()
22002200
kb.chars.delimiter = randomStr(length=6, lowercase=True)
2201-
# NOTE: markers have to be mutually distinct (e.g. equal start/stop makes the delimited output ambiguous, while equal replacement markers make _errorReplaceChars() restore the wrong character)
2201+
# NOTE: markers have to be mutually distinct (e.g. equal start/stop makes the delimited output ambiguous, while equal replacement markers make _errorReplaceChars() restore the wrong character). Also, none of the inner letters may be the boundary character itself, as that makes a marker contain a shorter one (e.g. 'qzqxq' carrying 'qzq')
22022202
_ = set()
22032203
while len(_) < 2:
22042204
_.add(randomStr(length=3, alphabet=KB_CHARS_LOW_FREQUENCY_ALPHABET))
@@ -2207,6 +2207,7 @@ def _setKnowledgeBaseAttributes(flushAll=True):
22072207
_ = set()
22082208
while len(_) < 4:
22092209
_.add(randomStr(length=1, lowercase=True))
2210+
_.discard(KB_CHARS_BOUNDARY_CHAR)
22102211
kb.chars.at, kb.chars.space, kb.chars.dollar, kb.chars.hash_ = ("%s%s%s" % (KB_CHARS_BOUNDARY_CHAR, __, KB_CHARS_BOUNDARY_CHAR) for __ in _)
22112212

22122213
kb.checkWafMode = False

lib/core/optiondict.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
"notString": "string",
115115
"regexp": "string",
116116
"code": "integer",
117+
"lengths": "boolean",
117118
"smart": "boolean",
118119
"textOnly": "boolean",
119120
"titles": "boolean",

lib/core/settings.py

Lines changed: 4 additions & 4 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.8.44"
23+
VERSION = "1.10.8.45"
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)
@@ -612,7 +612,7 @@
612612
# Row count at/above which keyset (seek) pagination is used automatically for table dumps when a usable integer-key cursor exists (smaller tables keep the plain LIMIT/OFFSET path; '--keyset' forces it regardless of size)
613613
KEYSET_MIN_ROWS = 1000
614614

615-
# Number of consecutive Huffman (set-membership) character attempts allowed to decline/escape without a single validated success before the technique latches itself off (safety against trimmed/blocked long IN() payloads)
615+
# Number of Huffman (set-membership) character attempts made before their escape ratio is judged; at/above it, escapes reaching half of all attempts latch the technique off (safety against trimmed/blocked long IN() payloads)
616616
HUFFMAN_PROBE_LIMIT = 8
617617

618618
# Cold-start (prior) weights for the order-0 Huffman model used in adaptive blind retrieval. Gently
@@ -1776,8 +1776,8 @@
17761776
# Character used as a boundary in kb.chars (preferably less frequent letter)
17771777
KB_CHARS_BOUNDARY_CHAR = 'q'
17781778

1779-
# Letters of lower frequency used in kb.chars
1780-
KB_CHARS_LOW_FREQUENCY_ALPHABET = "zqxjkvbp"
1779+
# Letters of lower frequency used in kb.chars (NOTE: without the boundary character itself, so that no marker can contain a shorter one)
1780+
KB_CHARS_LOW_FREQUENCY_ALPHABET = "zxjkvbp"
17811781

17821782
# Printable bytes
17831783
PRINTABLE_BYTES = set(bytes(string.printable, "ascii") if six.PY3 else string.printable)

lib/techniques/blind/inference.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@
8484
from lib.utils.xrange import xrange
8585
from thirdparty import six
8686

87-
# Sentinel returned by the opt-in Huffman retrieval (--huffman) meaning "this character is
88-
# outside the ASCII model (e.g. multi-byte/Unicode) - defer to the classic bisection".
87+
# Sentinel returned by the (default-on, '--no-huffman') Huffman retrieval meaning "this character
88+
# is outside the ASCII model (e.g. multi-byte/Unicode) - defer to the classic bisection".
8989
_HUFFMAN_FALLBACK = object()
9090

9191
# Cache of character-level Markov priors keyed by (order, scale, dbms); built once per process

lib/techniques/blind/multibit.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,13 @@ def _confirm(profile, expression, value, length):
591591
# whose low byte still looks like ASCII), and that must not count against a working channel.
592592
if length is None:
593593
if _ask(profile, "%s=%d" % (queries[dbms].length.query % ("(%s)" % expression), len(value))) is not True:
594+
# a NULL value has no length, so the comparison above is NULL (i.e. not selected) no matter
595+
# what was read - exactly how a channel that drops rows fails it. One extra probe tells the
596+
# two apart, so a column with NULLs in it does not retire an otherwise working channel
597+
if _ask(profile, "(%s) IS NULL" % expression) is True:
598+
_debug("value is NULL, so its length cannot be confirmed")
599+
return None
600+
594601
_debug("length of the extracted value did not confirm")
595602
return False
596603
elif length != len(value):

lib/techniques/union/use.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ def _chunkedJsonAggUse(expression, expressionFields, expressionFieldsList, count
257257
caps. K is halved adaptively if a chunk response still gets truncated. Returns a BigArray of
258258
rows, or None to let the caller fall back to the regular per-row UNION path.
259259
260-
Same DBMS coverage as the single-shot JSON-agg (per-DBMS aggregate + windowing); others -> None.
260+
Covers the single-shot JSON-agg back-ends that also have a windowing form here (i.e. all of them
261+
except Oracle and MSSQL, whose aggregates are built differently); others -> None.
261262
"""
262263
dbms = Backend.getIdentifiedDbms()
263264

tamper/mssqlnosemicolon.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def tamper(payload, **kwargs):
2121
"""
2222
Replaces (MsSQL) statement separator ';' with a blank character
2323
24+
Requirement:
25+
* Microsoft SQL Server
26+
2427
Notes:
2528
* Useful to bypass filters/WAFs blocking the ';' character, as
2629
Transact-SQL does not require any separator between statements

tamper/uniontable.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ def tamper(payload, **kwargs):
3232
* Useful to bypass web application firewalls, as the resulting payload contains neither
3333
the SELECT nor the FROM keyword. Verified against ModSecurity v3 with the OWASP CRS
3434
(paranoia level 1, blocking mode), where the plain counterpart scores 20 anomaly
35-
points and is blocked, while the rewritten payload scores 0 and is answered with
36-
HTTP 200
35+
points and is blocked, while the rewritten payload drops to 5 (rule 942360 alone,
36+
see below) or to 0 when chained with tamper script 'odbcbrace'
3737
* The rule doing most of the work there is 942270 '(?i)union.*?select.*?from', which
3838
needs all three keywords in that order. TABLE <table> is a complete query block on
3939
its own (sql_yacc.yy query_primary has exactly three alternatives: SELECT, VALUES and

tests/test_kbchars.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ def test_markers_never_collide(self):
5858
self.assertEqual(len(set(drawn)), len(MARKERS),
5959
msg="colliding kb.chars markers on round %d: %s" % (i, dict(zip(MARKERS, drawn))))
6060

61+
def test_markers_never_contain_each_other(self):
62+
# whole-string distinctness is not enough: the boundary character wrapping every marker used
63+
# to be drawn for the inner letters as well, so a start marker could render as 'qzqxq', which
64+
# carries the perfectly legal replacement marker 'qzq' (and 'qxq') inside it
65+
for i in range(ROUNDS):
66+
_setKnowledgeBaseAttributes()
67+
drawn = [getattr(kb.chars, _) for _ in MARKERS]
68+
for one in drawn:
69+
for other in drawn:
70+
if one is not other:
71+
self.assertNotIn(other, one,
72+
msg="kb.chars marker %r contains %r on round %d" % (one, other, i))
73+
6174
def test_markers_keep_their_shape(self):
6275
# the fix must not change the on-the-wire length of a payload
6376
for _ in range(ROUNDS // 100):

0 commit comments

Comments
 (0)