wormclaude 1.0.83 → 1.0.85
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/cli.js +7 -6
- package/dist/commands.js +90 -0
- package/dist/pentest.js +87 -0
- package/dist/subagents.js +22 -0
- package/dist/theme.js +1 -1
- package/dist/tools.js +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { linkify } from './links.js';
|
|
|
20
20
|
import { recordLearned } from './learn.js';
|
|
21
21
|
import { loadSkills, getSkills, getSkill, buildSkillPrompt } from './skills.js';
|
|
22
22
|
import { loadExtensions, getExtCommands, getExtCommand, buildExtCommandPrompt } from './extensions.js';
|
|
23
|
+
import { platformNote } from './subagents.js';
|
|
23
24
|
import { COMMANDS, runSlashCommand } from './commands.js';
|
|
24
25
|
import { tasks } from './tasks.js';
|
|
25
26
|
import { connectMcpServers } from './mcp.js';
|
|
@@ -123,12 +124,12 @@ loadExtensions(); // extensions/<ad>/ (gömülü + kullanıcı + proje) yükle
|
|
|
123
124
|
// Kalıcı hafıza: açılışta .wormclaude/memory.md + WORMCLAUDE.md'yi context'e yükle
|
|
124
125
|
const _memCtx = loadMemoryContext();
|
|
125
126
|
const _envContext = () => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
? '
|
|
130
|
-
: '
|
|
131
|
-
return
|
|
127
|
+
// Platform + kabuk kuralları paylaşılan kaynaktan (subagents.platformNote) — ana ajan
|
|
128
|
+
// ve alt-ajanlar AYNI Windows tırnak/araç kurallarını görür.
|
|
129
|
+
const extra = process.platform === 'win32'
|
|
130
|
+
? '\n- AVOID interactive scaffolders that hang (create-react-app); prefer Vite: npm create vite@latest myapp -- --template react.'
|
|
131
|
+
: '';
|
|
132
|
+
return platformNote() + extra;
|
|
132
133
|
};
|
|
133
134
|
const _initHistory = () => {
|
|
134
135
|
const sys = [{ role: 'system', content: _envContext() }];
|
package/dist/commands.js
CHANGED
|
@@ -15,6 +15,7 @@ import { isLearnEnabled, setLearnEnabled, getLearnFile, getLearnCount } from './
|
|
|
15
15
|
import { saveMemoryFact, getMemoryPath, loadMemoryContext } from './memory.js';
|
|
16
16
|
import { fetchAccount, getVerifyStatus, submitVerification } from './api.js';
|
|
17
17
|
import { programText, tier } from './program.js';
|
|
18
|
+
import { runPentest } from './pentest.js';
|
|
18
19
|
export const COMMANDS = [
|
|
19
20
|
{ name: '/help', desc: 'komutları ve ipuçlarını göster' },
|
|
20
21
|
{ name: '/clear', desc: 'sohbeti ve geçmişi temizle' },
|
|
@@ -44,6 +45,10 @@ export const COMMANDS = [
|
|
|
44
45
|
{ name: '/izinler', desc: 'onayli shell komutlarini yonet (list/add/remove/clear)' },
|
|
45
46
|
{ name: '/program', desc: 'Doğrulanmış Araştırmacı Programı — güven seviyeni göster' },
|
|
46
47
|
{ name: '/dogrula', desc: 'Doğrulanmış Araştırmacı başvurusu gönder: /dogrula <profil/şirket/gerekçe>' },
|
|
48
|
+
{ name: '/recon', desc: '[seviye 3+] yetkili hedefte keşif (alt-alan/host/crawl): /recon <alan>' },
|
|
49
|
+
{ name: '/scan', desc: '[seviye 3+] yetkili hedefte zafiyet taraması (nuclei): /scan <url>' },
|
|
50
|
+
{ name: '/xss', desc: '[seviye 3+] yetkili hedefte XSS taraması (dalfox): /xss <url>' },
|
|
51
|
+
{ name: '/sqli', desc: '[seviye 3+] yetkili hedefte SQLi taraması (sqlmap): /sqli <url>' },
|
|
47
52
|
{ name: '/export', desc: 'sohbeti dosyaya kaydet' },
|
|
48
53
|
{ name: '/resume', desc: 'en son kaydedilen oturumu yükle' },
|
|
49
54
|
{ name: '/quit', desc: 'çıkış' },
|
|
@@ -101,6 +106,85 @@ function tsStamp() {
|
|
|
101
106
|
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
|
|
102
107
|
}
|
|
103
108
|
// Komut yürütücü. true → komut işlendi, false → komut değil (normal mesaj).
|
|
109
|
+
const PT_LABELS = {
|
|
110
|
+
recon: 'Keşif (subfinder+httpx+katana)', scan: 'Zafiyet tarama (nuclei)',
|
|
111
|
+
xss: 'XSS (dalfox)', sqli: 'SQL injection (sqlmap)',
|
|
112
|
+
};
|
|
113
|
+
const PT_REASON = {
|
|
114
|
+
trust_required: 'Bu komut Doğrulanmış Araştırmacı (seviye 3+) gerektirir. Başvuru: /dogrula',
|
|
115
|
+
scope_required: 'Yetki onayı gerekli.',
|
|
116
|
+
no_quota: 'Bu ay tarama kotan yok (planını yükselt).',
|
|
117
|
+
quota_exceeded: 'Aylık tarama kotan doldu.',
|
|
118
|
+
invalid_target: 'Geçersiz hedef. URL/alan adı ver (örn https://test.com/p?id=1).',
|
|
119
|
+
unknown_tool: 'Bilinmeyen araç.',
|
|
120
|
+
auth: 'Giriş gerekli. /config key <anahtar>',
|
|
121
|
+
timeout: 'Sunucu zaman aşımı.',
|
|
122
|
+
upstream_error: 'Sunucuya ulaşılamadı.',
|
|
123
|
+
};
|
|
124
|
+
function formatFinding(x) {
|
|
125
|
+
const sev = x.severity ? `[${String(x.severity).toUpperCase()}] ` : '';
|
|
126
|
+
if (x.type === 'vuln')
|
|
127
|
+
return `${sev}${x.name || ''} — ${x.url || ''}`;
|
|
128
|
+
if (x.type === 'xss')
|
|
129
|
+
return `${sev}XSS ${x.param ? 'param ' + x.param : ''} — ${x.url || x.poc || ''}`;
|
|
130
|
+
if (x.type === 'sqli')
|
|
131
|
+
return `${sev}SQLi ${x.vulnerable ? 'ZAFİYETLİ' : ''} ${x.params ? '(' + x.params.join(',') + ')' : ''}`;
|
|
132
|
+
if (x.type === 'host')
|
|
133
|
+
return `${x.status || ''} ${x.url || ''}${x.title ? ' · ' + x.title : ''}${x.server ? ' · ' + x.server : ''}`;
|
|
134
|
+
if (x.value)
|
|
135
|
+
return `${x.value}`;
|
|
136
|
+
return JSON.stringify(x);
|
|
137
|
+
}
|
|
138
|
+
// /recon /scan /xss /sqli — ince runner'ı sürer. Zorunlu yetki onayı + trust 3+ teaser.
|
|
139
|
+
async function pentestCmd(tool, arg, ctx) {
|
|
140
|
+
const parts = (arg || '').trim().split(/\s+/).filter(Boolean);
|
|
141
|
+
let scopeAck = false;
|
|
142
|
+
if (parts.length && /^(onayla|--yes|-y|yes|evet)$/i.test(parts[parts.length - 1])) {
|
|
143
|
+
scopeAck = true;
|
|
144
|
+
parts.pop();
|
|
145
|
+
}
|
|
146
|
+
const target = parts.join(' ').trim();
|
|
147
|
+
const label = PT_LABELS[tool] || tool;
|
|
148
|
+
if (!target) {
|
|
149
|
+
ctx.note(`${label}\nKullanım: /${tool} <hedef>\nÖrnek: /${tool} https://test.com/sayfa?id=1`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (!scopeAck) {
|
|
153
|
+
ctx.note(`⚠️ YETKİ ONAYI GEREKLİ — ${label}\n` +
|
|
154
|
+
`Hedef: ${target}\n\n` +
|
|
155
|
+
`Bu tarama hedefe GERÇEK istekler gönderir ve trafik SENİN IP'nden çıkar. Yalnız sahibi olduğun ya da\n` +
|
|
156
|
+
`yazılı izin/angajman bulunan sistemlerde çalıştır. Yetkisiz tarama yasa dışıdır ve kayıt altına alınır.\n\n` +
|
|
157
|
+
`Onaylıyorsan tekrar çalıştır: /${tool} ${target} onayla`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
ctx.note(`${label} başlatılıyor — ${target}`);
|
|
161
|
+
const out = await runPentest(ctx.config, tool, target, true, (s) => ctx.note(s));
|
|
162
|
+
if (!out.ok) {
|
|
163
|
+
const r = out.reason || out.plan?.reason || 'error';
|
|
164
|
+
let msg = PT_REASON[r] || r;
|
|
165
|
+
if (r === 'quota_exceeded' && out.plan)
|
|
166
|
+
msg += ` (${out.plan.used}/${out.plan.quota})`;
|
|
167
|
+
ctx.note(`Tarama yapılamadı: ${msg}`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const rep = out.report || {};
|
|
171
|
+
const lines = [`✓ ${label} tamamlandı — ${rep.target || target}`];
|
|
172
|
+
if (out.missing && out.missing.length) {
|
|
173
|
+
lines.push(`⚠ Kurulu olmayan araç(lar) atlandı: ${out.missing.join(', ')}`);
|
|
174
|
+
}
|
|
175
|
+
const f = rep.findings || [];
|
|
176
|
+
if (!f.length) {
|
|
177
|
+
lines.push('Bulgu yok (hedef yanıt vermedi, temiz, ya da araç kurulu değil).');
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
lines.push(`${rep.found_count} bulgu:`);
|
|
181
|
+
for (const x of f.slice(0, 40))
|
|
182
|
+
lines.push(' ' + formatFinding(x));
|
|
183
|
+
if (f.length > 40)
|
|
184
|
+
lines.push(` … +${f.length - 40} daha`);
|
|
185
|
+
}
|
|
186
|
+
ctx.assistant(lines.join('\n'));
|
|
187
|
+
}
|
|
104
188
|
export async function runSlashCommand(input, ctx) {
|
|
105
189
|
const v = input.trim();
|
|
106
190
|
if (!v.startsWith('/'))
|
|
@@ -642,6 +726,12 @@ export async function runSlashCommand(input, ctx) {
|
|
|
642
726
|
: `Başvuru gönderilemedi: ${res.error}`);
|
|
643
727
|
return true;
|
|
644
728
|
}
|
|
729
|
+
case '/recon':
|
|
730
|
+
case '/scan':
|
|
731
|
+
case '/xss':
|
|
732
|
+
case '/sqli':
|
|
733
|
+
await pentestCmd(cmd.slice(1), arg, ctx);
|
|
734
|
+
return true;
|
|
645
735
|
case '/export': {
|
|
646
736
|
fs.mkdirSync(SESSION_DIR, { recursive: true });
|
|
647
737
|
const file = path.join(SESSION_DIR, `session-${tsStamp()}.json`);
|
package/dist/pentest.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// WormClaude güvenlik tarama — İSTEMCİ ince runner.
|
|
2
|
+
//
|
|
3
|
+
// Bu modül JENERİK bir çalıştırıcıdır: hiç payload/şablon/araç-seçimi içermez.
|
|
4
|
+
// Sunucudan bir komut PLANI alır, komutları YEREL makinede çalıştırır (trafik kullanıcının
|
|
5
|
+
// IP'sinden çıkar), ham çıktıyı sunucuya geri gönderir. Tüm zeka sunucuda kalır.
|
|
6
|
+
//
|
|
7
|
+
// Güvenlik: yalnız PT_ALLOWED'daki ikililer çalıştırılır (ele geçirilmiş/kötü sunucunun
|
|
8
|
+
// istemcide rastgele komut çalıştırmasını engeller). Komutlar SHELL'siz spawn edilir (enjeksiyon yok).
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
// İstemci-tarafı allowlist (sunucudakiyle aynı; çift güvence).
|
|
11
|
+
export const PT_ALLOWED = new Set(['httpx', 'nuclei', 'dalfox', 'sqlmap', 'subfinder', 'katana', 'nmap', 'ffuf']);
|
|
12
|
+
const MAX_OUT = 200_000;
|
|
13
|
+
async function postJson(config, p, body, timeoutMs) {
|
|
14
|
+
try {
|
|
15
|
+
const r = await fetch(`${config.baseUrl}${p}`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: { 'Content-Type': 'application/json', ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}) },
|
|
18
|
+
body: JSON.stringify(body),
|
|
19
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
20
|
+
});
|
|
21
|
+
const d = await r.json().catch(() => ({ ok: false, reason: 'bad_response' }));
|
|
22
|
+
if (!r.ok && !d.reason)
|
|
23
|
+
return { ok: false, reason: `HTTP ${r.status}` };
|
|
24
|
+
return d;
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
return { ok: false, reason: e?.name === 'TimeoutError' ? 'timeout' : 'upstream_error' };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function runStep(step) {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
// İstemci allowlist zorlaması — sunucu ne derse desin, izinsiz ikili ÇALIŞMAZ.
|
|
33
|
+
if (!PT_ALLOWED.has(step.bin)) {
|
|
34
|
+
resolve({ id: step.id, ran: false, exit: -1, stdout: '', stderr: `engellendi: izinli olmayan ikili "${step.bin}"` });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let out = '', err = '', done = false;
|
|
38
|
+
let child;
|
|
39
|
+
try {
|
|
40
|
+
child = spawn(step.bin, step.args, { shell: false, windowsHide: true });
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
resolve({ id: step.id, ran: false, exit: -1, stdout: '', stderr: `başlatılamadı (kurulu değil?): ${step.bin}` });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const to = setTimeout(() => { try {
|
|
47
|
+
child.kill('SIGKILL');
|
|
48
|
+
}
|
|
49
|
+
catch { /* */ } }, Math.max(5, step.timeout) * 1000);
|
|
50
|
+
child.stdout?.on('data', (d) => { if (out.length < MAX_OUT)
|
|
51
|
+
out += d.toString(); });
|
|
52
|
+
child.stderr?.on('data', (d) => { if (err.length < 4000)
|
|
53
|
+
err += d.toString(); });
|
|
54
|
+
child.on('error', () => {
|
|
55
|
+
if (done)
|
|
56
|
+
return;
|
|
57
|
+
done = true;
|
|
58
|
+
clearTimeout(to);
|
|
59
|
+
resolve({ id: step.id, ran: false, exit: -1, stdout: out, stderr: `çalıştırılamadı (kurulu değil?): ${step.bin}` });
|
|
60
|
+
});
|
|
61
|
+
child.on('close', (code) => {
|
|
62
|
+
if (done)
|
|
63
|
+
return;
|
|
64
|
+
done = true;
|
|
65
|
+
clearTimeout(to);
|
|
66
|
+
resolve({ id: step.id, ran: true, exit: code ?? -1, stdout: out, stderr: err });
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// Tam akış: plan al → yerelde çalıştır → rapor gönder. log() ile ilerleme bildirir.
|
|
71
|
+
export async function runPentest(config, tool, target, scopeAck, log) {
|
|
72
|
+
const plan = await postJson(config, '/pentest/plan', { tool, target, scope_ack: scopeAck }, 15000);
|
|
73
|
+
if (!plan.ok)
|
|
74
|
+
return { ok: false, reason: plan.reason, plan };
|
|
75
|
+
log(`Plan alındı (${plan.steps.length} adım). Yerelde çalıştırılıyor — trafik senin IP'nden çıkıyor…`);
|
|
76
|
+
const results = [];
|
|
77
|
+
const missing = [];
|
|
78
|
+
for (const s of plan.steps) {
|
|
79
|
+
log(` → ${s.bin} ${s.args.slice(0, 3).join(' ')}…`);
|
|
80
|
+
const r = await runStep(s);
|
|
81
|
+
if (!r.ran && /kurulu değil/.test(r.stderr))
|
|
82
|
+
missing.push(s.bin);
|
|
83
|
+
results.push(r);
|
|
84
|
+
}
|
|
85
|
+
const report = await postJson(config, '/pentest/report', { job_id: plan.job_id, results }, 30000);
|
|
86
|
+
return { ok: !!report.ok, plan, report, missing: [...new Set(missing)] };
|
|
87
|
+
}
|
package/dist/subagents.js
CHANGED
|
@@ -4,6 +4,28 @@
|
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as os from 'node:os';
|
|
6
6
|
import * as path from 'node:path';
|
|
7
|
+
/**
|
|
8
|
+
* Çalışma ortamı + kabuk kuralları — hem ana ajana hem ALT-ajanlara verilir.
|
|
9
|
+
* Windows'ta cmd.exe tırnak kuralları kritik: yanlış tırnak sessizce "Sistem
|
|
10
|
+
* belirtilen dosyayı bulamıyor" / "URL rejected" ile patlar (curl 'url' başarısız).
|
|
11
|
+
*/
|
|
12
|
+
export function platformNote() {
|
|
13
|
+
const isWin = process.platform === 'win32';
|
|
14
|
+
const plat = isWin ? 'Windows' : process.platform === 'darwin' ? 'macOS' : 'Linux';
|
|
15
|
+
const cwd = process.cwd();
|
|
16
|
+
if (isWin) {
|
|
17
|
+
return [
|
|
18
|
+
`ENVIRONMENT: User machine = Windows. The Bash tool runs commands via cmd.exe (NOT a Unix shell). CWD: ${cwd}.`,
|
|
19
|
+
'WINDOWS SHELL RULES (critical — wrong quoting fails with "Sistem belirtilen dosyayı bulamıyor" or "URL rejected"):',
|
|
20
|
+
'- Use DOUBLE quotes only. SINGLE quotes do NOT work in cmd.exe — `curl \'http://x\'` FAILS.',
|
|
21
|
+
'- The characters < > & | ^ ( ) are special in cmd.exe; ANY argument or URL containing them MUST be wrapped in double quotes. Correct: curl "https://site/path?q=<script>alert(1)</script>" — never single-quoted, never unquoted.',
|
|
22
|
+
'- For fetching or probing a URL, PREFER the WebFetch tool (cross-platform, no shell quoting). Use curl.exe only when you need the RAW HTTP response (e.g. to see if an XSS payload is reflected verbatim), and ALWAYS double-quote the full URL.',
|
|
23
|
+
'- Unix/security tools are usually NOT installed (no grep/sed/awk/ls/cat/nmap/nikto/sqlmap). Use the Read/Grep/Glob tools or PowerShell (Get-Content, Select-String, Get-ChildItem). Before calling an external tool, verify it exists with `where <tool>`; if missing, use an HTTP/WebFetch-based method instead.',
|
|
24
|
+
'- && chaining works in cmd.exe. Always pass non-interactive flags (-y/--yes) to avoid hangs.',
|
|
25
|
+
].join('\n');
|
|
26
|
+
}
|
|
27
|
+
return `ENVIRONMENT: User machine = ${plat}. Bash tool shell: bash/sh (POSIX). CWD: ${cwd}. Use POSIX commands and standard quoting; double-quote URLs containing special characters.`;
|
|
28
|
+
}
|
|
7
29
|
// ── Gömülü uzman ajanlar ──────────────────────────────────────────────────────
|
|
8
30
|
const BUILTINS = [
|
|
9
31
|
{
|
package/dist/theme.js
CHANGED
package/dist/tools.js
CHANGED
|
@@ -8,7 +8,7 @@ import * as os from 'node:os';
|
|
|
8
8
|
import * as path from 'node:path';
|
|
9
9
|
import { loadConfig } from './api.js';
|
|
10
10
|
import { runAgentLoop } from './agent.js';
|
|
11
|
-
import { resolveSubagent, subagentTypesHint } from './subagents.js';
|
|
11
|
+
import { resolveSubagent, subagentTypesHint, platformNote } from './subagents.js';
|
|
12
12
|
import { saveMemoryFact } from './memory.js';
|
|
13
13
|
import { emit as emitSpan } from './telemetry.js';
|
|
14
14
|
import { tasks } from './tasks.js';
|
|
@@ -951,7 +951,7 @@ export async function executeTool(name, args) {
|
|
|
951
951
|
if (name === 'Agent') {
|
|
952
952
|
// Uzman ajan seçimi: subagent_type verilirse özel prompt + tool-kısıtı uygulanır.
|
|
953
953
|
const def = resolveSubagent(args.subagent_type);
|
|
954
|
-
const sysPrompt = def ? def.system : SUBAGENT_SYSTEM;
|
|
954
|
+
const sysPrompt = (def ? def.system : SUBAGENT_SYSTEM) + '\n\n' + platformNote();
|
|
955
955
|
const subTools = subAgentTools(def?.tools);
|
|
956
956
|
const subMessages = [
|
|
957
957
|
{ role: 'system', content: sysPrompt },
|
|
@@ -1391,7 +1391,7 @@ export async function executeTool(name, args) {
|
|
|
1391
1391
|
if (sk.tools && sk.tools.length)
|
|
1392
1392
|
tools = tools.filter((t) => sk.tools.includes(t.function.name));
|
|
1393
1393
|
const messages = [
|
|
1394
|
-
{ role: 'system', content: SUBAGENT_SYSTEM },
|
|
1394
|
+
{ role: 'system', content: SUBAGENT_SYSTEM + '\n\n' + platformNote() },
|
|
1395
1395
|
{ role: 'user', content: prompt },
|
|
1396
1396
|
];
|
|
1397
1397
|
const { finalText } = await runAgentLoop({ config: cfg(), messages, tools, executeTool });
|