@newrelic/security-agent 0.0.1
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 +0 -0
- package/CONTRIBUTING.md +23 -0
- package/LICENSE +43 -0
- package/README.md +98 -0
- package/THIRD_PARTY_NOTICES.md +2909 -0
- package/index.js +24 -0
- package/lib/instrumentation-security/core/constants.js +66 -0
- package/lib/instrumentation-security/core/event-constants.js +49 -0
- package/lib/instrumentation-security/core/request-manager.js +73 -0
- package/lib/instrumentation-security/core/route-manager.js +30 -0
- package/lib/instrumentation-security/core/sec-trace.js +134 -0
- package/lib/instrumentation-security/core/sec-utils.js +212 -0
- package/lib/instrumentation-security/core/security-metadata.js +34 -0
- package/lib/instrumentation-security/core/stack-trace.js +156 -0
- package/lib/instrumentation-security/hooks/director/nr-director.js +98 -0
- package/lib/instrumentation-security/hooks/express/nr-express.js +106 -0
- package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +155 -0
- package/lib/instrumentation-security/hooks/fs/nr-fs.js +391 -0
- package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +131 -0
- package/lib/instrumentation-security/hooks/http/nr-http.js +461 -0
- package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +110 -0
- package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +81 -0
- package/lib/instrumentation-security/hooks/mongodb/common.js +239 -0
- package/lib/instrumentation-security/hooks/mongodb/constants.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +49 -0
- package/lib/instrumentation-security/hooks/mongodb/v2-mongo.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/v3-mongo.js +36 -0
- package/lib/instrumentation-security/hooks/mongodb/v4-mongo.js +17 -0
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +232 -0
- package/lib/instrumentation-security/hooks/native/nr-childProcess.js +131 -0
- package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +131 -0
- package/lib/instrumentation-security/hooks/require/nr-require.js +93 -0
- package/lib/instrumentation-security/hooks/restify/nr-restify.js +104 -0
- package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +91 -0
- package/lib/instrumentation-security/index.js +171 -0
- package/lib/nr-security-agent/index.js +170 -0
- package/lib/nr-security-agent/lib/core/Auth-headers.js +58 -0
- package/lib/nr-security-agent/lib/core/ContainerProperties.js +42 -0
- package/lib/nr-security-agent/lib/core/ECSProperties.js +34 -0
- package/lib/nr-security-agent/lib/core/FuzzFailEvent.js +27 -0
- package/lib/nr-security-agent/lib/core/LinkingMetadata.js +21 -0
- package/lib/nr-security-agent/lib/core/LogMessage.js +47 -0
- package/lib/nr-security-agent/lib/core/PodProperties.js +36 -0
- package/lib/nr-security-agent/lib/core/Policy.js +105 -0
- package/lib/nr-security-agent/lib/core/agent-status.js +56 -0
- package/lib/nr-security-agent/lib/core/agent.js +146 -0
- package/lib/nr-security-agent/lib/core/applicationinfo.js +634 -0
- package/lib/nr-security-agent/lib/core/commonUtils.js +411 -0
- package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +55 -0
- package/lib/nr-security-agent/lib/core/connections/restclient.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/index.js +25 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collecotor-policy-error-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +171 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +47 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/no-op-handler.js +12 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +27 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/unsupported-agent-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +14 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +443 -0
- package/lib/nr-security-agent/lib/core/event.js +186 -0
- package/lib/nr-security-agent/lib/core/health-check.js +159 -0
- package/lib/nr-security-agent/lib/core/json-file-handler.js +66 -0
- package/lib/nr-security-agent/lib/core/jsonValidator.js +149 -0
- package/lib/nr-security-agent/lib/core/lambda-delegated-task-service.js +90 -0
- package/lib/nr-security-agent/lib/core/logging.js +176 -0
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +173 -0
- package/lib/nr-security-agent/lib/core/sec-util.js +166 -0
- package/lib/nr-security-agent/lib/core/sha-size-util.js +338 -0
- package/lib/nr-security-agent/lib/core/sha_worker.js +24 -0
- package/lib/nr-security-agent/lib/core/startup-config.js +29 -0
- package/lib/nr-security-agent/lib/core/statusUtils.js +157 -0
- package/lib/nr-security-agent/lib/core/timeunit.js +44 -0
- package/lib/nr-security-agent/lib/core/websocket-client.js +335 -0
- package/lib/nr-security-agent/lib/core/worker-entities.js +82 -0
- package/lib/nr-security-agent/lib/core/worker.js +148 -0
- package/lib/nr-security-agent/lib/core/xss-utils.js +297 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/constants.js +12 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/index.js +15 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-sha-calculation.js +37 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-base.js +50 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-type.js +17 -0
- package/lib/nr-security-agent/resources/cert.pem +31 -0
- package/lib/nr-security-agent/resources/config.js +19 -0
- package/lib/nr-security-agent/resources/default-policy.yaml +36 -0
- package/lib/nr-security-api/index.js +111 -0
- package/package.json +95 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const requestManager = require("../../core/request-manager");
|
|
7
|
+
|
|
8
|
+
const async_hooks = require("async_hooks");
|
|
9
|
+
const secUtils = require('../../core/sec-utils');
|
|
10
|
+
const API = require("../../../nr-security-api");
|
|
11
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
12
|
+
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
13
|
+
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
14
|
+
const logger = API.getLogger();
|
|
15
|
+
|
|
16
|
+
module.exports = initialize;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Entry point of mysql and msyql2 module hooks
|
|
20
|
+
* @param {*} shim
|
|
21
|
+
* @param {*} mysql
|
|
22
|
+
* @param {*} moduleName
|
|
23
|
+
*/
|
|
24
|
+
function initialize(shim, mysql, moduleName) {
|
|
25
|
+
logger.info("Instrumenting", moduleName);
|
|
26
|
+
if (shim._moduleRoot.includes("mysql2")) {
|
|
27
|
+
promiseInitialize(shim, mysql, moduleName);
|
|
28
|
+
} else {
|
|
29
|
+
callbackInitialize(shim, mysql, moduleName);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Wrapper for mysql module hooks
|
|
35
|
+
* @param {*} shim
|
|
36
|
+
* @param {*} mysql
|
|
37
|
+
* @param {*} moduleName
|
|
38
|
+
*/
|
|
39
|
+
function callbackInitialize(shim, mysql, moduleName) {
|
|
40
|
+
shim.__wrappedPoolConnection = false;
|
|
41
|
+
|
|
42
|
+
shim.wrapReturn(mysql, "createConnection", wrapCreateConnection);
|
|
43
|
+
function wrapCreateConnection(shim, fn, fnName, connection) {
|
|
44
|
+
if (wrapQueryable(shim, connection, false)) {
|
|
45
|
+
const connProto = Object.getPrototypeOf(connection);
|
|
46
|
+
shim.unwrap(mysql, "createConnection");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
shim.wrapReturn(mysql, "createPool", wrapCreatePool);
|
|
51
|
+
function wrapCreatePool(shim, fn, fnName, pool) {
|
|
52
|
+
if (wrapQueryable(shim, pool, true) && wrapGetConnection(shim, pool)) {
|
|
53
|
+
shim.unwrap(mysql, "createPool");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
shim.wrapReturn(mysql, "createPoolCluster", wrapCreatePoolCluster);
|
|
58
|
+
function wrapCreatePoolCluster(shim, fn, fnName, poolCluster) {
|
|
59
|
+
const proto = Object.getPrototypeOf(poolCluster);
|
|
60
|
+
shim.wrapReturn(proto, "of", wrapPoolClusterOf);
|
|
61
|
+
function wrapPoolClusterOf(shim, of, _n, poolNamespace) {
|
|
62
|
+
if (wrapGetConnection(shim, poolNamespace)) {
|
|
63
|
+
shim.unwrap(proto, "of");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (wrapGetConnection(shim, poolCluster)) {
|
|
67
|
+
shim.unwrap(mysql, "createPoolCluster");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Wrapper for mysql2 module hooks
|
|
74
|
+
* @param {*} shim
|
|
75
|
+
*/
|
|
76
|
+
function promiseInitialize(shim) {
|
|
77
|
+
const callbackAPI = shim.require("./index");
|
|
78
|
+
if (callbackAPI && !shim.isWrapped(callbackAPI.createConnection)) {
|
|
79
|
+
callbackInitialize(shim, callbackAPI);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Wrapper to hook connection obejct.
|
|
85
|
+
* @param {*} shim
|
|
86
|
+
* @param {*} connectable
|
|
87
|
+
* @returns
|
|
88
|
+
*/
|
|
89
|
+
function wrapGetConnection(shim, connectable) {
|
|
90
|
+
if (
|
|
91
|
+
!connectable ||
|
|
92
|
+
!connectable.getConnection ||
|
|
93
|
+
shim.isWrapped(connectable.getConnection)
|
|
94
|
+
) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const proto = Object.getPrototypeOf(connectable);
|
|
99
|
+
shim.wrap(proto, "getConnection", function doWrapGetConnection(shim, fn) {
|
|
100
|
+
return function wrappedGetConnection() {
|
|
101
|
+
const args = shim.toArray(arguments);
|
|
102
|
+
const cbIdx = args.length - 1;
|
|
103
|
+
|
|
104
|
+
if (shim.isFunction(args[cbIdx]) && !shim.isWrapped(args[cbIdx])) {
|
|
105
|
+
let cb = args[cbIdx];
|
|
106
|
+
if (!shim.__wrappedPoolConnection) {
|
|
107
|
+
cb = shim.wrap(cb, wrapGetConnectionCallback);
|
|
108
|
+
}
|
|
109
|
+
args[cbIdx] = shim.bindSegment(cb);
|
|
110
|
+
}
|
|
111
|
+
return fn.apply(this, args);
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function wrapGetConnectionCallback(shim, cb) {
|
|
119
|
+
return function wrappedGetConnectionCallback(err, conn) {
|
|
120
|
+
try {
|
|
121
|
+
if (!err && wrapQueryable(shim, conn, false)) {
|
|
122
|
+
// Leave getConnection wrapped in order to maintain TX state, but we can
|
|
123
|
+
// simplify the wrapping of its callback in future calls.
|
|
124
|
+
shim.__wrappedPoolConnection = true;
|
|
125
|
+
}
|
|
126
|
+
} catch (_err) { }
|
|
127
|
+
return cb.apply(this, arguments);
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Wrapper to hook query function.
|
|
133
|
+
* @param {*} shim
|
|
134
|
+
* @param {*} queryable
|
|
135
|
+
* @param {*} isPoolQuery
|
|
136
|
+
* @returns
|
|
137
|
+
*/
|
|
138
|
+
function wrapQueryable(shim, queryable, isPoolQuery) {
|
|
139
|
+
if (!queryable || !queryable.query || shim.isWrapped(queryable.query)) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const proto = Object.getPrototypeOf(queryable);
|
|
143
|
+
queryHook(shim, proto, "query", isPoolQuery);
|
|
144
|
+
if (queryable.execute) {
|
|
145
|
+
queryHook(shim, proto, "execute", isPoolQuery);
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Utility to extract query from the intercepted args
|
|
152
|
+
* @param {*} shim
|
|
153
|
+
* @param {*} args
|
|
154
|
+
* @returns
|
|
155
|
+
*/
|
|
156
|
+
function extractQueryArgs(shim, args) {
|
|
157
|
+
let rawQuery = "";
|
|
158
|
+
let param = [];
|
|
159
|
+
|
|
160
|
+
// Figure out the query parameter.
|
|
161
|
+
if (shim.isString(args[0])) {
|
|
162
|
+
// query(sql [, values], callback)
|
|
163
|
+
rawQuery = args[0];
|
|
164
|
+
} else {
|
|
165
|
+
// query(opts [, values], callback)
|
|
166
|
+
rawQuery = args[0].sql;
|
|
167
|
+
}
|
|
168
|
+
// Then determine the query values and callback parameters.
|
|
169
|
+
if (shim.isArray(args[1])) {
|
|
170
|
+
// query({opts|sql}, values, callback)
|
|
171
|
+
param = args[1];
|
|
172
|
+
}
|
|
173
|
+
else if (args[1] && typeof args[1] == 'object') {
|
|
174
|
+
param = args[1];
|
|
175
|
+
param = Object.values(param)
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
rawQuery: rawQuery,
|
|
179
|
+
param: param,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Wrapper to wrap query function.
|
|
184
|
+
* @param {*} shim
|
|
185
|
+
* @param {*} mod
|
|
186
|
+
* @param {*} method
|
|
187
|
+
*/
|
|
188
|
+
function queryHook(shim, mod, method, isPoolQuery) {
|
|
189
|
+
|
|
190
|
+
shim.wrap(mod, method, function makeQueryWrapper(shim, fn) {
|
|
191
|
+
return function queryWrapper() {
|
|
192
|
+
const parameters = extractQueryArgs(shim, arguments);
|
|
193
|
+
shim.interceptedArgs = parameters;
|
|
194
|
+
const request = requestManager.getRequest(shim);
|
|
195
|
+
if (request && !isPoolQuery) {
|
|
196
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
197
|
+
traceObject.sourceMethod = method;
|
|
198
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, parameters, traceObject, secUtils.getExecutionId(), EVENT_TYPE.DB_COMMAND, EVENT_CATEGORY.MYSQL)
|
|
199
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
200
|
+
API.sendEvent(secEvent);
|
|
201
|
+
if (request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
202
|
+
callbackHook(shim, arguments, arguments.length - 1, secEvent);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return fn.apply(this, arguments);
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Callback hook to generate exit event
|
|
213
|
+
* @param {*} shim
|
|
214
|
+
* @param {*} mod
|
|
215
|
+
* @param {*} fun
|
|
216
|
+
* @param {*} secEvent
|
|
217
|
+
*/
|
|
218
|
+
function callbackHook(shim, mod, fun, secEvent) {
|
|
219
|
+
shim.secEvent = secEvent;
|
|
220
|
+
shim.wrap(mod, fun, function callbackWrapper(shim, fn) {
|
|
221
|
+
if (!shim.isFunction(fn)) {
|
|
222
|
+
return fn;
|
|
223
|
+
}
|
|
224
|
+
return function wrapper() {
|
|
225
|
+
if ((arguments[0] === null || arguments[0] === undefined) && shim.secEvent) {
|
|
226
|
+
API.generateExitEvent(shim.secEvent);
|
|
227
|
+
delete shim.secEvent;
|
|
228
|
+
}
|
|
229
|
+
return fn.apply(this, arguments);
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = initialize;
|
|
7
|
+
const requestManager = require("../../core/request-manager");
|
|
8
|
+
const secUtils = require("../../core/sec-utils");
|
|
9
|
+
const API = require("../../../nr-security-api");
|
|
10
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
11
|
+
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
12
|
+
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
13
|
+
const logger = API.getLogger();
|
|
14
|
+
|
|
15
|
+
function initialize(shim, childProcess, moduleName) {
|
|
16
|
+
logger.info('Instrumenting child_process');
|
|
17
|
+
execFileHook(shim, childProcess, moduleName);
|
|
18
|
+
spawnHook(shim, childProcess, moduleName);
|
|
19
|
+
spawnSyncHook(shim, process.binding("spawn_sync"), moduleName);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Wrapper to hook childProcess.execFile()
|
|
23
|
+
* @param {*} shim
|
|
24
|
+
* @param {*} childProcess
|
|
25
|
+
* @param {*} moduleName
|
|
26
|
+
*/
|
|
27
|
+
function execFileHook(shim, childProcess, moduleName) {
|
|
28
|
+
shim.wrap(childProcess, "execFile", function makeWrapper(shim, fn) {
|
|
29
|
+
return function wrapper() {
|
|
30
|
+
const interceptedArgs = [arguments[0]];
|
|
31
|
+
shim.interceptedArgs = interceptedArgs;
|
|
32
|
+
const request = requestManager.getRequest(shim);
|
|
33
|
+
if (request) {
|
|
34
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
35
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.SYSTEM_COMMAND, EVENT_CATEGORY.SYS)
|
|
36
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
37
|
+
API.sendEvent(secEvent);
|
|
38
|
+
if (request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
39
|
+
callbackHook(shim, arguments, arguments.length - 1, secEvent);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return fn.apply(this, arguments);
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Function to wrap childProcess.spawnSync()
|
|
51
|
+
* @param {*} shim
|
|
52
|
+
* @param {*} childProcess
|
|
53
|
+
* @param {*} moduleName
|
|
54
|
+
*/
|
|
55
|
+
function spawnSyncHook(shim, childProcess, moduleName) {
|
|
56
|
+
shim.wrap(childProcess, "spawn", function makeWrapper(shim, fn) {
|
|
57
|
+
return function wrapper() {
|
|
58
|
+
const interceptedArgs = arguments[0].args;
|
|
59
|
+
shim.interceptedArgs = interceptedArgs;
|
|
60
|
+
const request = requestManager.getRequest(shim);
|
|
61
|
+
if (request) {
|
|
62
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
63
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.SYSTEM_COMMAND, EVENT_CATEGORY.SYS)
|
|
64
|
+
this.secEvent = API.generateSecEvent(secMetadata);
|
|
65
|
+
API.sendEvent(this.secEvent);
|
|
66
|
+
}
|
|
67
|
+
const result = fn.apply(this, arguments);
|
|
68
|
+
|
|
69
|
+
if(result && result.status==0 && request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]){
|
|
70
|
+
API.generateExitEvent(this.secEvent);
|
|
71
|
+
delete this.secEvent
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Function to wrap childProcess.spawn()
|
|
80
|
+
* @param {*} shim
|
|
81
|
+
* @param {*} childProcess
|
|
82
|
+
* @param {*} moduleName
|
|
83
|
+
*/
|
|
84
|
+
function spawnHook(shim, childProcess, moduleName) {
|
|
85
|
+
shim.wrap(childProcess, "spawn", function makeWrapper(shim, fn) {
|
|
86
|
+
return function wrapper() {
|
|
87
|
+
let param = [];
|
|
88
|
+
param.push(arguments[0]);
|
|
89
|
+
if (arguments[1]) {
|
|
90
|
+
param.push(arguments[1].toString());
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
const interceptedArgs = param;
|
|
94
|
+
shim.interceptedArgs = interceptedArgs;
|
|
95
|
+
const request = requestManager.getRequest(shim);
|
|
96
|
+
if (request) {
|
|
97
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
98
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.SYSTEM_COMMAND, EVENT_CATEGORY.SYS)
|
|
99
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
100
|
+
API.sendEvent(secEvent);
|
|
101
|
+
if (request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
102
|
+
callbackHook(shim, arguments, arguments.length - 1, secEvent);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return fn.apply(this, arguments);
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Callback hook to generate exit event
|
|
112
|
+
* @param {*} shim
|
|
113
|
+
* @param {*} mod
|
|
114
|
+
* @param {*} fun
|
|
115
|
+
* @param {*} secEvent
|
|
116
|
+
*/
|
|
117
|
+
function callbackHook(shim, mod, fun, secEvent) {
|
|
118
|
+
shim.secEvent = secEvent;
|
|
119
|
+
shim.wrap(mod, fun, function callbackWrapper(shim, fn) {
|
|
120
|
+
if (!shim.isFunction(fn)) {
|
|
121
|
+
return fn;
|
|
122
|
+
}
|
|
123
|
+
return function wrapper(secEvent) {
|
|
124
|
+
if ((arguments[0] === null || arguments[0] === undefined) && shim.secEvent) {
|
|
125
|
+
API.generateExitEvent(shim.secEvent);
|
|
126
|
+
delete shim.secEvent;
|
|
127
|
+
}
|
|
128
|
+
return fn.apply(this, arguments);
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
'use strict'
|
|
8
|
+
|
|
9
|
+
const requestManager = require('../../core/request-manager');
|
|
10
|
+
const secUtils = require('../../core/sec-utils');
|
|
11
|
+
const API = require("../../../nr-security-api");
|
|
12
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
13
|
+
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
14
|
+
const logger = API.getLogger();
|
|
15
|
+
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
16
|
+
|
|
17
|
+
module.exports = function initialize(shim, pgsql, moduleName) {
|
|
18
|
+
logger.info('Instrumenting '+ moduleName)
|
|
19
|
+
// allows for native wrapping to not happen if not necessary
|
|
20
|
+
// when env var is true
|
|
21
|
+
if (process.env.NODE_PG_FORCE_NATIVE) {
|
|
22
|
+
return instrumentPGNative(pgsql)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// wrapping for native
|
|
26
|
+
function instrumentPGNative(pg) {
|
|
27
|
+
shim.wrapReturn(pg, 'Client', clientFactoryWrapper)
|
|
28
|
+
shim.wrapClass(pg, 'Pool', { post: poolPostConstructor, es6: true })
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function poolPostConstructor(shim) {
|
|
32
|
+
if (!shim.isWrapped(this.Client)) {
|
|
33
|
+
shim.wrapClass(this, 'Client', clientPostConstructor)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function clientFactoryWrapper(shim, fn, fnName, client) {
|
|
38
|
+
clientPostConstructor.call(client, shim)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function clientPostConstructor(shim) {
|
|
42
|
+
queryHook(shim, this, 'query');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The pg module defines "native" getter which sets up the native client lazily
|
|
46
|
+
// (only when called). We replace the getter, so that we can instrument the native
|
|
47
|
+
// client. The original getter replaces itself with the instance of the native
|
|
48
|
+
// client, so only instrument if the getter exists (otherwise assume already
|
|
49
|
+
// instrumented).
|
|
50
|
+
const origGetter = pgsql.__lookupGetter__('native')
|
|
51
|
+
if (origGetter) {
|
|
52
|
+
delete pgsql.native
|
|
53
|
+
pgsql.__defineGetter__('native', function getNative() {
|
|
54
|
+
const temp = origGetter()
|
|
55
|
+
if (temp != null) {
|
|
56
|
+
instrumentPGNative(temp)
|
|
57
|
+
}
|
|
58
|
+
return temp
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
queryHook(shim, pgsql && pgsql.Client && pgsql.Client.prototype, 'query');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
function queryHook(shim, mod, method){
|
|
68
|
+
shim.wrap(mod, method, function makeQueryWrapper(shim, fn){
|
|
69
|
+
return function queryWrapper(){
|
|
70
|
+
const request = requestManager.getRequest(shim);
|
|
71
|
+
const sqlArgs = [];
|
|
72
|
+
if (typeof arguments[0] === 'object') {
|
|
73
|
+
if ((arguments[0] && arguments[0].constructor && arguments[0].constructor.name == 'Cursor') || (arguments[0] && arguments[0].text && arguments[0].values)) {
|
|
74
|
+
sqlArgs.push(arguments[0].text);
|
|
75
|
+
if (Array.isArray(arguments[0].values)) {
|
|
76
|
+
sqlArgs.push(arguments[0].values);
|
|
77
|
+
}
|
|
78
|
+
} else if (arguments[0] && arguments[0].constructor && arguments[0].constructor.name == 'QueryStream' && arguments[0].cursor) {
|
|
79
|
+
sqlArgs.push(arguments[0].cursor.text);
|
|
80
|
+
if (Array.isArray(arguments[0].cursor.values)) {
|
|
81
|
+
sqlArgs.push(arguments[0].cursor.values);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if(arguments[0] && arguments[0].text){
|
|
85
|
+
sqlArgs.push(arguments[0].text);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
for (let i = 0; i < arguments.length; i++) {
|
|
89
|
+
if (typeof arguments[i] !== 'function') {
|
|
90
|
+
sqlArgs.push(arguments[i]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
shim.interceptedArgs = sqlArgs;
|
|
95
|
+
if (request) {
|
|
96
|
+
const traceObject = secUtils.getTraceObject(shim);
|
|
97
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, sqlArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.DB_COMMAND, EVENT_CATEGORY.POSTGRES)
|
|
98
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
99
|
+
API.sendEvent(secEvent);
|
|
100
|
+
if (request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
101
|
+
callbackHook(shim, arguments, arguments.length - 1, secEvent);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return fn.apply(this, arguments);
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Callback hook to generate exit event
|
|
112
|
+
* @param {*} shim
|
|
113
|
+
* @param {*} mod
|
|
114
|
+
* @param {*} fun
|
|
115
|
+
* @param {*} secEvent
|
|
116
|
+
*/
|
|
117
|
+
function callbackHook(shim, mod, fun, secEvent) {
|
|
118
|
+
shim.secEvent = secEvent;
|
|
119
|
+
shim.wrap(mod, fun, function callbackWrapper(shim, fn) {
|
|
120
|
+
if (!shim.isFunction(fn)) {
|
|
121
|
+
return fn;
|
|
122
|
+
}
|
|
123
|
+
return function wrapper() {
|
|
124
|
+
if ((arguments[0] === null || arguments[0] === undefined) && shim.secEvent) {
|
|
125
|
+
API.generateExitEvent(shim.secEvent);
|
|
126
|
+
delete shim.secEvent;
|
|
127
|
+
}
|
|
128
|
+
return fn.apply(this, arguments);
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const requestManager = require('../../core/request-manager');
|
|
7
|
+
const secUtils = require("../../core/sec-utils");
|
|
8
|
+
const API = require("../../../nr-security-api");
|
|
9
|
+
const securityMetaData = require('../../core/security-metadata');
|
|
10
|
+
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
11
|
+
const { STRING } = require('../../core/constants')
|
|
12
|
+
const logger = API.getLogger();
|
|
13
|
+
const Module = require('module');
|
|
14
|
+
const refDirRegEx = /^(\.\/)|^(\.\.\/)/g;
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const CSEC = 'nr-security-agent';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Entry point for xpath module hook
|
|
20
|
+
* @param {*} shim
|
|
21
|
+
* @param {*} mod
|
|
22
|
+
* @param {*} moduleName
|
|
23
|
+
*/
|
|
24
|
+
function initialize(shim) {
|
|
25
|
+
|
|
26
|
+
const original_load = Module._load;
|
|
27
|
+
logger.info('Instrumenting Module._load');
|
|
28
|
+
|
|
29
|
+
Module._load = function (request, parent) {
|
|
30
|
+
|
|
31
|
+
let moduleName = arguments[0];
|
|
32
|
+
|
|
33
|
+
if (arguments[0].match(refDirRegEx) && arguments[1] && arguments[1].path) {
|
|
34
|
+
moduleName = path.resolve(arguments[1].path, arguments[0]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let flag = false;
|
|
38
|
+
if (moduleName && typeof (moduleName) === STRING && !moduleName.includes(CSEC)) {
|
|
39
|
+
flag = true;
|
|
40
|
+
}
|
|
41
|
+
else if (parent && parent.id && typeof (parent.id) === STRING && moduleName.includes(CSEC) && parent.id.includes(CSEC)) {
|
|
42
|
+
flag = false;
|
|
43
|
+
}
|
|
44
|
+
else if (parent && parent.id && moduleName && typeof (moduleName) === STRING && moduleName.includes(CSEC) && parent.id.includes(CSEC)) {
|
|
45
|
+
flag = false;
|
|
46
|
+
}
|
|
47
|
+
if (flag) {
|
|
48
|
+
requireHook(shim, moduleName, parent);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return original_load.apply(this, arguments);
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function requireHook(shim, moduleName, parent) {
|
|
58
|
+
try {
|
|
59
|
+
let request = requestManager.getRequest(shim);
|
|
60
|
+
let fallback = false;
|
|
61
|
+
if (!request) {
|
|
62
|
+
fallback = true;
|
|
63
|
+
let values = [...requestManager.requestMap.values()];
|
|
64
|
+
if (values.length > 0) {
|
|
65
|
+
request = values[values.length - 1];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (request) {
|
|
69
|
+
const interceptedArgs = [moduleName];
|
|
70
|
+
let traceObject;
|
|
71
|
+
if (!fallback) {
|
|
72
|
+
traceObject = secUtils.getTraceObject(shim);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
traceObject = secUtils.getTraceObjectFallback(request);
|
|
76
|
+
}
|
|
77
|
+
const secMetadata = securityMetaData.getSecurityMetaData(request, interceptedArgs, traceObject, secUtils.getExecutionId(), EVENT_TYPE.FILE_OPERATION, EVENT_CATEGORY.FILE)
|
|
78
|
+
const secEvent = API.generateSecEvent(secMetadata);
|
|
79
|
+
API.sendEvent(secEvent);
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
initialize
|
|
92
|
+
}
|
|
93
|
+
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = initialize
|
|
7
|
+
const requestManager = require('../../core/request-manager');
|
|
8
|
+
const secUtils = require('../../core/sec-utils');
|
|
9
|
+
const { ATTHERATE, DOUBLE_DOLLAR } = require('../../core/constants');
|
|
10
|
+
const lodash = require('lodash');
|
|
11
|
+
const routeManager = require('../../core/route-manager');
|
|
12
|
+
const url = require('url');
|
|
13
|
+
const API = require("../../../nr-security-api");
|
|
14
|
+
const logger = API.getLogger();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Entry point of restify module hook.
|
|
18
|
+
* Wrapper for registryRadix module
|
|
19
|
+
* @param {*} shim
|
|
20
|
+
* @param {*} mod
|
|
21
|
+
* @param {*} moduleName
|
|
22
|
+
*/
|
|
23
|
+
function initialize(shim, mod, moduleName) {
|
|
24
|
+
logger.info('Instrumenting Restify');
|
|
25
|
+
try {
|
|
26
|
+
const registryRadix = shim.require("./lib/routerRegistryRadix");
|
|
27
|
+
|
|
28
|
+
//routerRadix hook
|
|
29
|
+
shim.wrap(registryRadix && registryRadix.prototype, 'add', function makeWrapper(shim, fn) {
|
|
30
|
+
return function wrapper() {
|
|
31
|
+
if (arguments[0]) {
|
|
32
|
+
try {
|
|
33
|
+
const method = lodash.upperCase(arguments[0].method);
|
|
34
|
+
const path = arguments[0].path;
|
|
35
|
+
const key = method + ATTHERATE + path;
|
|
36
|
+
const stakTrace = secUtils.traceElementForRoute();
|
|
37
|
+
const splittedStack = stakTrace[0].split(DOUBLE_DOLLAR);
|
|
38
|
+
routeManager.setRoute(key, splittedStack[0]);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return fn.apply(this, arguments);
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const router = shim.require("./lib/router");
|
|
48
|
+
|
|
49
|
+
shim.wrap(router && router.prototype, 'lookup', function lookupWrapper(shim, fn) {
|
|
50
|
+
return function wrappedLookup() {
|
|
51
|
+
const result = fn.apply(this, arguments);
|
|
52
|
+
extractParams(shim, arguments[0]);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
} catch (error) {
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Utilty to extract path params and query params
|
|
63
|
+
* @param {*} shim
|
|
64
|
+
* @param {*} req
|
|
65
|
+
*/
|
|
66
|
+
function extractParams(shim, req) {
|
|
67
|
+
const segment = shim.getActiveSegment();
|
|
68
|
+
if (segment && segment.transaction) {
|
|
69
|
+
|
|
70
|
+
let request = requestManager.getRequestFromId(segment.transaction.id);
|
|
71
|
+
if (req.params && request) {
|
|
72
|
+
try {
|
|
73
|
+
Object.keys(req.params).forEach(function (key) {
|
|
74
|
+
if (req.params[key]) {
|
|
75
|
+
if (!request.parameterMap[key]) {
|
|
76
|
+
request.parameterMap[key] = new Array(req.params[key].toString());
|
|
77
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
} catch (error) {
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (req.query && request) {
|
|
86
|
+
try {
|
|
87
|
+
const url_parts = url.parse(req.url, true);
|
|
88
|
+
const query = url_parts.query;
|
|
89
|
+
Object.keys(query).forEach(function (key) {
|
|
90
|
+
if (query[key]) {
|
|
91
|
+
request.parameterMap[key] = new Array(query[key].toString());
|
|
92
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (req.route && req.route.path && request) {
|
|
100
|
+
request.uri = req.route.path;
|
|
101
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|