wormclaude 1.0.191 → 1.0.193
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/dist/commands.js +1 -0
- package/dist/jwt.js +102 -0
- package/dist/theme.js +1 -1
- package/dist/tools.js +41 -3
- package/dist/tui.js +10 -0
- package/package.json +1 -1
package/dist/commands.js
CHANGED
|
@@ -61,6 +61,7 @@ export const COMMANDS = [
|
|
|
61
61
|
{ name: '/report', desc: 'son taramadan profesyonel pentest raporu üret (CVSS/etki/çözüm, dosyaya yazar)' },
|
|
62
62
|
{ name: '/fullscan', desc: '[seviye 3+] tam kapsamlı DETERMİNİSTİK tarama: recon+XSS+SQLi tek komutta: /fullscan <hedef>' },
|
|
63
63
|
{ name: '/audit', desc: 'kaynak kod güvenlik denetimi (SAST — sır/açık/CVE, yerel): /audit [klasör]' },
|
|
64
|
+
{ name: '/jwt', desc: 'JWT token güvenlik analizi (alg=none/zayıf-secret/expiry/claim, yerel): /jwt <token>' },
|
|
64
65
|
{ name: '/exploit', desc: 'yetkili testte doğrulanmış PoC üret: /exploit <cve|açıklama>' },
|
|
65
66
|
{ name: '/harden', desc: 'savunma çıktısı üret (YARA/Sigma + yama önerisi): /harden <hedef|tehdit>' },
|
|
66
67
|
{ name: '/phish', desc: '[yetkili] phishing simülasyonu: pretext + e-posta şablonu: /phish <hedef|senaryo>' },
|
package/dist/jwt.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// JWT güvenlik analizi — token decode + zafiyet tespiti. YEREL (ağ yok, deterministik).
|
|
2
|
+
// alg=none bypass, zayıf HMAC secret (sözlük denemesi), expiry, hassas claim, alg-confusion.
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
// Yaygın/varsayılan JWT secret'ları (zayıf imza tespiti için — gerçek kırma değil, hızlı kontrol)
|
|
5
|
+
const COMMON_SECRETS = [
|
|
6
|
+
'secret', 'password', '123456', 'changeme', 'jwt_secret', 'jwtsecret', 'your-256-bit-secret',
|
|
7
|
+
'your_jwt_secret', 'key', 'admin', 'test', 'supersecret', 'super_secret', 'secretkey', 'secret_key',
|
|
8
|
+
'privatekey', 'private_key', 'token', 'qwerty', 'letmein', 'mysecret', 'mysecretkey', 's3cr3t',
|
|
9
|
+
'P@ssw0rd', 'default', 'dev', 'development', 'prod', 'production', 'shhhh', 'access_secret',
|
|
10
|
+
'refresh_secret', 'auth_secret', 'app_secret', 'jwtkey', 'HS256', 'null', '0', 'password123',
|
|
11
|
+
];
|
|
12
|
+
function _b64urlToBuf(s) {
|
|
13
|
+
s = s.replace(/-/g, '+').replace(/_/g, '/');
|
|
14
|
+
while (s.length % 4)
|
|
15
|
+
s += '=';
|
|
16
|
+
return Buffer.from(s, 'base64');
|
|
17
|
+
}
|
|
18
|
+
function _b64urlJson(s) { return JSON.parse(_b64urlToBuf(s).toString('utf8')); }
|
|
19
|
+
const HMAC_ALG = { HS256: 'sha256', HS384: 'sha384', HS512: 'sha512' };
|
|
20
|
+
function _tryCrack(alg, signingInput, sigB64url) {
|
|
21
|
+
const h = HMAC_ALG[alg.toUpperCase()];
|
|
22
|
+
if (!h)
|
|
23
|
+
return null;
|
|
24
|
+
for (const sec of COMMON_SECRETS) {
|
|
25
|
+
const mac = crypto.createHmac(h, sec).update(signingInput).digest('base64')
|
|
26
|
+
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
27
|
+
if (mac === sigB64url)
|
|
28
|
+
return sec;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const SENSITIVE_CLAIM = /(pass|pwd|şifre|sifre|secret|ssn|credit|card|cvv|api[_-]?key|private)/i;
|
|
33
|
+
export function analyzeJwt(token) {
|
|
34
|
+
const findings = [];
|
|
35
|
+
const t = (token || '').trim().replace(/^Bearer\s+/i, '');
|
|
36
|
+
const parts = t.split('.');
|
|
37
|
+
if (parts.length < 2)
|
|
38
|
+
return { ok: false, findings: [], error: 'Geçerli bir JWT değil (nokta-ayrımlı 2-3 parça bekleniyor).' };
|
|
39
|
+
let header, payload;
|
|
40
|
+
try {
|
|
41
|
+
header = _b64urlJson(parts[0]);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return { ok: false, findings: [], error: 'JWT header decode edilemedi.' };
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
payload = _b64urlJson(parts[1]);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return { ok: false, findings: [], error: 'JWT payload decode edilemedi.' };
|
|
51
|
+
}
|
|
52
|
+
const alg = String(header?.alg || '').trim();
|
|
53
|
+
const sig = parts[2] || '';
|
|
54
|
+
// 1) alg=none → imza yok = tam bypass
|
|
55
|
+
if (/^none$/i.test(alg) || (!sig && parts.length === 3)) {
|
|
56
|
+
findings.push({ severity: 'critical', title: 'alg=none / imza yok', cwe: 'CWE-347',
|
|
57
|
+
detail: 'Token imzasız kabul ediliyorsa saldırgan payload\'ı (rol/kullanıcı) serbestçe değiştirir. Sunucu alg=none\'ı REDDETMELİ; izin verilen algoritmalar allow-list olmalı.' });
|
|
58
|
+
}
|
|
59
|
+
// 2) HMAC zayıf secret denemesi
|
|
60
|
+
if (HMAC_ALG[alg.toUpperCase()] && sig) {
|
|
61
|
+
const cracked = _tryCrack(alg, parts[0] + '.' + parts[1], sig);
|
|
62
|
+
if (cracked != null) {
|
|
63
|
+
findings.push({ severity: 'critical', title: `Zayıf HMAC secret KIRILDI: "${cracked}"`, cwe: 'CWE-326',
|
|
64
|
+
detail: 'İmza zayıf/varsayılan bir secret ile üretilmiş. Saldırgan bu secret ile GEÇERLI token forge eder (herhangi bir kullanıcı/rol). Güçlü, rastgele 256-bit+ secret kullan ve rotate et.' });
|
|
65
|
+
// crackedSecret döndür
|
|
66
|
+
findings._cracked = cracked;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// 3) RS/ES → alg-confusion notu
|
|
70
|
+
if (/^(RS|ES|PS)/i.test(alg)) {
|
|
71
|
+
findings.push({ severity: 'info', title: `Asimetrik imza (${alg}) — alg-confusion riski`, cwe: 'CWE-347',
|
|
72
|
+
detail: 'Sunucu algoritmayı sabitlemiyorsa, public key\'i HMAC secret\'ı olarak kullanan alg-confusion (RS256→HS256) saldırısı denenebilir. Sunucu beklenen algoritmayı KATI doğrulamalı.' });
|
|
73
|
+
}
|
|
74
|
+
// 4) expiry / nbf
|
|
75
|
+
const now = Math.floor(Date.now() / 1000);
|
|
76
|
+
if (payload?.exp == null) {
|
|
77
|
+
findings.push({ severity: 'low', title: 'exp (son kullanma) yok', cwe: 'CWE-613',
|
|
78
|
+
detail: 'Token süresiz geçerli → çalınırsa kalıcı erişim. Kısa exp + refresh token kullan.' });
|
|
79
|
+
}
|
|
80
|
+
else if (Number(payload.exp) < now) {
|
|
81
|
+
findings.push({ severity: 'info', title: 'Token süresi DOLMUŞ', detail: `exp=${new Date(Number(payload.exp) * 1000).toISOString()} (geçmiş). Sunucu expired token\'ı reddetmeli.` });
|
|
82
|
+
}
|
|
83
|
+
// 5) hassas claim'ler
|
|
84
|
+
for (const k of Object.keys(payload || {})) {
|
|
85
|
+
if (SENSITIVE_CLAIM.test(k)) {
|
|
86
|
+
findings.push({ severity: 'medium', title: `Hassas claim payload'da: "${k}"`, cwe: 'CWE-522',
|
|
87
|
+
detail: 'JWT payload base64\'tür, ŞIFRELI DEĞIL — herkes okuyabilir. Parola/sır/PII token içine konmamalı.' });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 6) privilege claim notu (tampering hedefi)
|
|
91
|
+
const privKeys = Object.keys(payload || {}).filter((k) => /^(role|roles|admin|is_admin|scope|scopes|permissions|priv|group)$/i.test(k));
|
|
92
|
+
if (privKeys.length) {
|
|
93
|
+
findings.push({ severity: 'info', title: `Yetki claim'leri: ${privKeys.join(', ')}`,
|
|
94
|
+
detail: 'Sunucu imzayı düzgün doğrulamıyorsa bu alanlar yetki yükseltme için manipüle edilir (alg=none / zayıf-secret ile birlikte kritik).' });
|
|
95
|
+
}
|
|
96
|
+
if (!findings.length)
|
|
97
|
+
findings.push({ severity: 'info', title: 'Belirgin JWT zafiyeti yok', detail: 'alg sağlam, secret yaygın listede değil, exp var, hassas claim yok. (Derin secret-kırma için hashcat -m 16500 öner.)' });
|
|
98
|
+
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
99
|
+
findings.sort((a, b) => order[a.severity] - order[b.severity]);
|
|
100
|
+
const cracked = findings._cracked;
|
|
101
|
+
return { ok: true, header, payload, findings, crackedSecret: cracked };
|
|
102
|
+
}
|
package/dist/theme.js
CHANGED
package/dist/tools.js
CHANGED
|
@@ -230,7 +230,7 @@ export const toolSchemas = [
|
|
|
230
230
|
parameters: {
|
|
231
231
|
type: 'object',
|
|
232
232
|
properties: {
|
|
233
|
-
tool: { type: 'string', enum: ['full', 'recon', 'scan', 'xss', 'sqli', 'dirscan', 'idor', 'portscan', 'osint'], description: 'full → tam kapsamlı web
|
|
233
|
+
tool: { type: 'string', enum: ['full', 'recon', 'scan', 'xss', 'sqli', 'dirscan', 'idor', 'portscan', 'osint', 'cloudscan'], description: 'full → tam kapsamlı web taraması; recon/scan/dirscan/portscan/osint/cloudscan → domain/host/şirket; xss/sqli/idor → parameterized URL. portscan = TCP port/servis. osint = DNS + e-posta güvenliği (SPF/DMARC). cloudscan = açık bulut bucket keşfi (S3/GCP/Azure — şirket/domain adından aday üretip public erişim test eder; "bucket tara"/"s3 tara"/"açık depolama"/"cloud" denince)' },
|
|
234
234
|
target: { type: 'string', description: 'Domain for recon/scan/dirscan (example.com) OR parameterized URL for xss/sqli (https://example.com/p?id=1)' },
|
|
235
235
|
cookie: { type: 'string', description: 'Optional. Session cookie for AUTHENTICATED / behind-login scanning, e.g. "sessionid=abc123; csrftoken=xyz". The user copies it from their logged-in browser (DevTools → Application → Cookies, or the Cookie request header). Sent only to the target from the user IP — never stored on the server. Provide it whenever the user wants to scan pages behind a login.' },
|
|
236
236
|
auth_header: { type: 'string', description: 'Optional. Authorization header value for token-based authenticated scanning, e.g. "Bearer eyJhbGci..." or "Basic dXNlcjpwYXNz". Use instead of / together with cookie when the site authenticates via a token header.' },
|
|
@@ -256,6 +256,20 @@ export const toolSchemas = [
|
|
|
256
256
|
},
|
|
257
257
|
},
|
|
258
258
|
},
|
|
259
|
+
{
|
|
260
|
+
type: 'function',
|
|
261
|
+
function: {
|
|
262
|
+
name: 'JwtAudit',
|
|
263
|
+
description: "Analyze a JWT (JSON Web Token) for security weaknesses, locally. Use when the user pastes/asks about a token (\"bu jwt güvenli mi\", \"token analiz et\", \"jwt incele\", \"bu token'da açık var mı\"). Decodes header+payload and checks: alg=none bypass, weak/default HMAC secret (dictionary test), missing/expired exp, sensitive claims in payload, alg-confusion (RS256→HS256), privilege claims. Fully LOCAL — token never leaves the machine. Returns decoded claims + findings.",
|
|
264
|
+
parameters: {
|
|
265
|
+
type: 'object',
|
|
266
|
+
properties: {
|
|
267
|
+
token: { type: 'string', description: 'The JWT string (eyJ...eyJ...sig). "Bearer " prefix is stripped automatically.' },
|
|
268
|
+
},
|
|
269
|
+
required: ['token'],
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
259
273
|
{
|
|
260
274
|
type: 'function',
|
|
261
275
|
function: {
|
|
@@ -640,7 +654,7 @@ const computerToolSchemas = [
|
|
|
640
654
|
// çağırıp işi yapar, planı ekrana basmaz. (Gerekirse buraya yeni araç eklenir.)
|
|
641
655
|
const CORE_TOOLS = new Set([
|
|
642
656
|
'Bash', 'PowerShell', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
|
|
643
|
-
'WebFetch', 'WebSearch', 'Sleep', 'SecurityScan', 'CodeAudit',
|
|
657
|
+
'WebFetch', 'WebSearch', 'Sleep', 'SecurityScan', 'CodeAudit', 'JwtAudit',
|
|
644
658
|
'TaskOutput', // uzun komutları arka planda çalıştırıp bitişini yoklamak için (run_in_background)
|
|
645
659
|
'AskUserQuestion', // GERİ EKLENDİ: FLAT şema (options: string[]) ile 32B temiz çağrı üretiyor
|
|
646
660
|
// (test edildi). Eski degenere NESTED şemadandı ([{label,description}]). Handler string→{label}
|
|
@@ -669,6 +683,7 @@ const TOOL_META = {
|
|
|
669
683
|
Scroll: { needsPermission: true, validate: (a) => (a && a.direction ? null : 'direction gerekli') },
|
|
670
684
|
WebSearch: { readOnly: true, validate: (a) => (a && a.query ? null : 'query gerekli') },
|
|
671
685
|
CodeAudit: { readOnly: true, concurrencySafe: true },
|
|
686
|
+
JwtAudit: { readOnly: true, concurrencySafe: true, validate: (a) => (a && a.token ? null : 'token gerekli') },
|
|
672
687
|
TodoWrite: { readOnly: true, validate: (a) => (a && Array.isArray(a.todos) ? null : 'todos dizisi gerekli') },
|
|
673
688
|
SaveMemory: { validate: (a) => (a && a.fact && String(a.fact).trim() ? null : 'fact gerekli') },
|
|
674
689
|
PowerShell: { needsPermission: true, validate: (a) => (a && a.command ? null : 'command gerekli') },
|
|
@@ -752,7 +767,7 @@ async function execOne(call, hooks) {
|
|
|
752
767
|
if (call.name === 'SecurityScan') {
|
|
753
768
|
let tool = String(args?.tool || '').toLowerCase().trim();
|
|
754
769
|
const target = String(args?.target || '').trim();
|
|
755
|
-
if (!['recon', 'scan', 'xss', 'sqli', 'dirscan', 'idor', 'portscan', 'osint', 'full', 'fullscan'].includes(tool) || !target) {
|
|
770
|
+
if (!['recon', 'scan', 'xss', 'sqli', 'dirscan', 'idor', 'portscan', 'osint', 'cloud', 'cloudscan', 'full', 'fullscan'].includes(tool) || !target) {
|
|
756
771
|
return { ok: false, output: 'SecurityScan: tool (recon|scan|xss|sqli|dirscan|full) ve target gerekli.', args };
|
|
757
772
|
}
|
|
758
773
|
if (tool === 'scan')
|
|
@@ -965,6 +980,27 @@ async function execOne(call, hooks) {
|
|
|
965
980
|
return { ok: false, output: 'Kod denetimi hatası: ' + (e?.message || e), args };
|
|
966
981
|
}
|
|
967
982
|
}
|
|
983
|
+
// 3.46) JWT güvenlik analizi (YEREL; token sunucuya gitmez)
|
|
984
|
+
if (call.name === 'JwtAudit') {
|
|
985
|
+
try {
|
|
986
|
+
const { analyzeJwt } = await import('./jwt.js');
|
|
987
|
+
const r = analyzeJwt(String(args?.token || ''));
|
|
988
|
+
if (!r.ok)
|
|
989
|
+
return { ok: false, output: 'JWT analizi: ' + (r.error || 'çözümlenemedi'), args };
|
|
990
|
+
let out = 'JWT analizi\n';
|
|
991
|
+
out += 'header: ' + JSON.stringify(r.header) + '\n';
|
|
992
|
+
out += 'payload: ' + JSON.stringify(r.payload) + '\n';
|
|
993
|
+
if (r.crackedSecret != null)
|
|
994
|
+
out += `⚠ HMAC secret KIRILDI: "${r.crackedSecret}"\n`;
|
|
995
|
+
out += `${r.findings.length} bulgu:\n`;
|
|
996
|
+
out += r.findings.map((f) => `[${f.severity.toUpperCase()}]${f.cwe ? ' ' + f.cwe : ''} ${f.title}\n ${f.detail}`).join('\n');
|
|
997
|
+
out += '\n[jwt-done] JWT analizi bitti. Bulguları severity-sıralı özetle; payload base64\'tür (şifreli değil), bunu kullanıcıya hatırlat.';
|
|
998
|
+
return { ok: true, output: out, args };
|
|
999
|
+
}
|
|
1000
|
+
catch (e) {
|
|
1001
|
+
return { ok: false, output: 'JWT analizi hatası: ' + (e?.message || e), args };
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
968
1004
|
// 3.5) Komut güvenliği (Bash/PowerShell) — cmdsec: deny→blokla, allow→izinsiz, confirm→izin akışı
|
|
969
1005
|
if ((call.name === 'Bash' || call.name === 'PowerShell') && args && args.command) {
|
|
970
1006
|
const chk = checkCommand(String(args.command), { shell: call.name === 'PowerShell' ? 'powershell' : 'bash' });
|
|
@@ -1117,6 +1153,8 @@ export function toolLabel(name, args) {
|
|
|
1117
1153
|
return `🔍 Web arandı: ${String(args.query).slice(0, 50)}`;
|
|
1118
1154
|
if (name === 'CodeAudit')
|
|
1119
1155
|
return `🛡️ Kod denetimi (SAST): ${String(args.path || '.').slice(0, 50)}`;
|
|
1156
|
+
if (name === 'JwtAudit')
|
|
1157
|
+
return `🎫 JWT analizi`;
|
|
1120
1158
|
if (name === 'TodoWrite')
|
|
1121
1159
|
return `TodoWrite(${(args.todos || []).length} öğe)`;
|
|
1122
1160
|
if (name === 'PowerShell')
|
package/dist/tui.js
CHANGED
|
@@ -842,6 +842,16 @@ export async function runTui() {
|
|
|
842
842
|
runTurn(`CodeAudit aracıyla şu yolu kaynak kod güvenliği için tara (SAST): ${a}. Bulguları severity-sıralı özetle + öncelikli düzeltmeler.`, v);
|
|
843
843
|
return;
|
|
844
844
|
}
|
|
845
|
+
// /jwt — JWT token güvenlik analizi (yerel); modele JwtAudit çağırt
|
|
846
|
+
if (tok === '/jwt') {
|
|
847
|
+
const a = v.slice(tok.length).trim();
|
|
848
|
+
if (!a) {
|
|
849
|
+
printItem({ kind: 'note', text: 'Kullanım: /jwt <token>' });
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
runTurn(`JwtAudit aracıyla şu JWT'yi güvenlik için analiz et: ${a}. Bulguları severity-sıralı özetle.`, v);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
845
855
|
// /exploit · /harden — aktif tarama değil, model-üretim (PoC / YARA-Sigma) → çerçeveli istemle modele
|
|
846
856
|
if (tok === '/exploit') {
|
|
847
857
|
const a = v.slice(tok.length).trim();
|