@contrast/protect 1.3.0 → 1.4.0
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/lib/error-handlers/install/express4.js +2 -3
- package/lib/error-handlers/install/fastify3.js +2 -4
- package/lib/error-handlers/install/koa2.js +1 -2
- package/lib/{cli-rewriter.js → get-source-context.js} +13 -15
- package/lib/hardening/constants.js +20 -0
- package/lib/hardening/handlers.js +65 -0
- package/lib/hardening/index.js +29 -0
- package/lib/hardening/install/node-serialize0.js +59 -0
- package/lib/index.d.ts +3 -21
- package/lib/index.js +4 -0
- package/lib/input-analysis/handlers.js +169 -7
- package/lib/input-analysis/index.js +4 -0
- package/lib/input-analysis/install/body-parser1.js +13 -21
- package/lib/input-analysis/install/cookie-parser1.js +13 -15
- package/lib/input-analysis/install/express4.js +8 -13
- package/lib/input-analysis/install/fastify3.js +4 -5
- package/lib/input-analysis/install/formidable1.js +4 -5
- package/lib/input-analysis/install/http.js +12 -3
- package/lib/input-analysis/install/koa-body5.js +5 -10
- package/lib/input-analysis/install/koa-bodyparser4.js +6 -10
- package/lib/input-analysis/install/koa2.js +13 -24
- package/lib/input-analysis/install/multer1.js +5 -6
- package/lib/input-analysis/install/qs6.js +7 -11
- package/lib/input-analysis/install/universal-cookie4.js +3 -7
- package/lib/input-analysis/ip-analysis.js +76 -0
- package/lib/input-analysis/virtual-patches.js +109 -0
- package/lib/input-tracing/handlers/index.js +86 -22
- package/lib/input-tracing/index.js +10 -4
- package/lib/input-tracing/install/child-process.js +13 -7
- package/lib/input-tracing/install/eval.js +60 -0
- package/lib/input-tracing/install/fs.js +4 -2
- package/lib/input-tracing/install/http.js +63 -0
- package/lib/input-tracing/install/mongodb.js +20 -20
- package/lib/input-tracing/install/mysql.js +3 -2
- package/lib/input-tracing/install/postgres.js +5 -4
- package/lib/input-tracing/install/sequelize.js +7 -5
- package/lib/input-tracing/install/sqlite3.js +6 -4
- package/lib/input-tracing/install/vm.js +132 -0
- package/lib/make-source-context.js +4 -1
- package/lib/semantic-analysis/handlers.js +160 -0
- package/lib/semantic-analysis/index.js +38 -0
- package/package.json +7 -9
- package/lib/utils.js +0 -84
|
@@ -16,30 +16,17 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const util = require('util');
|
|
19
|
-
const { simpleTraverse } = require('
|
|
19
|
+
const { BLOCKING_MODES, isString, simpleTraverse } = require('@contrast/common');
|
|
20
20
|
|
|
21
21
|
module.exports = function(core) {
|
|
22
22
|
const { protect: { agentLib, inputTracing, throwSecurityException } } = core;
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Util for pulling results from context for the particular rule id
|
|
26
|
-
* @param {string} ruleId rule id
|
|
27
|
-
* @param {object} context async storage data for protect
|
|
28
|
-
* @returns {AnalysisResult[]}
|
|
29
|
-
*/
|
|
30
|
-
function getResultsByRuleId(ruleId, context) {
|
|
31
|
-
if (context.rules.agentLibRules[ruleId].mode === 'off') {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
return context.findings.resultsMap[ruleId];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
24
|
function handleFindings(sourceContext, sinkContext, ruleId, result, findings) {
|
|
38
25
|
result.details.push({ sinkContext, findings });
|
|
39
26
|
|
|
40
27
|
const { mode } = sourceContext.rules.agentLibRules[ruleId];
|
|
41
28
|
|
|
42
|
-
if (
|
|
29
|
+
if (BLOCKING_MODES.includes(mode)) {
|
|
43
30
|
result.blocked = true;
|
|
44
31
|
const blockInfo = [mode, ruleId];
|
|
45
32
|
sourceContext.findings.securityException = blockInfo;
|
|
@@ -153,13 +140,87 @@ module.exports = function(core) {
|
|
|
153
140
|
};
|
|
154
141
|
|
|
155
142
|
inputTracing.ssjsInjection = function(sourceContext, sinkContext) {
|
|
156
|
-
|
|
157
|
-
|
|
143
|
+
const ruleId = 'ssjs-injection';
|
|
144
|
+
let sinkValuesArr = [];
|
|
145
|
+
|
|
146
|
+
const results = getResultsByRuleId(ruleId, sourceContext);
|
|
147
|
+
|
|
148
|
+
if (!results) return;
|
|
149
|
+
|
|
150
|
+
if (isString(sinkContext.value)) {
|
|
151
|
+
sinkValuesArr.push(sinkContext.value);
|
|
152
|
+
} else {
|
|
153
|
+
const strValues = Object.values(sinkContext.value).filter((v) => isString(v) && v.length);
|
|
154
|
+
sinkValuesArr = [...strValues];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (const result of results) {
|
|
158
|
+
let findings = null;
|
|
159
|
+
|
|
160
|
+
for (const v of sinkValuesArr) {
|
|
161
|
+
if (findings) break;
|
|
162
|
+
|
|
163
|
+
const inputIndex = v.indexOf(result.value);
|
|
164
|
+
|
|
165
|
+
if (inputIndex === 0 && v === result.value) {
|
|
166
|
+
findings = {
|
|
167
|
+
startIndex: 0,
|
|
168
|
+
endIndex: result?.value.length - 1,
|
|
169
|
+
boundaryIndex: 0,
|
|
170
|
+
codeString: result.value
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (inputIndex > 0) {
|
|
175
|
+
const endIndex = inputIndex + result?.value.length;
|
|
176
|
+
findings = agentLib.checkSsjsInjectionSink(v, inputIndex, endIndex) && {
|
|
177
|
+
startIndex: inputIndex,
|
|
178
|
+
endIndex,
|
|
179
|
+
boundaryIndex: inputIndex,
|
|
180
|
+
codeString: result.value
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (findings) {
|
|
186
|
+
handleFindings(sourceContext, sinkContext, ruleId, result, findings);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
158
189
|
};
|
|
159
190
|
|
|
191
|
+
inputTracing.handleReflectedXss = function(sourceContext, sinkContext) {
|
|
192
|
+
const ruleId = 'reflected-xss';
|
|
193
|
+
const results = getResultsByRuleId(ruleId, sourceContext);
|
|
194
|
+
|
|
195
|
+
if (!results) return;
|
|
196
|
+
|
|
197
|
+
for (const result of results) {
|
|
198
|
+
const idx = sinkContext.value.indexOf(result.value);
|
|
199
|
+
const findings = idx !== -1 ? { value: sinkContext.value } : null;
|
|
200
|
+
|
|
201
|
+
if (findings) {
|
|
202
|
+
result.details.push({ sinkContext, findings });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
|
|
160
208
|
return inputTracing;
|
|
161
209
|
};
|
|
162
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Util for pulling results from context for the particular rule id
|
|
213
|
+
* @param {string} ruleId rule id
|
|
214
|
+
* @param {object} context async storage data for protect
|
|
215
|
+
* @returns {AnalysisResult[]}
|
|
216
|
+
*/
|
|
217
|
+
function getResultsByRuleId(ruleId, context) {
|
|
218
|
+
if (context.rules.agentLibRules[ruleId].mode === 'off') {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
return context.findings.resultsMap[ruleId];
|
|
222
|
+
}
|
|
223
|
+
|
|
163
224
|
function handleObjectValue(result, object) {
|
|
164
225
|
if (typeof object !== 'object') {
|
|
165
226
|
return null;
|
|
@@ -179,7 +240,10 @@ function handleObjectValue(result, object) {
|
|
|
179
240
|
obj = obj[value];
|
|
180
241
|
// does the found object in the query equal the saved object?
|
|
181
242
|
if (util.isDeepStrictEqual(obj, result.mongoContext.inputToCheck)) {
|
|
182
|
-
|
|
243
|
+
const start = JSON.stringify(object).indexOf(value);
|
|
244
|
+
const end = start + value.length;
|
|
245
|
+
const inputBoundaryIndex = 0;
|
|
246
|
+
findings = { start, end, boundaryOverrunIndex: start, inputBoundaryIndex };
|
|
183
247
|
}
|
|
184
248
|
}
|
|
185
249
|
});
|
|
@@ -201,10 +265,10 @@ function handleStringValue(result, string) {
|
|
|
201
265
|
|
|
202
266
|
if (inputIndex === 0 && string === result.value) {
|
|
203
267
|
findings = {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
268
|
+
start: 0,
|
|
269
|
+
end: result.value.length - 1,
|
|
270
|
+
boundaryOverrunIndex: 0,
|
|
271
|
+
inputBoundaryIndex: 0,
|
|
208
272
|
};
|
|
209
273
|
}
|
|
210
274
|
|
|
@@ -30,18 +30,24 @@ module.exports = function(core) {
|
|
|
30
30
|
require('./handlers')(core);
|
|
31
31
|
|
|
32
32
|
// load the instrumentation installers
|
|
33
|
-
require('./install/fs')(core);
|
|
34
33
|
require('./install/child-process')(core);
|
|
34
|
+
require('./install/fs')(core);
|
|
35
|
+
require('./install/mongodb')(core);
|
|
35
36
|
require('./install/mysql')(core);
|
|
36
37
|
require('./install/postgres')(core);
|
|
37
|
-
require('./install/
|
|
38
|
+
require('./install/sequelize')(core);
|
|
39
|
+
require('./install/sqlite3')(core);
|
|
40
|
+
require('./install/http')(core);
|
|
38
41
|
|
|
39
42
|
inputTracing.install = function() {
|
|
40
|
-
inputTracing.fsInstrumentation.install();
|
|
41
43
|
inputTracing.cpInstrumentation.install();
|
|
44
|
+
inputTracing.fsInstrumentation.install();
|
|
45
|
+
inputTracing.mongodbInstrumentation.install();
|
|
42
46
|
inputTracing.mysqlInstrumentation.install();
|
|
43
47
|
inputTracing.postgresInstrumentation.install();
|
|
44
|
-
inputTracing.
|
|
48
|
+
inputTracing.sequelizeInstrumentation.install();
|
|
49
|
+
inputTracing.sqlite3Instrumentation.install();
|
|
50
|
+
inputTracing.httpInstrumentation.install();
|
|
45
51
|
// TODO: NODE-2360 (2260?)
|
|
46
52
|
};
|
|
47
53
|
|
|
@@ -20,10 +20,11 @@ const { patchType } = require('../constants');
|
|
|
20
20
|
|
|
21
21
|
module.exports = function(core) {
|
|
22
22
|
const {
|
|
23
|
-
scopes: {
|
|
23
|
+
scopes: { instrumentation },
|
|
24
24
|
patcher,
|
|
25
25
|
depHooks,
|
|
26
26
|
captureStacktrace,
|
|
27
|
+
protect,
|
|
27
28
|
protect: { inputTracing }
|
|
28
29
|
} = core;
|
|
29
30
|
|
|
@@ -34,20 +35,25 @@ module.exports = function(core) {
|
|
|
34
35
|
patcher.patch(cp, method, {
|
|
35
36
|
name,
|
|
36
37
|
patchType,
|
|
37
|
-
pre(
|
|
38
|
+
pre({ args, hooked, orig }) {
|
|
38
39
|
if (instrumentation.isLocked()) return;
|
|
39
40
|
|
|
40
|
-
const sourceContext =
|
|
41
|
-
|
|
41
|
+
const sourceContext = protect.getSourceContext('child_process');
|
|
42
|
+
const value = args[0];
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
if (!value || !isString(value)) return;
|
|
44
|
+
if (!sourceContext || !value || !isString(value)) return;
|
|
45
45
|
|
|
46
46
|
const sinkContext = captureStacktrace(
|
|
47
47
|
{ name, value },
|
|
48
|
-
{ constructorOpt:
|
|
48
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
49
49
|
);
|
|
50
|
+
|
|
50
51
|
inputTracing.handleCommandInjection(sourceContext, sinkContext);
|
|
52
|
+
// To evade code duplication we are using these INPUT TRACING instrumentation
|
|
53
|
+
// to do the checks for SEMANTIC ANALYSIS too
|
|
54
|
+
core.protect.semanticAnalysis.handleCommandInjectionCommandBackdoors(sourceContext, sinkContext);
|
|
55
|
+
core.protect.semanticAnalysis.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContext);
|
|
56
|
+
core.protect.semanticAnalysis.handleCmdInjectionSemanticDangerous(sourceContext, sinkContext);
|
|
51
57
|
}
|
|
52
58
|
});
|
|
53
59
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright: 2022 Contrast Security, Inc
|
|
3
|
+
* Contact: support@contrastsecurity.com
|
|
4
|
+
* License: Commercial
|
|
5
|
+
|
|
6
|
+
* NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
* used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
* made available through public repositories, use of this Software is subject to
|
|
9
|
+
* the applicable End User Licensing Agreement found at
|
|
10
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
* between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
* way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const { isString } = require('@contrast/common');
|
|
19
|
+
const { patchType } = require('../constants');
|
|
20
|
+
|
|
21
|
+
module.exports = function(core) {
|
|
22
|
+
const {
|
|
23
|
+
logger,
|
|
24
|
+
scopes: { instrumentation },
|
|
25
|
+
patcher,
|
|
26
|
+
captureStacktrace,
|
|
27
|
+
protect,
|
|
28
|
+
protect: { inputTracing }
|
|
29
|
+
} = core;
|
|
30
|
+
|
|
31
|
+
function install() {
|
|
32
|
+
if (!global.ContrastMethods.__contrastEval) {
|
|
33
|
+
logger.error('Cannot install `eval` instrumentation - Contrast method DNE');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
patcher.patch(global.ContrastMethods, '__contrastEval', {
|
|
38
|
+
name: 'global.ContrastMethods.__contrastEval',
|
|
39
|
+
patchType,
|
|
40
|
+
pre: ({ args, hooked, orig }) => {
|
|
41
|
+
if (instrumentation.isLocked()) return;
|
|
42
|
+
|
|
43
|
+
const sourceContext = protect.getSourceContext('eval');
|
|
44
|
+
const value = args[0];
|
|
45
|
+
|
|
46
|
+
if (!sourceContext || !value || !isString(value)) return;
|
|
47
|
+
|
|
48
|
+
const sinkContext = captureStacktrace(
|
|
49
|
+
{ name: 'eval', value },
|
|
50
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
51
|
+
);
|
|
52
|
+
inputTracing.ssjsInjection(sourceContext, sinkContext);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const evalInstrumentation = inputTracing.evalInstrumentation = { install };
|
|
58
|
+
|
|
59
|
+
return evalInstrumentation;
|
|
60
|
+
};
|
|
@@ -61,10 +61,11 @@ const fsMethods = [
|
|
|
61
61
|
|
|
62
62
|
module.exports = function(core) {
|
|
63
63
|
const {
|
|
64
|
-
scopes: {
|
|
64
|
+
scopes: { instrumentation },
|
|
65
65
|
patcher,
|
|
66
66
|
depHooks,
|
|
67
67
|
captureStacktrace,
|
|
68
|
+
protect,
|
|
68
69
|
protect: { inputTracing }
|
|
69
70
|
} = core;
|
|
70
71
|
|
|
@@ -88,7 +89,8 @@ module.exports = function(core) {
|
|
|
88
89
|
if (instrumentation.isLocked()) return;
|
|
89
90
|
|
|
90
91
|
// obtain the Protect sourceContext
|
|
91
|
-
const sourceContext =
|
|
92
|
+
const sourceContext = protect.getSourceContext('fs');
|
|
93
|
+
|
|
92
94
|
if (!sourceContext) return;
|
|
93
95
|
|
|
94
96
|
// build list of values on which to perform INPUT TRACING
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright: 2022 Contrast Security, Inc
|
|
3
|
+
* Contact: support@contrastsecurity.com
|
|
4
|
+
* License: Commercial
|
|
5
|
+
|
|
6
|
+
* NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
* used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
* made available through public repositories, use of this Software is subject to
|
|
9
|
+
* the applicable End User Licensing Agreement found at
|
|
10
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
* between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
* way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const { patchType } = require('../constants');
|
|
19
|
+
|
|
20
|
+
module.exports = function(core) {
|
|
21
|
+
const {
|
|
22
|
+
scopes: { instrumentation },
|
|
23
|
+
patcher,
|
|
24
|
+
depHooks,
|
|
25
|
+
captureStacktrace,
|
|
26
|
+
protect,
|
|
27
|
+
protect: { inputTracing }
|
|
28
|
+
} = core;
|
|
29
|
+
|
|
30
|
+
function install() {
|
|
31
|
+
depHooks.resolve({ name: 'http' }, http => {
|
|
32
|
+
for (const method of ['write', 'end']) {
|
|
33
|
+
const name = `http.ServerResponse.prototype.${method}`;
|
|
34
|
+
patcher.patch(http.ServerResponse.prototype, method, {
|
|
35
|
+
name,
|
|
36
|
+
patchType,
|
|
37
|
+
pre(data) {
|
|
38
|
+
if (instrumentation.isLocked()) return;
|
|
39
|
+
|
|
40
|
+
const sourceContext = protect.getSourceContext(name);
|
|
41
|
+
|
|
42
|
+
if (!sourceContext) return;
|
|
43
|
+
|
|
44
|
+
const value = data.args[0]?.toString();
|
|
45
|
+
if (!value) return;
|
|
46
|
+
|
|
47
|
+
const sinkContext = captureStacktrace(
|
|
48
|
+
{ name, value },
|
|
49
|
+
{ constructorOpt: data.hooked }
|
|
50
|
+
);
|
|
51
|
+
inputTracing.handleReflectedXss(sourceContext, sinkContext);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const httpInstrumentation = inputTracing.httpInstrumentation = {
|
|
59
|
+
install
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return httpInstrumentation;
|
|
63
|
+
};
|
|
@@ -22,8 +22,8 @@ module.exports = function (core) {
|
|
|
22
22
|
const {
|
|
23
23
|
depHooks,
|
|
24
24
|
patcher,
|
|
25
|
-
scopes: { sources },
|
|
26
25
|
captureStacktrace,
|
|
26
|
+
protect,
|
|
27
27
|
protect: { inputTracing },
|
|
28
28
|
} = core;
|
|
29
29
|
|
|
@@ -61,15 +61,15 @@ module.exports = function (core) {
|
|
|
61
61
|
patcher.patch(obj, method, {
|
|
62
62
|
name: patchName,
|
|
63
63
|
patchType,
|
|
64
|
-
pre: ({ args, hooked, name }) => {
|
|
64
|
+
pre: ({ args, hooked, name, orig }) => {
|
|
65
65
|
const value = getCursorQueryData(args, version);
|
|
66
|
-
const sourceContext =
|
|
66
|
+
const sourceContext = protect.getSourceContext(patchName);
|
|
67
67
|
|
|
68
68
|
if (!sourceContext || !value) return;
|
|
69
69
|
|
|
70
70
|
const sinkContext = captureStacktrace(
|
|
71
71
|
{ name, value },
|
|
72
|
-
{ constructorOpt: hooked }
|
|
72
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
73
73
|
);
|
|
74
74
|
inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
|
|
75
75
|
}
|
|
@@ -80,10 +80,10 @@ module.exports = function (core) {
|
|
|
80
80
|
patcher.patch(obj, method, {
|
|
81
81
|
name: patchName,
|
|
82
82
|
patchType,
|
|
83
|
-
pre: ({ args, hooked, name }) => {
|
|
84
|
-
const sourceContext =
|
|
85
|
-
if (!sourceContext) return;
|
|
83
|
+
pre: ({ args, hooked, name, orig }) => {
|
|
84
|
+
const sourceContext = protect.getSourceContext(patchName);
|
|
86
85
|
|
|
86
|
+
if (!sourceContext) return;
|
|
87
87
|
|
|
88
88
|
const ops = Array.isArray(args[1])
|
|
89
89
|
? args[1]
|
|
@@ -93,7 +93,7 @@ module.exports = function (core) {
|
|
|
93
93
|
if (value) {
|
|
94
94
|
const sinkContext = captureStacktrace(
|
|
95
95
|
{ name, value },
|
|
96
|
-
{ constructorOpt: hooked }
|
|
96
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
97
97
|
);
|
|
98
98
|
inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
|
|
99
99
|
}
|
|
@@ -126,15 +126,15 @@ module.exports = function (core) {
|
|
|
126
126
|
patcher.patch(mongodb.Collection.prototype, method, {
|
|
127
127
|
name: `mongodb.Collection.prototype.${method}`,
|
|
128
128
|
patchType,
|
|
129
|
-
pre: ({ args, hooked, name }) => {
|
|
129
|
+
pre: ({ args, hooked, name, orig }) => {
|
|
130
130
|
const value = typeof args[0] == 'function' ? null : args[0];
|
|
131
|
-
const sourceContext =
|
|
131
|
+
const sourceContext = protect.getSourceContext(`mongodb.Collection.prototype.${method}`);
|
|
132
132
|
|
|
133
133
|
if (!sourceContext || !value) return;
|
|
134
134
|
|
|
135
135
|
const sinkContext = captureStacktrace(
|
|
136
136
|
{ name, value },
|
|
137
|
-
{ constructorOpt: hooked }
|
|
137
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
138
138
|
);
|
|
139
139
|
inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
|
|
140
140
|
},
|
|
@@ -144,15 +144,15 @@ module.exports = function (core) {
|
|
|
144
144
|
patcher.patch(mongodb.Db.prototype, 'command', {
|
|
145
145
|
name: 'mongodb.Db.prototype.command',
|
|
146
146
|
patchType,
|
|
147
|
-
pre: ({ args, hooked, name }) => {
|
|
147
|
+
pre: ({ args, hooked, name, orig }) => {
|
|
148
148
|
const value = args[0]?.filter;
|
|
149
|
-
const sourceContext =
|
|
149
|
+
const sourceContext = protect.getSourceContext('mongodb.Collection.prototype.command');
|
|
150
150
|
|
|
151
151
|
if (!sourceContext || !value) return;
|
|
152
152
|
|
|
153
153
|
const sinkContext = captureStacktrace(
|
|
154
154
|
{ name, value },
|
|
155
|
-
{ constructorOpt: hooked }
|
|
155
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
156
156
|
);
|
|
157
157
|
inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
|
|
158
158
|
}
|
|
@@ -168,15 +168,15 @@ module.exports = function (core) {
|
|
|
168
168
|
patcher.patch(mongodb.Db.prototype, 'eval', {
|
|
169
169
|
name: 'mongodb.Db.prototype.eval',
|
|
170
170
|
patchType,
|
|
171
|
-
pre: ({ args, hooked, name }) => {
|
|
171
|
+
pre: ({ args, hooked, name, orig }) => {
|
|
172
172
|
const value = args[0];
|
|
173
|
-
const sourceContext =
|
|
173
|
+
const sourceContext = protect.getSourceContext('mongodb.Db.prototype.eval');
|
|
174
174
|
|
|
175
175
|
if (!sourceContext || !value) return;
|
|
176
176
|
|
|
177
177
|
const sinkContext = captureStacktrace(
|
|
178
178
|
{ name, value },
|
|
179
|
-
{ constructorOpt: hooked }
|
|
179
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
180
180
|
);
|
|
181
181
|
|
|
182
182
|
inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
|
|
@@ -187,15 +187,15 @@ module.exports = function (core) {
|
|
|
187
187
|
depHooks.resolve({ name: 'mongodb', file: 'lib/cursor/find_cursor', version: '>=4.0.0' }, (cursor) => patcher.patch(cursor, 'FindCursor', {
|
|
188
188
|
name: 'mongodb.FindCursor',
|
|
189
189
|
patchType,
|
|
190
|
-
pre: ({ args, hooked, name }) => {
|
|
190
|
+
pre: ({ args, hooked, name, orig }) => {
|
|
191
191
|
const value = args[2];
|
|
192
|
-
const sourceContext =
|
|
192
|
+
const sourceContext = protect.getSourceContext('mongodb.FindCursor');
|
|
193
193
|
|
|
194
194
|
if (!sourceContext || !value) return;
|
|
195
195
|
|
|
196
196
|
const sinkContext = captureStacktrace(
|
|
197
197
|
{ name, value },
|
|
198
|
-
{ constructorOpt: hooked }
|
|
198
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
199
199
|
);
|
|
200
200
|
inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
|
|
201
201
|
}
|
|
@@ -23,7 +23,7 @@ module.exports = function(core) {
|
|
|
23
23
|
depHooks,
|
|
24
24
|
patcher,
|
|
25
25
|
captureStacktrace,
|
|
26
|
-
|
|
26
|
+
protect,
|
|
27
27
|
protect: { inputTracing }
|
|
28
28
|
} = core;
|
|
29
29
|
|
|
@@ -49,7 +49,8 @@ module.exports = function(core) {
|
|
|
49
49
|
patchType,
|
|
50
50
|
pre(data) {
|
|
51
51
|
const { args, hooked, name, orig } = data;
|
|
52
|
-
const sourceContext =
|
|
52
|
+
const sourceContext = protect.getSourceContext(name);
|
|
53
|
+
|
|
53
54
|
if (!sourceContext) return;
|
|
54
55
|
|
|
55
56
|
const value = mysqlInstr.getValueFromArgs(args);
|
|
@@ -22,8 +22,8 @@ module.exports = function(core) {
|
|
|
22
22
|
const {
|
|
23
23
|
depHooks,
|
|
24
24
|
patcher,
|
|
25
|
-
scopes: { sources },
|
|
26
25
|
captureStacktrace,
|
|
26
|
+
protect,
|
|
27
27
|
protect: { inputTracing }
|
|
28
28
|
} = core;
|
|
29
29
|
|
|
@@ -32,8 +32,9 @@ module.exports = function(core) {
|
|
|
32
32
|
if (query && isString(query)) return query;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function preHook({ args, hooked, name }) {
|
|
36
|
-
const sourceContext =
|
|
35
|
+
function preHook({ args, hooked, name, orig }) {
|
|
36
|
+
const sourceContext = protect.getSourceContext(name);
|
|
37
|
+
|
|
37
38
|
if (!sourceContext) return;
|
|
38
39
|
|
|
39
40
|
const value = getQueryFromArgs(args);
|
|
@@ -41,7 +42,7 @@ module.exports = function(core) {
|
|
|
41
42
|
|
|
42
43
|
const sinkContext = captureStacktrace(
|
|
43
44
|
{ name, value },
|
|
44
|
-
{ constructorOpt: hooked }
|
|
45
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
45
46
|
);
|
|
46
47
|
|
|
47
48
|
inputTracing.handleSqlInjection(sourceContext, sinkContext);
|
|
@@ -20,10 +20,11 @@ const { patchType } = require('../constants');
|
|
|
20
20
|
|
|
21
21
|
module.exports = function(core) {
|
|
22
22
|
const {
|
|
23
|
-
scopes: {
|
|
23
|
+
scopes: { instrumentation },
|
|
24
24
|
patcher,
|
|
25
25
|
depHooks,
|
|
26
26
|
captureStacktrace,
|
|
27
|
+
protect,
|
|
27
28
|
protect: { inputTracing }
|
|
28
29
|
} = core;
|
|
29
30
|
|
|
@@ -38,18 +39,19 @@ module.exports = function(core) {
|
|
|
38
39
|
patcher.patch(sequelize.prototype, 'query', {
|
|
39
40
|
name,
|
|
40
41
|
patchType,
|
|
41
|
-
pre({ args, hooked, name }) {
|
|
42
|
+
pre({ args, hooked, name, orig }) {
|
|
42
43
|
if (instrumentation.isLocked()) return;
|
|
43
44
|
|
|
44
|
-
const sourceContext =
|
|
45
|
-
|
|
45
|
+
const sourceContext = protect.getSourceContext(name);
|
|
46
|
+
|
|
47
|
+
if (!sourceContext || sourceContext.allowed) return;
|
|
46
48
|
|
|
47
49
|
const value = getQueryFromArgs(args);
|
|
48
50
|
if (!value) return;
|
|
49
51
|
|
|
50
52
|
const sinkContext = captureStacktrace(
|
|
51
53
|
{ name, value },
|
|
52
|
-
{ constructorOpt: hooked }
|
|
54
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
53
55
|
);
|
|
54
56
|
inputTracing.handleSqlInjection(sourceContext, sinkContext);
|
|
55
57
|
}
|
|
@@ -20,10 +20,11 @@ const { patchType } = require('../constants');
|
|
|
20
20
|
|
|
21
21
|
module.exports = function(core) {
|
|
22
22
|
const {
|
|
23
|
-
scopes: {
|
|
23
|
+
scopes: { instrumentation },
|
|
24
24
|
patcher,
|
|
25
25
|
depHooks,
|
|
26
26
|
captureStacktrace,
|
|
27
|
+
protect,
|
|
27
28
|
protect: { inputTracing }
|
|
28
29
|
} = core;
|
|
29
30
|
|
|
@@ -34,10 +35,10 @@ module.exports = function(core) {
|
|
|
34
35
|
patcher.patch(sqlite3.Database.prototype, method, {
|
|
35
36
|
name,
|
|
36
37
|
patchType,
|
|
37
|
-
pre({ args, hooked, name }) {
|
|
38
|
+
pre({ args, hooked, name, orig }) {
|
|
38
39
|
if (instrumentation.isLocked()) return;
|
|
39
40
|
|
|
40
|
-
const sourceContext =
|
|
41
|
+
const sourceContext = protect.getSourceContext(name);
|
|
41
42
|
if (!sourceContext) return;
|
|
42
43
|
|
|
43
44
|
const value = args[0];
|
|
@@ -45,8 +46,9 @@ module.exports = function(core) {
|
|
|
45
46
|
|
|
46
47
|
const sinkContext = captureStacktrace(
|
|
47
48
|
{ name, value },
|
|
48
|
-
{ constructorOpt: hooked }
|
|
49
|
+
{ constructorOpt: hooked, prependFrames: [orig] }
|
|
49
50
|
);
|
|
51
|
+
|
|
50
52
|
inputTracing.handleSqlInjection(sourceContext, sinkContext);
|
|
51
53
|
}
|
|
52
54
|
});
|