mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-08-27 04:05:58 +00:00
Minor update
This commit is contained in:
parent
2afa92451a
commit
023d85fba8
2 changed files with 27 additions and 15 deletions
|
|
@ -20,7 +20,7 @@ from lib.core.enums import OS
|
||||||
from thirdparty import six
|
from thirdparty import six
|
||||||
|
|
||||||
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
|
||||||
VERSION = "1.10.7.239"
|
VERSION = "1.10.7.240"
|
||||||
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
|
||||||
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
|
||||||
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,19 @@ See the file 'LICENSE' for copying permission
|
||||||
|
|
||||||
Adversarial JITTER stress harness for time-based blind extraction.
|
Adversarial JITTER stress harness for time-based blind extraction.
|
||||||
|
|
||||||
Drives the REAL bisection() + REAL wasLastResponseDelayed() against a mock oracle that returns a
|
Drives the REAL bisection() + REAL wasLastResponseDelayed() + REAL validateChar() re-validation
|
||||||
simulated RESPONSE DURATION (base + jitter + timeSec-if-condition-true) instead of a boolean - so
|
against a mock oracle that returns a simulated RESPONSE DURATION (base + jitter + timeSec-if-condition-
|
||||||
the actual statistical delay-decision and its re-validation run under controlled network jitter,
|
true) instead of a boolean - so the whole time-based decision stack runs under controlled network
|
||||||
with NO real sleeping (thousands of extractions per second, fully deterministic per seed).
|
jitter, with NO real sleeping (thousands of extractions per second, fully deterministic per seed).
|
||||||
|
The delimiter-wrapped template is what lets validateChar's per-char '!=' re-check actually fire (it is
|
||||||
|
sqlmap's main defense against a single spike faking one bit); without it the harness is far too harsh.
|
||||||
|
|
||||||
Two tiers:
|
Two tiers:
|
||||||
* TestJitterRegression - ALWAYS runs. Low/mild jitter MUST extract perfectly. A real regression
|
* TestJitterRegression - ALWAYS runs. Low/mild jitter MUST extract perfectly, and a spike in the
|
||||||
guard for the time-based decision stack (deterministic, fast, non-flaky).
|
baseline model MUST NOT hide genuine delays. Deterministic, fast, non-flaky.
|
||||||
* TestJitterStressSweep - OPT-IN (set env SQLMAP_JITTER_STRESS=1). The adversarial sweeps that map
|
* TestJitterStressSweep - OPT-IN (set env SQLMAP_JITTER_STRESS=1). Adversarial sweeps (Gaussian
|
||||||
the failure surface (Gaussian sigma, heavy-tailed spikes). Informational
|
sigma, heavy-tailed spikes) mapping where extraction finally degrades.
|
||||||
+ loose bounds only; kept out of normal CI to avoid slowness/flakiness.
|
Informational + loose bounds only; kept out of normal CI (slow/noisy).
|
||||||
|
|
||||||
Run the sweep on demand: SQLMAP_JITTER_STRESS=1 python -m unittest tests.test_jitter_stress -v
|
Run the sweep on demand: SQLMAP_JITTER_STRESS=1 python -m unittest tests.test_jitter_stress -v
|
||||||
"""
|
"""
|
||||||
|
|
@ -35,11 +37,15 @@ from lib.core.data import conf, kb
|
||||||
from lib.core.common import getCurrentThreadData, setTechnique
|
from lib.core.common import getCurrentThreadData, setTechnique
|
||||||
from lib.core.datatype import AttribDict
|
from lib.core.datatype import AttribDict
|
||||||
from lib.core.enums import ADJUST_TIME_DELAY, PAYLOAD
|
from lib.core.enums import ADJUST_TIME_DELAY, PAYLOAD
|
||||||
|
from lib.core.settings import PAYLOAD_DELIMITER
|
||||||
from lib.request.connect import Connect
|
from lib.request.connect import Connect
|
||||||
import lib.techniques.blind.inference as inf
|
import lib.techniques.blind.inference as inf
|
||||||
|
|
||||||
_TEMPLATE = "EXPR=%s IDX=%d CMP>%d"
|
# The comparison must sit BETWEEN PAYLOAD_DELIMITERs: validateChar (inference.py) rewrites '>' to '!='
|
||||||
_PARSE = re.compile(r"IDX=(\d+) CMP(.)(\d+)")
|
# with a regex anchored on the delimiters, and without them that per-char re-validation silently
|
||||||
|
# no-ops (defeating sqlmap's main per-request-spike defense and making this harness far too pessimistic).
|
||||||
|
_TEMPLATE = "%sEXPR=%%s IDX=%%d CMP>%%d%s" % (PAYLOAD_DELIMITER, PAYLOAD_DELIMITER)
|
||||||
|
_PARSE = re.compile(r"IDX=(\d+) CMP(!=|=|>)(\d+)") # bisection '>'/'=' plus validateChar's '!='
|
||||||
_TIMESEC = 5.0
|
_TIMESEC = 5.0
|
||||||
_BASE = 0.10 # base (non-delay) round-trip latency, seconds
|
_BASE = 0.10 # base (non-delay) round-trip latency, seconds
|
||||||
_STRESS = os.environ.get("SQLMAP_JITTER_STRESS")
|
_STRESS = os.environ.get("SQLMAP_JITTER_STRESS")
|
||||||
|
|
@ -107,7 +113,7 @@ class _JitterBase(unittest.TestCase):
|
||||||
return False
|
return False
|
||||||
idx, op, thr = int(m.group(1)), m.group(2), int(m.group(3))
|
idx, op, thr = int(m.group(1)), m.group(2), int(m.group(3))
|
||||||
ch = ord(secret[idx - 1]) if 0 <= idx - 1 < len(secret) else 0
|
ch = ord(secret[idx - 1]) if 0 <= idx - 1 < len(secret) else 0
|
||||||
cond = (ch > thr) if op == ">" else (ch == thr)
|
cond = (ch > thr) if op == ">" else (ch != thr) if op == "!=" else (ch == thr)
|
||||||
if "NOT(" in payload:
|
if "NOT(" in payload:
|
||||||
cond = not cond
|
cond = not cond
|
||||||
td.lastQueryDuration = _BASE + abs(jitter(rng)) + (_TIMESEC if cond else 0.0)
|
td.lastQueryDuration = _BASE + abs(jitter(rng)) + (_TIMESEC if cond else 0.0)
|
||||||
|
|
@ -183,11 +189,14 @@ class TestJitterRegression(_JitterBase):
|
||||||
@unittest.skipUnless(_STRESS, "adversarial jitter sweep is opt-in (set SQLMAP_JITTER_STRESS=1)")
|
@unittest.skipUnless(_STRESS, "adversarial jitter sweep is opt-in (set SQLMAP_JITTER_STRESS=1)")
|
||||||
class TestJitterStressSweep(_JitterBase):
|
class TestJitterStressSweep(_JitterBase):
|
||||||
"""Opt-in failure-surface map. Prints correctness vs jitter and asserts only loose, non-flaky
|
"""Opt-in failure-surface map. Prints correctness vs jitter and asserts only loose, non-flaky
|
||||||
invariants (clean case perfect, degradation is monotone-ish). Use to evaluate hardening changes."""
|
invariants (clean case perfect). Use to evaluate hardening changes."""
|
||||||
|
|
||||||
SECRET = "Str0ng!"
|
SECRET = "Str0ng!"
|
||||||
|
|
||||||
def test_gaussian_sweep(self):
|
def test_gaussian_sweep(self):
|
||||||
|
# Continuous jitter: degrades only once sigma approaches timeSec/7 (7*stdev threshold nears the
|
||||||
|
# real delay). That is the FUNDAMENTAL limit of the statistic - the answer there is a larger
|
||||||
|
# timeSec (--time-sec), not a code change; shown here so a regression that degrades it earlier is visible.
|
||||||
print("\n[jitter] Gaussian sigma sweep (timeSec=%.0f, base=%.2f):" % (_TIMESEC, _BASE))
|
print("\n[jitter] Gaussian sigma sweep (timeSec=%.0f, base=%.2f):" % (_TIMESEC, _BASE))
|
||||||
for sigma in (0.0, 0.3, 0.5, 0.7, 0.9, 1.2):
|
for sigma in (0.0, 0.3, 0.5, 0.7, 0.9, 1.2):
|
||||||
ok, n = self._rate(self.SECRET, _gaussian(sigma))
|
ok, n = self._rate(self.SECRET, _gaussian(sigma))
|
||||||
|
|
@ -196,8 +205,11 @@ class TestJitterStressSweep(_JitterBase):
|
||||||
self.assertEqual(ok, n)
|
self.assertEqual(ok, n)
|
||||||
|
|
||||||
def test_heavy_tailed_spike_sweep(self):
|
def test_heavy_tailed_spike_sweep(self):
|
||||||
|
# One-off +8s spikes: baseline-trim (stripTimeOutliers) keeps the model clean and validateChar's
|
||||||
|
# '!=' re-check catches a spike that fakes a single bit, so extraction stays ~perfect until an
|
||||||
|
# absurd spike rate (a fifth of all requests). This is the payoff of both defenses together.
|
||||||
print("\n[jitter] Heavy-tailed spike sweep (base sigma=0.2, spike=+8s):")
|
print("\n[jitter] Heavy-tailed spike sweep (base sigma=0.2, spike=+8s):")
|
||||||
for p in (0.0, 0.01, 0.03, 0.05, 0.10):
|
for p in (0.0, 0.01, 0.03, 0.05, 0.10, 0.20):
|
||||||
ok, n = self._rate(self.SECRET, _spike(0.2, p, 8.0))
|
ok, n = self._rate(self.SECRET, _spike(0.2, p, 8.0))
|
||||||
print(" spike_p=%.2f -> %d/%d (%3.0f%%)" % (p, ok, n, 100.0 * ok / n))
|
print(" spike_p=%.2f -> %d/%d (%3.0f%%)" % (p, ok, n, 100.0 * ok / n))
|
||||||
if p == 0.0:
|
if p == 0.0:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue