wormclaude 1.0.164 → 1.0.166

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 CHANGED
@@ -10,7 +10,7 @@ import * as usage from './usage.js';
10
10
  import { runCompact, contextPercent, autoCompactThreshold } from './compact.js';
11
11
  import { cmdDesc, setLang, saveLang, getLang } from './i18n.js';
12
12
  import { listCheckpoints, rewindLast, rewindTo, rewindAll } from './checkpoint.js';
13
- import { setPlanMode } from './tools.js';
13
+ import { setPlanMode, getBashCwd } from './tools.js';
14
14
  import { loadSkills, getSkills, getSkillsDir, installSkill, updateSkill, removeSkill, getRegistry } from './skills.js';
15
15
  import { getApprovedCommands, approveCommands, unapproveCommands, clearApproved } from './cmdsec.js';
16
16
  import { isLearnEnabled, setLearnEnabled, getLearnFile, getLearnCount } from './learn.js';
@@ -57,6 +57,8 @@ export const COMMANDS = [
57
57
  { name: '/scan', desc: '[seviye 3+] yetkili hedefte genel tarama (keşif+başlıklar): /scan <alan>' },
58
58
  { name: '/xss', desc: '[seviye 3+] yetkili hedefte XSS taraması (kendi motorumuz): /xss <url>' },
59
59
  { name: '/sqli', desc: '[seviye 3+] yetkili hedefte SQLi taraması (kendi motorumuz): /sqli <url>' },
60
+ { name: '/dirscan', desc: '[seviye 3+] dizin/içerik keşfi (yönetim/api/yedek/sızıntı yolları): /dirscan <alan>' },
61
+ { name: '/report', desc: 'son taramadan profesyonel pentest raporu üret (CVSS/etki/çözüm, dosyaya yazar)' },
60
62
  { name: '/fullscan', desc: '[seviye 3+] tam kapsamlı DETERMİNİSTİK tarama: recon+XSS+SQLi tek komutta: /fullscan <hedef>' },
61
63
  { name: '/exploit', desc: 'yetkili testte doğrulanmış PoC üret: /exploit <cve|açıklama>' },
62
64
  { name: '/harden', desc: 'savunma çıktısı üret (YARA/Sigma + yama önerisi): /harden <hedef|tehdit>' },
@@ -121,11 +123,11 @@ function tsStamp() {
121
123
  const tt = (en, tr) => (getLang() === 'tr' ? tr : en);
122
124
  const PT_LABELS_EN = {
123
125
  recon: 'Recon (subdomains + headers + exposure)', scan: 'General scan (recon)',
124
- xss: 'XSS scan', sqli: 'SQL injection scan',
126
+ xss: 'XSS scan', sqli: 'SQL injection scan', dirscan: 'Directory/content discovery',
125
127
  };
126
128
  const PT_LABELS_TR = {
127
129
  recon: 'Keşif (alt-alan + başlık + ifşa)', scan: 'Genel tarama (keşif)',
128
- xss: 'XSS taraması', sqli: 'SQL injection taraması',
130
+ xss: 'XSS taraması', sqli: 'SQL injection taraması', dirscan: 'Dizin/içerik keşfi',
129
131
  };
130
132
  const ptLabel = (tool) => (getLang() === 'tr' ? PT_LABELS_TR : PT_LABELS_EN)[tool] || tool;
131
133
  const PT_REASON_EN = {
@@ -151,8 +153,100 @@ const PT_REASON_TR = {
151
153
  upstream_error: 'Sunucuya ulaşılamadı.',
152
154
  };
153
155
  const ptReason = (r) => (getLang() === 'tr' ? PT_REASON_TR : PT_REASON_EN)[r] || r;
156
+ // ── Pentest RAPORU (Tier 3) — son taramanın GERÇEK bulgularından profesyonel rapor üretir.
157
+ // Uydurma YOK: bulgular motordan gelir; aşağıdaki harita yalnız etki/çözüm bilgisini ekler (statik, küratörlü).
158
+ let _lastScan = null;
159
+ export function setLastScan(target, findings) {
160
+ if (findings && findings.length)
161
+ _lastScan = { target, findings, ts: Date.now() };
162
+ }
163
+ // type → {başlık, CWE, etki, çözüm} (CWE-temelli küratörlü bilgi)
164
+ const _REMED = {
165
+ xss: { t: 'Cross-Site Scripting (XSS)', cwe: 'CWE-79', impact: 'Saldırgan kurbanın tarayıcısında script çalıştırır — oturum çalma, hesap ele geçirme, sayfa tahrifi.', fix: 'Çıktıyı bağlama göre encode et (HTML/JS/URL), CSP uygula, girdiyi doğrula; framework auto-escaping kullan.' },
166
+ sqli: { t: 'SQL Injection', cwe: 'CWE-89', impact: 'Veritabanı okuma/yazma, kimlik doğrulama atlama, tüm verinin sızması.', fix: 'Parametreli sorgu (prepared statement) kullan; ORM; girdi doğrulama; en-az-yetki DB kullanıcısı.' },
167
+ ssti: { t: 'Server-Side Template Injection', cwe: 'CWE-1336', impact: 'Şablon motorunda kod çalıştırma → çoğu zaman RCE.', fix: 'Kullanıcı girdisini şablona koyma; sandbox’lı motor; logicless şablon (Mustache).' },
168
+ lfi: { t: 'Local File Inclusion / Path Traversal', cwe: 'CWE-22', impact: 'Sunucu dosyalarını okuma (config, /etc/passwd), zincirle RCE.', fix: 'Dosya yolunu allowlist’le; ../ temizle; kullanıcı girdisini dosya yoluna koyma.' },
169
+ ssrf: { t: 'Server-Side Request Forgery', cwe: 'CWE-918', impact: 'İç servislere/metadata’ya (cloud) erişim, iç ağ tarama.', fix: 'Hedef host’u allowlist’le; iç IP’leri (169.254, 10.x, localhost) reddet; redirect takip etme.' },
170
+ 'cmd-injection': { t: 'Komut Enjeksiyonu', cwe: 'CWE-78', impact: 'Sunucuda işletim sistemi komutu çalıştırma → tam sistem ele geçirme.', fix: 'Shell çağırma; dil-içi API kullan; argümanları allowlist’le; kullanıcı girdisini komuta koyma.' },
171
+ 'nosql-injection': { t: 'NoSQL Injection', cwe: 'CWE-943', impact: 'Sorgu manipülasyonu, kimlik doğrulama atlama, veri sızması.', fix: 'Girdiyi tip-doğrula; operatör ($ne/$gt) enjeksiyonunu engelle; ODM güvenli bağlama.' },
172
+ 'open-redirect': { t: 'Açık Yönlendirme', cwe: 'CWE-601', impact: 'Oltalama/phishing — kullanıcı güvenilen alandan kötücül siteye yönlenir.', fix: 'Yönlendirme hedefini allowlist’le; harici URL’e doğrudan yönlendirme yapma.' },
173
+ crlf: { t: 'CRLF / HTTP Başlık Enjeksiyonu', cwe: 'CWE-113', impact: 'Başlık enjeksiyonu, önbellek zehirleme, oturum sabitleme.', fix: 'Yanıt başlığına giren girdiden CR/LF (%0d%0a) temizle.' },
174
+ 'graphql-introspection': { t: 'GraphQL Introspection Açık', cwe: 'CWE-200', impact: 'Tüm API şeması/gizli uçlar ifşa → saldırı yüzeyi haritalanır.', fix: 'Üretimde introspection’ı kapat; şema ifşasını sınırla.' },
175
+ path: { t: 'Açıkta Dizin/Dosya', cwe: 'CWE-538', impact: 'Hassas dosya/uç ifşası (kaynak, yedek, yönetim) → bilgi sızması.', fix: 'Hassas yolları kaldır/kısıtla; .git/.env vb. web kökünden çıkar; erişim kontrolü.' },
176
+ weak_headers: { t: 'Eksik Güvenlik Başlıkları', cwe: 'CWE-693', impact: 'Clickjacking/MIME-sniffing/MITM riskini artırır.', fix: 'CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy ekle.' },
177
+ cors: { t: 'CORS Yanlış Yapılandırması', cwe: 'CWE-942', impact: 'Kötücül site kullanıcı adına yetkili istek yapabilir, veri çalar.', fix: 'Origin’i allowlist’le; ACAO:* + credentials birlikte kullanma.' },
178
+ exposure: { t: 'Hassas Dosya İfşası', cwe: 'CWE-538', impact: 'Sır/yapılandırma sızması (.git/.env/yedek).', fix: 'Dosyaları web kökünden kaldır; erişimi engelle; sızan sırları rotate et.' },
179
+ subdomain_takeover: { t: 'Subdomain Takeover', cwe: 'CWE-350', impact: 'Saldırgan sahipsiz alt-alanı ele geçirir → phishing/çerez çalma.', fix: 'Kullanılmayan DNS kayıtlarını (CNAME) sil; 3.parti servisi geri talep et.' },
180
+ };
181
+ export function buildReport(scan) {
182
+ const sevRank = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
183
+ const fs2 = [...scan.findings].sort((a, b) => (sevRank[a.severity] ?? 9) - (sevRank[b.severity] ?? 9));
184
+ const cnt = (s) => scan.findings.filter((f) => f.severity === s).length;
185
+ const d = new Date(scan.ts);
186
+ const date = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
187
+ const L = getLang() === 'tr';
188
+ const out = [];
189
+ out.push(`# ${L ? 'Güvenlik Değerlendirme Raporu' : 'Security Assessment Report'} — ${scan.target}`);
190
+ out.push(`\n**${L ? 'Tarih' : 'Date'}:** ${date} · **${L ? 'Araç' : 'Tool'}:** WormClaude v2 · **${L ? 'Kapsam' : 'Scope'}:** ${scan.target} (${L ? 'yetkili' : 'authorized'})\n`);
191
+ out.push(`## ${L ? 'Yönetici Özeti' : 'Executive Summary'}`);
192
+ out.push(`${scan.findings.length} ${L ? 'bulgu' : 'findings'} — **High: ${cnt('high')}**, Medium: ${cnt('medium')}, Low: ${cnt('low')}, Info: ${cnt('info')}.`);
193
+ const top = fs2.filter((f) => ['high', 'medium'].includes(f.severity)).slice(0, 5).map((f) => (_REMED[f.type]?.t || f.type));
194
+ if (top.length)
195
+ out.push(`${L ? 'Öne çıkan riskler' : 'Key risks'}: ${[...new Set(top)].join(', ')}.`);
196
+ else
197
+ out.push(L ? 'Yüksek/orta seviye doğrulanmış bulgu yok; yüzey büyük ölçüde temiz görünüyor.' : 'No high/medium confirmed findings; surface appears largely clean.');
198
+ out.push(`\n## ${L ? 'Bulgular' : 'Findings'}`);
199
+ let n = 0;
200
+ for (const f of fs2) {
201
+ if (f.type === 'reflection')
202
+ continue;
203
+ n++;
204
+ const r = _REMED[f.type];
205
+ const sev = (f.severity || 'info').toUpperCase();
206
+ out.push(`\n### ${n}. [${sev}] ${r?.t || f.type}${(r?.cwe || f.cwe) ? ' (' + (r?.cwe || f.cwe) + ')' : ''}`);
207
+ if (f.url)
208
+ out.push(`- **${L ? 'Uç' : 'Endpoint'}:** ${f.url}${f.param ? ` (param: \`${f.param}\`)` : ''}`);
209
+ if (f.evidence)
210
+ out.push(`- **${L ? 'Kanıt' : 'Evidence'}:** ${f.evidence}`);
211
+ else if (f.missing)
212
+ out.push(`- **${L ? 'Eksik' : 'Missing'}:** ${(f.missing || []).join(', ')}`);
213
+ if (r) {
214
+ out.push(`- **${L ? 'Etki' : 'Impact'}:** ${r.impact}`);
215
+ out.push(`- **${L ? 'Çözüm' : 'Remediation'}:** ${r.fix}`);
216
+ }
217
+ }
218
+ if (!n)
219
+ out.push(L ? '_Raporlanacak bulgu yok._' : '_No findings to report._');
220
+ out.push(`\n## ${L ? 'Metodoloji' : 'Methodology'}`);
221
+ out.push(L
222
+ ? 'WormClaude deterministik motoru: keşif (alt-alan/başlık/ifşa) + dizin/içerik keşfi + XSS/SQLi/SSTI/LFI/SSRF/komut-enjeksiyonu/NoSQL/açık-yönlendirme/CRLF + subdomain-takeover. Crawl-tabanlı param keşfi; trafik yetkili kapsamda kullanıcı IP’sinden çıktı.'
223
+ : 'WormClaude deterministic engine: recon (subdomains/headers/exposure) + content discovery + XSS/SQLi/SSTI/LFI/SSRF/cmd-injection/NoSQL/open-redirect/CRLF + subdomain-takeover. Crawl-based param discovery; traffic from the operator IP within authorized scope.');
224
+ out.push(`\n## ${L ? 'Sınırlar' : 'Limitations'}`);
225
+ out.push(L
226
+ ? 'Stored/DOM XSS, kimlik-doğrulama arkası akışlar, iş-mantığı ve post-exploitation kapsam dışıdır; bunlar için manuel test / tam araç (Burp Pro, sqlmap) önerilir. "Bulgu yok" = "güvenli" anlamına gelmez.'
227
+ : 'Stored/DOM XSS, authenticated flows, business logic and post-exploitation are out of scope; manual testing / full tooling (Burp Pro, sqlmap) recommended. "No findings" does not mean "secure".');
228
+ return out.join('\n');
229
+ }
230
+ async function reportCmd(ctx) {
231
+ if (!_lastScan) {
232
+ ctx.note(tt('No scan yet. Run /fullscan <target> (or /recon /xss /sqli) first, then /report.', 'Henüz tarama yok. Önce /fullscan <hedef> (ya da /recon /xss /sqli) çalıştır, sonra /report.'));
233
+ return;
234
+ }
235
+ const md = buildReport(_lastScan);
236
+ const host = (_lastScan.target.replace(/^https?:\/\//, '').replace(/[^\w.-]/g, '_')).slice(0, 40);
237
+ const fname = `wormclaude-report-${host}.md`;
238
+ const fpath = path.resolve(getBashCwd(), fname);
239
+ try {
240
+ fs.writeFileSync(fpath, md, 'utf8');
241
+ ctx.assistant(tt(`Report written: ${fpath}\n(${_lastScan.findings.length} findings from the last scan of ${_lastScan.target})`, `Rapor yazıldı: ${fpath}\n(${_lastScan.target} son taramasından ${_lastScan.findings.length} bulgu)`));
242
+ }
243
+ catch (e) {
244
+ // Yazılamazsa ekrana bas
245
+ ctx.assistant(md);
246
+ }
247
+ }
154
248
  // Bekleyen tarama onayı — kullanıcı uyarıdan sonra sadece "run"/"onayla" yazınca çalıştırmak için.
155
- const PT_BUILTIN = new Set(['recon', 'scan', 'xss', 'sqli']);
249
+ const PT_BUILTIN = new Set(['recon', 'scan', 'xss', 'sqli', 'dirscan']);
156
250
  let pendingPentest = null;
157
251
  export function getPendingPentestCommand(input) {
158
252
  if (!pendingPentest)
@@ -188,7 +282,7 @@ function formatFinding(x) {
188
282
  // FALSE-POZİTİF guard: ilk kelime tam komut adı + argüman var + soru DEĞİL ("recon nedir?" tetiklemez).
189
283
  // Yalnız hedef-alan komutları; ve hedef URL/domain GİBİ görünmeli ("xss ile tara" → komut DEĞİL,
190
284
  // model SecurityScan ile halleder). "?'li URL kabul edilir (parametreli xss/sqli hedefi).
191
- const _BARE_CMDS = new Set(['recon', 'scan', 'xss', 'sqli', 'fullscan']);
285
+ const _BARE_CMDS = new Set(['recon', 'scan', 'xss', 'sqli', 'fullscan', 'dirscan']);
192
286
  const _TARGET_RE = /(^https?:\/\/)|(\.[a-z]{2,})|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i;
193
287
  export function detectBareCommand(input) {
194
288
  const s = (input || '').trim();
@@ -258,6 +352,7 @@ async function pentestCmd(tool, arg, ctx) {
258
352
  const rep = out.report || {};
259
353
  const lines = [`✓ ${label} ${tt('complete', 'tamamlandı')} — ${rep.target || target}`];
260
354
  const f = rep.findings || [];
355
+ setLastScan(rep.target || target, f); // /report için sakla
261
356
  if (!f.length) {
262
357
  lines.push(tt('No vulnerabilities found — the target looks clean, OR it did not respond/was unreachable (down, redirect, blocking). Try again on a live, genuinely vulnerable target.', 'Zafiyet bulunamadı — hedef temiz görünüyor YA DA yanıt vermedi/erişilemiyor (down, yönlendirme, bloklama). Ayakta + gerçekten zafiyetli bir hedefte tekrar dene.'));
263
358
  }
@@ -305,7 +400,8 @@ async function fullScanCmd(arg, ctx) {
305
400
  }
306
401
  pendingPentest = null;
307
402
  // Çekirdek (recon+XSS+SQLi, crawl'lı) + sunucudaki TÜM şablon tarayıcıları (SSRF/XXE/SSTI/LFI/…).
308
- const steps = [['recon', ptLabel('recon')], ['xss', ptLabel('xss')], ['sqli', ptLabel('sqli')]];
403
+ const steps = [['recon', ptLabel('recon')], ['dirscan', ptLabel('dirscan')],
404
+ ['xss', ptLabel('xss')], ['sqli', ptLabel('sqli')]];
309
405
  const ptInfo = await fetchPtTools(ctx.config);
310
406
  for (const tm of ((ptInfo && ptInfo.templates) || [])) {
311
407
  if (tm && tm.id)
@@ -332,6 +428,7 @@ async function fullScanCmd(arg, ctx) {
332
428
  }
333
429
  const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
334
430
  all.sort((a, b) => (order[a.severity] ?? 9) - (order[b.severity] ?? 9));
431
+ setLastScan(target, all); // /report için sakla
335
432
  const lines = [`✓ ${tt('Full scan complete', 'Tam tarama tamamlandı')} — ${target}`];
336
433
  if (!all.length) {
337
434
  lines.push(tt('No findings across all scanners. Target looks clean or was unreachable.', 'Tüm tarayıcılarda bulgu yok. Hedef temiz görünüyor ya da erişilemedi.'));
@@ -969,11 +1066,15 @@ export async function runSlashCommand(input, ctx) {
969
1066
  case '/scan':
970
1067
  case '/xss':
971
1068
  case '/sqli':
1069
+ case '/dirscan':
972
1070
  await pentestCmd(cmd.slice(1), arg, ctx);
973
1071
  return true;
974
1072
  case '/fullscan':
975
1073
  await fullScanCmd(arg, ctx);
976
1074
  return true;
1075
+ case '/report':
1076
+ await reportCmd(ctx);
1077
+ return true;
977
1078
  case '/skill': {
978
1079
  const m = (arg || '').trim().split(/\s+/).filter(Boolean);
979
1080
  const sub = (m.shift() || '').toLowerCase();
package/dist/theme.js CHANGED
@@ -16,4 +16,4 @@ export const theme = {
16
16
  synType: '#a78bfa', // tip/sınıf adları, sabitler
17
17
  synProp: '#e0e0e0', // özellik/anahtar adları
18
18
  };
19
- export const VERSION = '1.0.164';
19
+ export const VERSION = '1.0.166';
package/dist/tools.js CHANGED
@@ -226,8 +226,8 @@ export const toolSchemas = [
226
226
  parameters: {
227
227
  type: 'object',
228
228
  properties: {
229
- tool: { type: 'string', enum: ['recon', 'scan', 'xss', 'sqli'], description: 'recon/scan → domain; xss/sqli → parameterized URL' },
230
- target: { type: 'string', description: 'Domain for recon/scan (example.com) OR parameterized URL for xss/sqli (https://example.com/p?id=1)' },
229
+ tool: { type: 'string', enum: ['recon', 'scan', 'xss', 'sqli', 'dirscan'], description: 'recon/scan/dirscan → domain; xss/sqli → parameterized URL' },
230
+ target: { type: 'string', description: 'Domain for recon/scan/dirscan (example.com) OR parameterized URL for xss/sqli (https://example.com/p?id=1)' },
231
231
  },
232
232
  required: ['tool', 'target'],
233
233
  },
@@ -728,8 +728,8 @@ async function execOne(call, hooks) {
728
728
  if (call.name === 'SecurityScan') {
729
729
  let tool = String(args?.tool || '').toLowerCase().trim();
730
730
  const target = String(args?.target || '').trim();
731
- if (!['recon', 'scan', 'xss', 'sqli'].includes(tool) || !target) {
732
- return { ok: false, output: 'SecurityScan: tool (recon|scan|xss|sqli) ve target gerekli.', args };
731
+ if (!['recon', 'scan', 'xss', 'sqli', 'dirscan'].includes(tool) || !target) {
732
+ return { ok: false, output: 'SecurityScan: tool (recon|scan|xss|sqli|dirscan) ve target gerekli.', args };
733
733
  }
734
734
  if (tool === 'scan')
735
735
  tool = 'recon'; // "scan" genel tarama → motorun bildiği "recon" (slash ile aynı)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.164",
3
+ "version": "1.0.166",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {