-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathdeep_focus.py
More file actions
321 lines (270 loc) · 15.6 KB
/
deep_focus.py
File metadata and controls
321 lines (270 loc) · 15.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
import sys
import subprocess
import time
import os
from pathlib import Path
# Local Code modules
from execution import config
from execution import visualizer
# --- Configuration & Setup ---
sys.path.append(".") # Ensure module path is correct
# --- ASCII Art & Branding ---
BANNER = r"""
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⢀⠀⠀⠘
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣷⡿⠀⣀⣼
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⢛⣵⣶⣟⣽⣿
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢎⣾⣿⣿⣿⣿⣩⠞
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣨⣾⣿⣿⣿⣿⠟⠉⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣾⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣾⣿⣿⡿⠋⠉⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⡄⠙⠦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣰⣾⣿⣿⢟⣩⣶⠤⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢦⠀⠈⠳⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⠿⠋⠐⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠈⢧⠀⠓⠿⠙⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⢀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢖⢤⡈⠳⡄⠀⠀⠈⢷⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢀⡀⠀⠀⢀⣴⣿⣿⡯⠖⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠙⢯⡉⠙⠒⠒⢒⣢⣤⣦⣤⠤⣀⣀⣀⣑⣼⡳⣜⣦⡀⠈⠉⠉⢣⡀⠀⠀⠀ ⠀⣠⣦⠾⢉⣿⢇⠀⣴⠿⠋⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠙⠲⣄⡘⠁⠀⠀⠀⠐⠋⠀⢠⠒⠦⢭⣙⡳⢍⣿⣶⣄⠈⠒⠵⣄⠀⠀⠀⠀⠀⠀⣾⣻⣾⣾⣧⣦⣿⣅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠉⠓⠲⠤⠤⠔⠢⣄⠀⠀⠀⠤⢴⣿⣟⣊⣉⣛⣳⠦⢄⣈⠓⠦⢄⡀⠀⠀⢻⢱⣿⠛⢁⠉⠁⠘⠳⡦⡤⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠤⠤⢈⣁⣀⡀⡀⠀⠀⣀⣉⠁⠒⣭⣓⠦⢌⣒⣶⠶⠿⢻⡆⠈⢿⣤⣀⣠⠇⡿⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡤⠤⠒⠊⠉⠉⠉⠉⠙⠉⠙⠋⠙⠛⣛⣓⣶⣶⣶⡶⠭⣛⣿⣦⠂⠻⣟⠀⢰⡿⣥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣖⣒⡊⣭⠄⠀⠀⢀⡠⠴⠒⠪⡿⠋⣹⣷⣤⡶⢷⣿⢿⡟⠋⣡⣴⢿⢿⣿⣿⣿⣦⣜⠷⢟⣁⣹⣝⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡠⣔⣯⡶⣂⠤⠚⠉⢀⣀⣤⠮⠗⠚⣋⠭⠚⢁⠤⠞⠋⣠⢾⣿⢱⢃⢟⣿⣿⠃⢸⣿⣷⣄⣀⣈⣍⠛⠮⠷⢲⠾⣴⡷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢀⣠⣔⠯⠓⢉⣽⠟⠋⠀⢀⣀⣠⢞⣵⡾⣠⠖⠈⠀⠀⠀⠀⠀⡠⣺⣵⢫⣻⠇⡼⢸⣇⢻⠀⡼⢤⠈⠑⠃⡜⠀⠀⠀⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⢀⣤⠾⠛⠉⠀⠀⢐⣫⠴⠚⠉⠉⢉⣟⡵⠋⠞⠀⠀⠀⠀⠀⠀⢀⣠⣴⡫⡻⣣⡸⠙⠀⢻⢸⡗⢏⡾⠁⢘⠀⡀⣴⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠈⠉⠀⠀⠀⠀⠴⠚⠉⠀⠀⠀⢀⡴⠋⠋⠀⠀⠀⠀⠀⣀⣠⢴⠖⠋⣴⣿⣯⢞⡽⣣⠇⡰⠏⣸⡷⠋⠀⠀⢨⡴⣩⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⠋⠀⠀⠀⣀⣤⠶⢝⡲⣿⠟⢁⣠⣾⠟⠁⡀⠞⠁⡡⢊⣅⣼⣿⠃⠀⠀⠀⠈⡇⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣜⣁⠤⠴⠒⠋⠉⠁⣠⢔⣫⡾⠽⣾⡿⢋⡀⠀⠀⢉⡴⠊⠠⣨⣾⣎⢾⣝⠀⠀⢀⢀⣷⡇⠀⠀⠀⠀⢠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠠⠞⠉⠠⣦⠀⣀⣤⠶⡟⣛⢩⡁⢀⣾⣏⣞⣾⣮⢴⣖⣋⠀⠴⠾⠼⠞⠁⣸⣉⣷⣴⣰⣸⣻⡇⠀⠀⡠⣤⣻⠁⣴⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠟⢰⠀⢀⣄⠧⢿⣞⡧⣿⠿⠿⠓⢝⠥⠭⠭⠭⠭⠭⠍⢔⡲⣶⣺⠫⠥⠤⢚⣛⡩⠧⢛⣒⢝⣫⡷⢆⣁⣄⠀⠀⠀⡀⣠⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡠⢜⣒⡽⢺⣛⡽⠵⠛⠛⠉⠉⠋⠉⠀⠀⠀⠀⠀⠀⠀⠈⠀⠸⠇⠁⠉⠉⠉⠉⠚⠛⠵⢴⠹⣇⢍⣒⡢⠾⣢⢤⣀⠽⡿⣶⡤⣀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢀⡠⢖⠫⢕⡺⠝⠚⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠈⠀⠀⠉⠉⠒⠭⣚⠽⣲⣤⣙⢦⡍⠒⠤⡀⠀
⠀⠀⠀⠀⢀⡤⣺⢕⣠⡿⠏⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⠢⣉⠚⢕⡦⣀⠀⠀⠀
⠀⠀⠀⠐⠁⠈⠀⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠆⠉⠪⠳⠄⠀
Deep Focus
Made By Y0oshi | ig:@rde0
"""
# Global handle for scanner subprocess
scanner_process = None
# Rich console for colored output
from rich.console import Console
console = Console()
def print_help():
"""Display available CLI commands."""
console.print("\n[bold cyan]Available Commands:[/bold cyan]")
console.print(" [green]/scan[/green] - Start Scanner (Background) and Open Visualizer")
console.print(" [red]/stop[/red] - Stop Scanner and Export Data")
console.print(" [yellow]/settings[/yellow] - Configure Target, Speed & Limits")
console.print(" [bold white]/exit[/bold white] - Quit Application")
def start_scan():
"""Start the background scanning process and launch the UI."""
global scanner_process
cfg = config.load_config()
# Check if already running
if scanner_process and scanner_process.poll() is None:
console.print("[yellow][*] Scanner is already active.[/yellow]")
return
console.print("[green][*] Launching Scanner Engine...[/green]")
# Construct scanner command
cmd = [
sys.executable, "execution/scanner.py",
"--target", cfg['target_network'],
"--rate", str(cfg['scan_speed']),
"--max-load", str(cfg['max_load']),
"--cool-down", str(cfg['cool_down_target']),
"--loop"
]
# Execute in background, discarding output to avoid UI conflicts
# Output is piped to /dev/null
try:
devnull = open(os.devnull, 'w')
scanner_process = subprocess.Popen(cmd, stdout=devnull, stderr=devnull)
console.print(f"[green][+] Scanner started successfully (PID: {scanner_process.pid})[/green]")
time.sleep(1) # Allow process to initialize
except Exception as e:
console.print(f"[bold red][!] Failed to start scanner: {e}[/bold red]")
return
# Attach Visualizer (This blocks the main thread until user exits UI)
console.print("[*] Attaching Dashboard... (Active)")
time.sleep(1)
try:
visualizer.run_dashboard()
except KeyboardInterrupt:
pass # Handle Ctrl+C gracefully
except Exception as e:
console.print(f"[bold red][!] Visualizer error: {e}[/bold red]")
# When visualizer exits:
console.print("\n[blue][i] Dashboard closed. Scanner is still running in background.[/blue]")
console.print(" Type '[bold red]/stop[/bold red]' to halt, or '[green]/scan[/green]' to view again.")
def stop_scan():
"""Terminate the scanner process and offer export."""
global scanner_process
# 1. Terminate Process
if scanner_process and scanner_process.poll() is None:
console.print(f"[yellow][*] Stopping Scanner (PID: {scanner_process.pid})...[/yellow]")
scanner_process.terminate()
try:
scanner_process.wait(timeout=5)
except subprocess.TimeoutExpired:
scanner_process.kill() # Force kill if stuck
console.print("[green][+] Scanner Stopped.[/green]")
scanner_process = None
else:
console.print("[dim][i] Scanner is not running.[/dim]")
# 2. Offer Export
perform_export()
import gc
# 3. Cleanup Session Data
console.print("\n[dim][*] Cleaning up session data...[/dim]")
# Force GC to release any lingering SQLite handles
gc.collect()
for attempt in range(5):
try:
# Remove temporary SQLite database files
for f in ["results.db", "results.db-wal", "results.db-shm"]:
if os.path.exists(f):
os.remove(f)
console.print("[green][+] Session cleared. Ready for next scan.[/green]")
break
except (PermissionError, OSError):
# Windows file locking... wait and retry
time.sleep(1.0)
if attempt == 4:
console.print(f"[red][!] Cleanup warning: Could not delete results.db (File locked). Manual delete required.[/red]")
except Exception as e:
console.print(f"[red][!] Cleanup warning: {e}[/red]")
break
def perform_export():
"""Export valid findings to a text file."""
# Lazy import sqlite3 only when needed
import sqlite3
cfg = config.load_config()
# Sanitize path: Remove shell escapes common in Mac terminal drag-and-drop
raw_path = str(cfg['export_path'])
clean_path = raw_path.replace(r'\ ', ' ')
choice = input(f"Export results to '{clean_path}'? (Y/n): ").lower()
if choice in ['n', 'no']:
return
export_dir = Path(clean_path)
export_dir.mkdir(exist_ok=True)
timestamp = int(time.time())
filename = export_dir / f"deep_focus_export_{timestamp}.txt"
console.print(f"[cyan][*] Exporting data to {filename}...[/cyan]")
conn = None
try:
conn = sqlite3.connect("results.db")
cursor = conn.cursor()
# Select high-value targets (Open ports + Valid services)
query = """
SELECT ip, port, service_type, banner
FROM services
WHERE state='open'
AND (
service_type IN ('ssh', 'vnc', 'rtsp', 'ftp')
OR
(service_type LIKE '%http%' AND banner NOT LIKE '%403 Forbidden%' AND banner NOT LIKE '%404 Not Found%')
)
"""
cursor.execute(query)
count = 0
with open(filename, "w", encoding="utf-8") as f:
f.write(f"Deep Focus Scan Report - {time.ctime()}\n")
f.write("="*60 + "\n\n")
for row in cursor:
ip, port, svc, banner = row
f.write(f"Target: {ip}:{port}\n")
f.write(f"Service: {svc}\n")
if banner:
# Clean up banner for readable log output
clean_banner = banner.replace('\n', ' ').replace('\r', '')[:120]
f.write(f"Details: {clean_banner}\n")
f.write("-" * 30 + "\n")
count += 1
console.print(f"[bold green][+] Export Complete. Saved {count} records.[/bold green]")
except Exception as e:
console.print(f"[bold red][!] Export Failed: {e}[/bold red]")
finally:
if conn:
conn.close()
def configure_settings():
"""Interactive settings menu."""
cfg = config.load_config()
power = cfg.get('power_level', 50)
speed = cfg.get('scan_speed', 500)
print("\n--- Configuration ---")
print(f"1. Target Network [Current: {cfg['target_network']}]")
print(f"2. Power Level [Current: {power}%] (Controls Thermal Limit)")
print(f"3. Scan Speed [Current: {speed} threads]")
print(f"4. Export Path [Current: {cfg['export_path']}]")
print("5. Back")
choice = input("Select setting to change: ")
if choice == '1':
val = input("Enter new Target CIDR (e.g. 104.21.0.0/20): ").strip()
if val: cfg['target_network'] = val
elif choice == '2':
val = input("Enter Power Level (10-100): ").strip()
if val:
try:
p_int = int(val)
p_int = max(10, min(100, p_int))
# Dynamic Governor Formula
# Base Load 1.5 + variable part based on user %
ratio = p_int / 100.0
max_load = 1.5 + (ratio * 8.5)
cfg['power_level'] = p_int
cfg['max_load'] = round(max_load, 2)
cfg['cool_down_target'] = round(max_load * 0.6, 2)
print(f"[+] Power set to {p_int}%. (Max Load: {cfg['max_load']})")
except ValueError:
print("Invalid input.")
elif choice == '3':
print("\n[!] CAUTION: Recommended range is 300-600 threads.")
print(" Above 600 may cause router overload and heat issues.")
val = input("Enter Scan Speed (100-1000): ").strip()
if val:
try:
s_int = int(val)
s_int = max(100, min(1000, s_int))
cfg['scan_speed'] = s_int
if s_int > 600:
print(f"[!] Speed set to {s_int}. Watch for overheating!")
else:
print(f"[+] Speed set to {s_int} threads.")
except ValueError:
print("Invalid input.")
elif choice == '4':
val = input("Enter Export Path: ").strip()
if val: cfg['export_path'] = val
config.save_config(cfg)
print("[+] Settings Saved.")
def main():
"""Main Application Loop."""
# Resize terminal for optimal viewing (100 cols x 40 rows)
sys.stdout.write("\033[8;40;100t")
os.system('clear') # Clean start
# Print branded banner
for line in BANNER.strip().split('\n'):
console.print(line, style="bold red", justify="center")
print_help()
# Command Loop
while True:
try:
cmd = input("\nDeep Focus> ").strip().lower()
if not cmd:
continue
if cmd == "/scan":
start_scan()
elif cmd == "/stop":
stop_scan()
elif cmd == "/settings":
configure_settings()
elif cmd == "/help":
print_help()
elif cmd == "/exit":
stop_scan()
console.print("[bold white]Goodbye.[/bold white]")
sys.exit(0)
else:
console.print("[dim]Unknown command. Type /help for list.[/dim]")
except KeyboardInterrupt:
print("\n") # Just new line, don't crash
if __name__ == "__main__":
main()