@obfuscan/core 0.1.0 → 0.2.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/README.md +1 -1
- package/dist/detectors/high-entropy-literal.d.ts.map +1 -1
- package/dist/detectors/high-entropy-literal.js +16 -0
- package/dist/detectors/high-entropy-literal.js.map +1 -1
- package/dist/detectors/index.d.ts +2 -1
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +3 -1
- package/dist/detectors/index.js.map +1 -1
- package/dist/detectors/npm-c2-dropper.d.ts +11 -0
- package/dist/detectors/npm-c2-dropper.d.ts.map +1 -0
- package/dist/detectors/npm-c2-dropper.js +61 -0
- package/dist/detectors/npm-c2-dropper.js.map +1 -0
- package/dist/detectors/shell-untrusted-input.js +1 -1
- package/dist/detectors/shell-untrusted-input.js.map +1 -1
- package/dist/internal/patterns.d.ts +3 -1
- package/dist/internal/patterns.d.ts.map +1 -1
- package/dist/internal/patterns.js +53 -2
- package/dist/internal/patterns.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# obfuscan
|
|
2
2
|
|
|
3
|
-
Detect obfuscated code and likely backdoors in
|
|
3
|
+
Detect obfuscated code and likely backdoors in files or text. Multi-language. Embeddable. Diff-aware. Pure TypeScript.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@obfuscan/core)
|
|
6
6
|
[](./LICENSE)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"high-entropy-literal.d.ts","sourceRoot":"","sources":["../../src/detectors/high-entropy-literal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"high-entropy-literal.d.ts","sourceRoot":"","sources":["../../src/detectors/high-entropy-literal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAgDlE,eAAO,MAAM,kBAAkB,EAAE,QAkDhC,CAAC"}
|
|
@@ -21,6 +21,9 @@ const MIN_LEN = 40;
|
|
|
21
21
|
const ENTROPY_THRESHOLD = 4.5; // bits/char
|
|
22
22
|
const MAX_SOURCE_BYTES = 2_000_000; // skip files larger than 2 MB
|
|
23
23
|
const MAX_FINDINGS_PER_FILE = 50; // protect the report from minified bundles
|
|
24
|
+
const BASE64ISH_RE = /^[A-Za-z0-9+/=_-]+$/;
|
|
25
|
+
const DATA_URI_BASE64_RE = /^data:[^,]{1,120};base64,[A-Za-z0-9+/=]+$/i;
|
|
26
|
+
const ESCAPED_BYTES_RE = /^(?:\\x[0-9A-Fa-f]{2}|\\u[0-9A-Fa-f]{4}|\\[0-7]{3})+$/;
|
|
24
27
|
/** Shannon entropy in bits/char. */
|
|
25
28
|
function shannon(s) {
|
|
26
29
|
if (s.length === 0)
|
|
@@ -35,6 +38,17 @@ function shannon(s) {
|
|
|
35
38
|
}
|
|
36
39
|
return h;
|
|
37
40
|
}
|
|
41
|
+
function looksEncodedOrPacked(s) {
|
|
42
|
+
if (DATA_URI_BASE64_RE.test(s))
|
|
43
|
+
return true;
|
|
44
|
+
if (ESCAPED_BYTES_RE.test(s))
|
|
45
|
+
return true;
|
|
46
|
+
// Ordinary prose, SQL, and structured log messages often cross the entropy
|
|
47
|
+
// threshold. Packed payloads are typically dense and whitespace-free.
|
|
48
|
+
if (/\s/.test(s))
|
|
49
|
+
return false;
|
|
50
|
+
return BASE64ISH_RE.test(s);
|
|
51
|
+
}
|
|
38
52
|
/** Convert a 0-based character offset to a 1-based line number. */
|
|
39
53
|
function lineAt(source, offset) {
|
|
40
54
|
let line = 1;
|
|
@@ -63,6 +77,8 @@ export const highEntropyLiteral = {
|
|
|
63
77
|
const body = match[2];
|
|
64
78
|
if (!body || body.length < MIN_LEN)
|
|
65
79
|
continue;
|
|
80
|
+
if (!looksEncodedOrPacked(body))
|
|
81
|
+
continue;
|
|
66
82
|
const entropy = shannon(body);
|
|
67
83
|
if (entropy < ENTROPY_THRESHOLD)
|
|
68
84
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"high-entropy-literal.js","sourceRoot":"","sources":["../../src/detectors/high-entropy-literal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,+EAA+E;AAC/E,MAAM,iBAAiB,GAAG,mCAAmC,CAAC;AAE9D,MAAM,OAAO,GAAG,EAAE,CAAC;AACnB,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAC,YAAY;AAC3C,MAAM,gBAAgB,GAAG,SAAS,CAAC,CAAC,8BAA8B;AAClE,MAAM,qBAAqB,GAAG,EAAE,CAAC,CAAC,2CAA2C;AAE7E,oCAAoC;AACpC,SAAS,OAAO,CAAC,CAAS;IACxB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACvB,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,mEAAmE;AACnE,SAAS,MAAM,CAAC,MAAc,EAAE,MAAc;IAC5C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrD,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ;YAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAa;IAC1C,EAAE,EAAE,0BAA0B;IAC9B,OAAO,EAAE,6FAA6F;IAEtG,OAAO,CAAC,GAAgB;QACtB,2DAA2D;QAC3D,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC;IACvE,CAAC;IAED,GAAG,CAAC,GAAgB;QAClB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;QACvB,IAAI,KAA6B,CAAC;QAElC,6DAA6D;QAC7D,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAEzE,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACvC,IAAI,QAAQ,CAAC,MAAM,IAAI,qBAAqB;gBAAE,MAAM;YAEpD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO;gBAAE,SAAS;
|
|
1
|
+
{"version":3,"file":"high-entropy-literal.js","sourceRoot":"","sources":["../../src/detectors/high-entropy-literal.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,7 @@ import { suspiciousIoCluster } from "./suspicious-io-cluster.js";
|
|
|
20
20
|
import { stringArrayDecoder } from "./string-array-decoder.js";
|
|
21
21
|
import { shellUntrustedInput } from "./shell-untrusted-input.js";
|
|
22
22
|
import { libraryLoadNonLiteral } from "./library-load-non-literal.js";
|
|
23
|
+
import { npmC2Dropper } from "./npm-c2-dropper.js";
|
|
23
24
|
import { manifestInstallScript } from "./manifest-install-script.js";
|
|
24
25
|
import { pythonSetupSideEffect } from "./python-setup-side-effect.js";
|
|
25
26
|
import { perlMakefileSideEffect } from "./perl-makefile-side-effect.js";
|
|
@@ -27,5 +28,5 @@ import { cargoBuildRsNetwork } from "./cargo-build-rs-network.js";
|
|
|
27
28
|
import { ghaCurlPipeShell } from "./gha-curl-pipe-shell.js";
|
|
28
29
|
import { dockerfileCurlPipeShell } from "./dockerfile-curl-pipe-shell.js";
|
|
29
30
|
export declare function defaultDetectors(): readonly Detector[];
|
|
30
|
-
export { highEntropyLiteral, bidiControlChar, homoglyphIdentifier, longLine, encodedArrayFingerprint, decodeThenExec, dynamicExecNonLiteral, networkThenExec, deserializerUntrusted, suspiciousIoCluster, stringArrayDecoder, shellUntrustedInput, libraryLoadNonLiteral, manifestInstallScript, pythonSetupSideEffect, perlMakefileSideEffect, cargoBuildRsNetwork, ghaCurlPipeShell, dockerfileCurlPipeShell, };
|
|
31
|
+
export { highEntropyLiteral, bidiControlChar, homoglyphIdentifier, longLine, encodedArrayFingerprint, decodeThenExec, dynamicExecNonLiteral, networkThenExec, deserializerUntrusted, suspiciousIoCluster, npmC2Dropper, stringArrayDecoder, shellUntrustedInput, libraryLoadNonLiteral, manifestInstallScript, pythonSetupSideEffect, perlMakefileSideEffect, cargoBuildRsNetwork, ghaCurlPipeShell, dockerfileCurlPipeShell, };
|
|
31
32
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,wBAAgB,gBAAgB,IAAI,SAAS,QAAQ,EAAE,CAEtD;AA+BD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,QAAQ,EACR,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,GACxB,CAAC"}
|
package/dist/detectors/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import { suspiciousIoCluster } from "./suspicious-io-cluster.js";
|
|
|
21
21
|
import { stringArrayDecoder } from "./string-array-decoder.js";
|
|
22
22
|
import { shellUntrustedInput } from "./shell-untrusted-input.js";
|
|
23
23
|
import { libraryLoadNonLiteral } from "./library-load-non-literal.js";
|
|
24
|
+
import { npmC2Dropper } from "./npm-c2-dropper.js";
|
|
24
25
|
// Manifest — ecosystem-specific detectors
|
|
25
26
|
import { manifestInstallScript } from "./manifest-install-script.js";
|
|
26
27
|
import { pythonSetupSideEffect } from "./python-setup-side-effect.js";
|
|
@@ -44,6 +45,7 @@ const DEFAULTS = Object.freeze([
|
|
|
44
45
|
dynamicExecNonLiteral,
|
|
45
46
|
deserializerUntrusted,
|
|
46
47
|
suspiciousIoCluster,
|
|
48
|
+
npmC2Dropper,
|
|
47
49
|
stringArrayDecoder,
|
|
48
50
|
shellUntrustedInput,
|
|
49
51
|
libraryLoadNonLiteral,
|
|
@@ -56,5 +58,5 @@ const DEFAULTS = Object.freeze([
|
|
|
56
58
|
dockerfileCurlPipeShell,
|
|
57
59
|
]);
|
|
58
60
|
// Named re-exports for tests and advanced consumers.
|
|
59
|
-
export { highEntropyLiteral, bidiControlChar, homoglyphIdentifier, longLine, encodedArrayFingerprint, decodeThenExec, dynamicExecNonLiteral, networkThenExec, deserializerUntrusted, suspiciousIoCluster, stringArrayDecoder, shellUntrustedInput, libraryLoadNonLiteral, manifestInstallScript, pythonSetupSideEffect, perlMakefileSideEffect, cargoBuildRsNetwork, ghaCurlPipeShell, dockerfileCurlPipeShell, };
|
|
61
|
+
export { highEntropyLiteral, bidiControlChar, homoglyphIdentifier, longLine, encodedArrayFingerprint, decodeThenExec, dynamicExecNonLiteral, networkThenExec, deserializerUntrusted, suspiciousIoCluster, npmC2Dropper, stringArrayDecoder, shellUntrustedInput, libraryLoadNonLiteral, manifestInstallScript, pythonSetupSideEffect, perlMakefileSideEffect, cargoBuildRsNetwork, ghaCurlPipeShell, dockerfileCurlPipeShell, };
|
|
60
62
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,6CAA6C;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,6CAA6C;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,6CAA6C;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,6CAA6C;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,0CAA0C;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,QAAQ,GAAwB,MAAM,CAAC,MAAM,CAAC;IAClD,UAAU;IACV,kBAAkB;IAClB,eAAe;IACf,mBAAmB;IACnB,QAAQ;IACR,uBAAuB;IAEvB,UAAU;IACV,cAAc;IACd,eAAe;IACf,qBAAqB;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,YAAY;IACZ,kBAAkB;IAClB,mBAAmB;IACnB,qBAAqB;IAErB,WAAW;IACX,qBAAqB;IACrB,qBAAqB;IACrB,sBAAsB;IACtB,mBAAmB;IACnB,gBAAgB;IAChB,uBAAuB;CACxB,CAAC,CAAC;AAEH,qDAAqD;AACrD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,QAAQ,EACR,uBAAuB,EACvB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,GACxB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.npm-c2-dropper — Layer B/package malware heuristic.
|
|
3
|
+
*
|
|
4
|
+
* Flags the combined shape used by npm C2 droppers: package code polls a C2
|
|
5
|
+
* API, decrypts staged content, writes it to disk, marks it executable, and
|
|
6
|
+
* launches it with Node or a child process. Each individual API is common;
|
|
7
|
+
* the cluster is the signal.
|
|
8
|
+
*/
|
|
9
|
+
import type { Detector } from "../types.js";
|
|
10
|
+
export declare const npmC2Dropper: Detector;
|
|
11
|
+
//# sourceMappingURL=npm-c2-dropper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-c2-dropper.d.ts","sourceRoot":"","sources":["../../src/detectors/npm-c2-dropper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAelE,eAAO,MAAM,YAAY,EAAE,QAuD1B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* obf.npm-c2-dropper — Layer B/package malware heuristic.
|
|
3
|
+
*
|
|
4
|
+
* Flags the combined shape used by npm C2 droppers: package code polls a C2
|
|
5
|
+
* API, decrypts staged content, writes it to disk, marks it executable, and
|
|
6
|
+
* launches it with Node or a child process. Each individual API is common;
|
|
7
|
+
* the cluster is the signal.
|
|
8
|
+
*/
|
|
9
|
+
import { lineAtOffset, MAX_SOURCE_BYTES } from "../internal/patterns.js";
|
|
10
|
+
import { truncateSnippet } from "../internal/text.js";
|
|
11
|
+
const JS_LIKE = new Set(["javascript", "typescript"]);
|
|
12
|
+
const C2_RE = /(?:slack\.com|conversations\.history|auth\.test|\bAuthorization\s*:\s*["']Bearer\s+|\bxox[abprs]-)/;
|
|
13
|
+
const CRYPTO_RE = /(?:AES-GCM|PBKDF2|subtle|\.decrypt\s*\(|deriveKey\s*\(|importKey\s*\()/;
|
|
14
|
+
const WRITE_RE = /\bwriteFileSync\s*\(/;
|
|
15
|
+
const CHMOD_RE = /\bchmodSync\s*\(/;
|
|
16
|
+
const CHILD_PROCESS_RE = /(?:\bspawn\s*[:=,}]|\bexecSync\s*[:=,}]|\bchild_process\b|\bprocess\.execPath\b|\b\.unref\s*\()/;
|
|
17
|
+
const SELF_DELETE_RE = /\bunlinkSync\s*\(\s*__filename\b/;
|
|
18
|
+
export const npmC2Dropper = {
|
|
19
|
+
id: "obf.npm-c2-dropper",
|
|
20
|
+
docsUrl: "https://github.com/bytebardorg/obfuscan/blob/main/docs/detectors.md#obfnpm-c2-dropper",
|
|
21
|
+
applies(ctx) {
|
|
22
|
+
return (ctx.source.length > 0 &&
|
|
23
|
+
ctx.source.length < MAX_SOURCE_BYTES &&
|
|
24
|
+
(ctx.languageId === null || JS_LIKE.has(ctx.languageId)));
|
|
25
|
+
},
|
|
26
|
+
run(ctx) {
|
|
27
|
+
const src = ctx.source;
|
|
28
|
+
const c2 = C2_RE.exec(src);
|
|
29
|
+
if (!c2)
|
|
30
|
+
return [];
|
|
31
|
+
const crypto = CRYPTO_RE.exec(src);
|
|
32
|
+
if (!crypto)
|
|
33
|
+
return [];
|
|
34
|
+
const write = WRITE_RE.exec(src);
|
|
35
|
+
const chmod = CHMOD_RE.exec(src);
|
|
36
|
+
const child = CHILD_PROCESS_RE.exec(src);
|
|
37
|
+
const selfDelete = SELF_DELETE_RE.exec(src);
|
|
38
|
+
if (!write || !chmod || !child)
|
|
39
|
+
return [];
|
|
40
|
+
const offset = Math.min(c2.index, crypto.index, write.index, chmod.index, child.index, selfDelete?.index ?? Number.POSITIVE_INFINITY);
|
|
41
|
+
return [{
|
|
42
|
+
ruleId: npmC2Dropper.id,
|
|
43
|
+
severity: "block",
|
|
44
|
+
score: 10,
|
|
45
|
+
file: ctx.path,
|
|
46
|
+
line: lineAtOffset(src, offset),
|
|
47
|
+
snippet: truncateSnippet(src.slice(offset, offset + 200)),
|
|
48
|
+
reason: `JavaScript package contains C2 polling, decrypt-stage, write/chmod, ` +
|
|
49
|
+
`and child-process launch signals. This matches npm command-and-control dropper behavior.`,
|
|
50
|
+
evidence: {
|
|
51
|
+
c2: c2[0],
|
|
52
|
+
crypto: crypto[0],
|
|
53
|
+
writesFile: true,
|
|
54
|
+
chmodsFile: true,
|
|
55
|
+
launchesChildProcess: true,
|
|
56
|
+
selfDelete: !!selfDelete,
|
|
57
|
+
},
|
|
58
|
+
}];
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=npm-c2-dropper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-c2-dropper.js","sourceRoot":"","sources":["../../src/detectors/npm-c2-dropper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAEtD,MAAM,KAAK,GACT,oGAAoG,CAAC;AACvG,MAAM,SAAS,GAAG,wEAAwE,CAAC;AAC3F,MAAM,QAAQ,GAAG,sBAAsB,CAAC;AACxC,MAAM,QAAQ,GAAG,kBAAkB,CAAC;AACpC,MAAM,gBAAgB,GACpB,iGAAiG,CAAC;AACpG,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAE1D,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,EAAE,EAAE,oBAAoB;IACxB,OAAO,EAAE,uFAAuF;IAEhG,OAAO,CAAC,GAAgB;QACtB,OAAO,CACL,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,gBAAgB;YACpC,CAAC,GAAG,CAAC,UAAU,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CACzD,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,GAAgB;QAClB,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC;QACvB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,CAAC;QAEnB,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEvB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QAE1C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,EAAE,CAAC,KAAK,EACR,MAAM,CAAC,KAAK,EACZ,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,KAAK,EACX,UAAU,EAAE,KAAK,IAAI,MAAM,CAAC,iBAAiB,CAC9C,CAAC;QAEF,OAAO,CAAC;gBACN,MAAM,EAAE,YAAY,CAAC,EAAE;gBACvB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,EAAE;gBACT,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,IAAI,EAAE,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC;gBAC/B,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC;gBACzD,MAAM,EACJ,sEAAsE;oBACtE,0FAA0F;gBAC5F,QAAQ,EAAE;oBACR,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;oBACT,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;oBACjB,UAAU,EAAE,IAAI;oBAChB,UAAU,EAAE,IAAI;oBAChB,oBAAoB,EAAE,IAAI;oBAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;iBACzB;aACF,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -24,7 +24,7 @@ function compile(config) {
|
|
|
24
24
|
cache.set(config, null);
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
|
-
const alt = namedCallAlternation(list);
|
|
27
|
+
const alt = namedCallAlternation(list, { allowUnsafeBareTails: true });
|
|
28
28
|
// Capture sink + the first 80 chars of arguments
|
|
29
29
|
const re = new RegExp(`(?:^|[^A-Za-z0-9_$])((?:${alt}))\\s*\\(([^)\\n]{0,200})`, "g");
|
|
30
30
|
cache.set(config, re);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-untrusted-input.js","sourceRoot":"","sources":["../../src/detectors/shell-untrusted-input.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,4DAA4D;AAC5D,+CAA+C;AAC/C,mCAAmC;AACnC,kDAAkD;AAClD,8BAA8B;AAC9B,2DAA2D;AAC3D,8CAA8C;AAC9C,MAAM,cAAc,GAClB,mGAAmG,CAAC;AAEtG,MAAM,KAAK,GAAG,IAAI,OAAO,EAAiC,CAAC;AAE3D,SAAS,OAAO,CAAC,MAAsB;IACrC,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"shell-untrusted-input.js","sourceRoot":"","sources":["../../src/detectors/shell-untrusted-input.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,9 @@ export declare function escapeRegex(s: string): string;
|
|
|
31
31
|
*
|
|
32
32
|
* Returns an inner alternation suitable for inclusion in a larger pattern.
|
|
33
33
|
*/
|
|
34
|
-
export declare function namedCallAlternation(names: readonly string[]
|
|
34
|
+
export declare function namedCallAlternation(names: readonly string[], options?: {
|
|
35
|
+
allowUnsafeBareTails?: boolean;
|
|
36
|
+
}): string;
|
|
35
37
|
/**
|
|
36
38
|
* 1-based line number for a 0-based character offset.
|
|
37
39
|
* Used by every detector to report source positions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/internal/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C;
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/internal/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C;AA8CD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE;IAAE,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/C,MAAM,CAwCR;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,mEAAmE;AACnE,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,UAAY,CAAC"}
|
|
@@ -23,6 +23,49 @@
|
|
|
23
23
|
export function escapeRegex(s) {
|
|
24
24
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
25
25
|
}
|
|
26
|
+
const UNSAFE_BARE_TAILS = new Set([
|
|
27
|
+
"call",
|
|
28
|
+
"compile",
|
|
29
|
+
"constructor",
|
|
30
|
+
"decode",
|
|
31
|
+
"do",
|
|
32
|
+
"exec",
|
|
33
|
+
"execute",
|
|
34
|
+
"from",
|
|
35
|
+
"get",
|
|
36
|
+
"import",
|
|
37
|
+
"invoke",
|
|
38
|
+
"load",
|
|
39
|
+
"new",
|
|
40
|
+
"open",
|
|
41
|
+
"parse",
|
|
42
|
+
"post",
|
|
43
|
+
"request",
|
|
44
|
+
"require",
|
|
45
|
+
"run",
|
|
46
|
+
"send",
|
|
47
|
+
"source",
|
|
48
|
+
"spawn",
|
|
49
|
+
"start",
|
|
50
|
+
"system",
|
|
51
|
+
"use",
|
|
52
|
+
]);
|
|
53
|
+
function isUnsafeBareTail(tail) {
|
|
54
|
+
return UNSAFE_BARE_TAILS.has(tail.toLowerCase());
|
|
55
|
+
}
|
|
56
|
+
function qualifiedSuffix(raw) {
|
|
57
|
+
const parts = raw.split(/(\.|::)/);
|
|
58
|
+
const segments = parts.filter((_, i) => i % 2 === 0 && parts[i] !== "");
|
|
59
|
+
const separators = parts.filter((_, i) => i % 2 === 1);
|
|
60
|
+
if (segments.length < 2 || separators.length < 1)
|
|
61
|
+
return null;
|
|
62
|
+
const a = segments[segments.length - 2];
|
|
63
|
+
const b = segments[segments.length - 1];
|
|
64
|
+
const sep = separators[separators.length - 1];
|
|
65
|
+
if (!a || !b || !sep)
|
|
66
|
+
return null;
|
|
67
|
+
return `${a}${sep}${b}`;
|
|
68
|
+
}
|
|
26
69
|
/**
|
|
27
70
|
* Build a regex source matching any of the configured names as a function
|
|
28
71
|
* call. Accepts qualified names — for `base64.b64decode` the regex matches
|
|
@@ -33,7 +76,7 @@ export function escapeRegex(s) {
|
|
|
33
76
|
*
|
|
34
77
|
* Returns an inner alternation suitable for inclusion in a larger pattern.
|
|
35
78
|
*/
|
|
36
|
-
export function namedCallAlternation(names) {
|
|
79
|
+
export function namedCallAlternation(names, options = {}) {
|
|
37
80
|
const alts = [];
|
|
38
81
|
for (const raw of names) {
|
|
39
82
|
if (!raw)
|
|
@@ -55,7 +98,15 @@ export function namedCallAlternation(names) {
|
|
|
55
98
|
const tail = parts[parts.length - 1] ?? raw;
|
|
56
99
|
alts.push(escapeRegex(raw));
|
|
57
100
|
if (parts.length > 1 && tail !== raw && tail.length > 0) {
|
|
58
|
-
|
|
101
|
+
if (isUnsafeBareTail(tail) && !options.allowUnsafeBareTails) {
|
|
102
|
+
const suffix = qualifiedSuffix(raw);
|
|
103
|
+
if (suffix && suffix !== raw)
|
|
104
|
+
alts.push(escapeRegex(suffix));
|
|
105
|
+
alts.push(`(?:\\.|::)${escapeRegex(tail)}`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
alts.push(escapeRegex(tail));
|
|
109
|
+
}
|
|
59
110
|
}
|
|
60
111
|
}
|
|
61
112
|
// Deduplicate while preserving order
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/internal/patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/internal/patterns.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obfuscan/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Detect obfuscated code and likely backdoors in pull-request diffs. Multi-language. Diff-aware. Pure TypeScript.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/ByteBardOrg/obfuscan",
|