Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
55 changes: 45 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ pkg install nmap python libpcap -y
#### 🐍 Instalação das Bibliotecas Python (Comum a todos)

```bash
# Instalar as bibliotecas Python
pip3 install -r requirements.txt
# Instalar as bibliotecas Python em um único comando
pip3 install scapy==2.5.0 python-nmap==0.7.1 whois==0.9.27 colorama==0.4.6
```

#### 🐧 Debian/Ubuntu
Expand All @@ -59,20 +59,34 @@ sudo apt update
sudo apt install -y nmap python3-scapy
```

O arquivo `requirements.txt` contém:
As dependências Python são: `scapy==2.5.0`, `python-nmap==0.7.1`, `whois==0.9.27`, `colorama==0.4.6`.

```
scapy
python-nmap
requests
whois
colorama
### ✅ Instalação Rápida (Passo a Passo)

```bash
# 1) Instalar dependências de sistema (exemplo Debian/Ubuntu)
sudo apt update
sudo apt install -y nmap python3-scapy

# 2) Instalar dependências Python (com versões fixas)
pip3 install scapy==2.5.0 python-nmap==0.7.1 whois==0.9.27 colorama==0.4.6

# 3) Executar a ferramenta
python3 main.py --help
```

## ⚙️ Como Usar

O toolkit é executado através do arquivo principal `main.py` com subcomandos.

### ✅ Modo Interativo (UI no Terminal)

Se preferir uma experiência guiada, use o modo interativo com menu no terminal:

```bash
python3 main.py ui
```

### 1. Análise de Rede (`net`)

#### ARP Scan (Descoberta de Hosts)
Expand All @@ -81,7 +95,7 @@ O toolkit é executado através do arquivo principal `main.py` com subcomandos.
```bash
sudo python3 main.py net arp <faixa_de_ip>
# Exemplo:
sudo python3 main.py net arp 192.168.1.1/24
sudo python3 main.py net arp 192.0.2.0/24
```

#### Port Scan (Varredura de Portas)
Expand Down Expand Up @@ -134,5 +148,26 @@ sudo python3 main.py sniff -t 30

* **Privilégios de Root (sudo):** As funcionalidades de baixo nível de rede, como **ARP Scan** e **Sniffer de Rede**, exigem privilégios de root (`sudo`) para acessar a interface de rede e enviar/receber pacotes brutos.
* **Uso Ético:** Esta ferramenta é destinada a fins educacionais e testes de penetração **autorizados**. O uso indevido contra sistemas sem permissão expressa é ilegal e antiético. O desenvolvedor não se responsabiliza por qualquer uso indevido desta ferramenta.
* **Validação de entradas:** Os módulos de varredura validam alvo e faixa de portas para reduzir erros e evitar entradas inválidas. Garanta que os alvos estejam corretos antes de executar os scans.
* **Interface:** A aplicação utiliza a biblioteca `colorama` para uma melhor experiência visual no terminal.

## 🧰 Solução de Problemas (Troubleshooting)

Se você encontrar falhas na execução, revise os pontos abaixo:

* **Erro ao usar `scapy` ou `nmap`:** instale as dependências de sistema (`nmap` e `python3-scapy` ou equivalentes) conforme as instruções de Fedora/Ubuntu/Termux acima.
* **PermissionError em `net arp` ou `sniff`:** execute com `sudo`, pois essas operações precisam de acesso à interface de rede.
* **Ambiente virtual (venv):** se estiver usando venv, pode ser necessário executar o Python do venv com `sudo` para que o `scapy` tenha acesso às interfaces de rede.

## 🔒 Considerações de Segurança e Engenharia

Para transparência e auditoria:

* **Execução de comandos:** o toolkit não utiliza `eval`, `exec` ou `os.system`, evitando superfícies clássicas de injeção de comandos.
* **Validação de entrada:** há validações de alvo, faixa de portas, rede e caminhos de arquivo, reduzindo erros de execução e entradas malformadas.
* **Concorrência:** as varreduras atuais usam fluxo sequencial; para ambientes grandes, recomenda-se evoluir para `asyncio`/`threading` conforme o caso.
* **Logs e auditoria:** se você precisa de rastreabilidade, considere adicionar logging estruturado (ex.: módulo `logging`) com níveis apropriados e sem dados sensíveis.

## 📄 Licença

Este projeto é distribuído sob a licença MIT. Consulte o arquivo `LICENSE` para detalhes.
31 changes: 30 additions & 1 deletion info_analysis.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
import hashlib
import os
import socket
import re
import whois
import requests
from colorama import Fore, Style

DOMAIN_LABEL_PATTERN = re.compile(r"^[A-Za-z0-9-]{1,63}$")

def _is_valid_domain(domain):
if not domain or any(char.isspace() for char in domain):
return False
if len(domain) > 253:
return False
parts = domain.rstrip(".").split(".")
return all(
part
and DOMAIN_LABEL_PATTERN.match(part)
and not part.startswith("-")
and not part.endswith("-")
for part in parts
)

def calculate_file_hash(file_path, algorithm='sha256'):
"""
Calcula o hash de um arquivo usando o algoritmo especificado.
Expand All @@ -13,6 +30,12 @@ def calculate_file_hash(file_path, algorithm='sha256'):
if not os.path.exists(file_path):
print(f"{Fore.RED}Erro: Arquivo não encontrado em {file_path}{Style.RESET_ALL}")
return None
if not os.path.isfile(file_path):
print(f"{Fore.RED}Erro: O caminho informado não é um arquivo válido.{Style.RESET_ALL}")
return None
if os.path.islink(file_path):
print(f"{Fore.RED}Erro: Links simbólicos não são permitidos para cálculo de hash.{Style.RESET_ALL}")
return None

hash_func = hashlib.new(algorithm)
with open(file_path, 'rb') as f:
Expand All @@ -36,6 +59,9 @@ def whois_lookup(domain):
"""
Realiza uma consulta Whois para um domínio.
"""
if not _is_valid_domain(domain):
print(f"{Fore.RED}Erro: Domínio inválido para consulta Whois.{Style.RESET_ALL}")
return None
print(f"{Fore.CYAN}Realizando consulta Whois para {domain}...{Style.RESET_ALL}")
try:
w = whois.whois(domain)
Expand All @@ -50,6 +76,9 @@ def dns_lookup(domain):
"""
Realiza uma consulta DNS básica para obter o endereço IP.
"""
if not _is_valid_domain(domain):
print(f"{Fore.RED}Erro: Domínio inválido para consulta DNS.{Style.RESET_ALL}")
return None
print(f"{Fore.CYAN}Realizando consulta DNS para {domain}...{Style.RESET_ALL}")
try:
ip_address = socket.gethostbyname(domain)
Expand Down
71 changes: 70 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
import sys
import os
import whois
from colorama import Fore, Style, init

# Inicializa colorama para funcionar em diferentes terminais
Expand Down Expand Up @@ -76,6 +77,68 @@ def display_results(title, data):
print(f"{Fore.YELLOW}A operação não retornou dados ou falhou.{Style.RESET_ALL}")


def _prompt_non_empty(prompt_text):
while True:
value = input(prompt_text).strip()
if value:
return value
print(f"{Fore.YELLOW}Entrada vazia. Tente novamente.{Style.RESET_ALL}")


def run_interactive_menu():
"""Executa um menu interativo para uso guiado do toolkit."""
print(f"{Fore.GREEN}Modo interativo iniciado. Selecione uma opção:{Style.RESET_ALL}")
while True:
print(
f"""
{Fore.BLUE}1){Style.RESET_ALL} ARP Scan
{Fore.BLUE}2){Style.RESET_ALL} Port Scan
{Fore.BLUE}3){Style.RESET_ALL} Calcular Hash de Arquivo
{Fore.BLUE}4){Style.RESET_ALL} Whois Lookup
{Fore.BLUE}5){Style.RESET_ALL} DNS Lookup
{Fore.BLUE}6){Style.RESET_ALL} Sniffer de Pacotes
{Fore.BLUE}0){Style.RESET_ALL} Sair
"""
)
choice = input("Opção: ").strip()

if choice == "1":
ip_range = _prompt_non_empty("Faixa de IP (ex: 192.0.2.0/24): ")
results = arp_scan(ip_range)
display_results(f"Resultados do ARP Scan em {ip_range}", results)
elif choice == "2":
target = _prompt_non_empty("Alvo (IP ou domínio): ")
ports = input("Portas (ex: 22,80,443 ou 1-100) [1-1024]: ").strip() or "1-1024"
results = port_scan(target, ports)
display_results(f"Resultados do Port Scan em {target}", results)
elif choice == "3":
file_path = _prompt_non_empty("Caminho para o arquivo: ")
algorithm = input("Algoritmo [sha256]: ").strip() or "sha256"
file_hash = calculate_file_hash(file_path, algorithm)
display_results(f"Hash {algorithm.upper()} do Arquivo", file_hash)
elif choice == "4":
domain = _prompt_non_empty("Domínio (ex: example.com): ")
whois_info = whois_lookup(domain)
display_results(f"Whois Lookup para {domain}", whois_info)
elif choice == "5":
domain = _prompt_non_empty("Domínio (ex: example.com): ")
ip = dns_lookup(domain)
display_results(f"DNS Lookup para {domain}", ip)
elif choice == "6":
print(f"{Fore.YELLOW}Atenção: O Sniffer de Pacotes requer privilégios de root (sudo).{Style.RESET_ALL}")
interface = input("Interface (opcional): ").strip() or None
count_input = input("Número de pacotes (0 para ilimitado) [0]: ").strip()
timeout_input = input("Tempo limite em segundos (opcional): ").strip()
count = int(count_input) if count_input.isdigit() else 0
timeout = int(timeout_input) if timeout_input.isdigit() else None
start_sniffer(interface, count, timeout)
elif choice == "0":
print(f"{Fore.GREEN}Encerrando modo interativo.{Style.RESET_ALL}")
break
else:
print(f"{Fore.YELLOW}Opção inválida. Escolha novamente.{Style.RESET_ALL}")


def main():
print_banner()

Expand All @@ -88,7 +151,7 @@ def main():

# ARP Scan
arp_parser = net_subparsers.add_parser('arp', help='Realiza um ARP Scan para descoberta de hosts (Requer sudo)')
arp_parser.add_argument('ip_range', help='Faixa de IP (ex: 192.168.1.1/24)')
arp_parser.add_argument('ip_range', help='Faixa de IP (ex: 192.0.2.0/24)')

# Port Scan
port_parser = net_subparsers.add_parser('port', help='Realiza um Port Scan TCP (usando nmap)')
Expand Down Expand Up @@ -118,6 +181,9 @@ def main():
sniff_parser.add_argument('-c', '--count', type=int, default=0, help='Número de pacotes a capturar (0 para ilimitado)')
sniff_parser.add_argument('-t', '--timeout', type=int, default=None, help='Tempo máximo de captura em segundos')

# --- Subparser para Interface ---
subparsers.add_parser('ui', help='Inicia o modo interativo com menu guiado')


args = parser.parse_args()

Expand All @@ -144,6 +210,9 @@ def main():
print(f"{Fore.YELLOW}Atenção: O Sniffer de Pacotes requer privilégios de root (sudo) para funcionar corretamente.{Style.RESET_ALL}")
start_sniffer(args.interface, args.count, args.timeout)

elif args.command == 'ui':
run_interactive_menu()

elif args.command is None:
parser.print_help()

Expand Down
50 changes: 49 additions & 1 deletion network_scanner.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,55 @@
import ipaddress
import nmap
import re
import socket
from scapy.all import ARP, Ether, srp
from colorama import Fore, Style

PORTS_PATTERN = re.compile(r"^\d{1,5}(-\d{1,5})?(,\d{1,5}(-\d{1,5})?)*$")

def _is_valid_ports(ports):
if not ports or not PORTS_PATTERN.match(ports):
return False
for part in ports.split(","):
if "-" in part:
start, end = part.split("-", 1)
if not (start.isdigit() and end.isdigit()):
return False
start_i, end_i = int(start), int(end)
if start_i < 1 or end_i > 65535 or start_i > end_i:
return False
else:
if not part.isdigit():
return False
value = int(part)
if value < 1 or value > 65535:
return False
return True

def _is_valid_target(target):
if not target or any(char.isspace() for char in target):
return False
try:
ipaddress.ip_address(target)
return True
except ValueError:
pass
if len(target) > 253:
return False
label_regex = re.compile(r"^[A-Za-z0-9-]{1,63}$")
parts = target.rstrip(".").split(".")
return all(part and label_regex.match(part) and not part.startswith("-") and not part.endswith("-") for part in parts)

def arp_scan(ip_range):
"""
Realiza um ARP Scan para descobrir hosts ativos na rede local.
Requer privilégios de root (sudo) para funcionar corretamente.
"""
try:
ipaddress.ip_network(ip_range, strict=False)
except ValueError:
print(f"{Fore.RED}Erro: Faixa de IP inválida para ARP Scan (ex: 192.0.2.0/24).{Style.RESET_ALL}")
return []
print(f"{Fore.CYAN}Iniciando ARP Scan em {ip_range}...{Style.RESET_ALL}")
try:
# Cria o pacote ARP
Expand Down Expand Up @@ -38,6 +80,12 @@ def port_scan(target_ip, ports='1-1024'):
"""
Realiza um Port Scan TCP usando nmap.
"""
if not _is_valid_target(target_ip):
print(f"{Fore.RED}Erro: Alvo inválido para o Port Scan. Use um IP ou domínio válido.{Style.RESET_ALL}")
return {}
if not _is_valid_ports(ports):
print(f"{Fore.RED}Erro: Faixa de portas inválida. Use números de 1-65535 separados por vírgulas ou intervalos (ex: 22,80,443 ou 1-100).{Style.RESET_ALL}")
return {}
print(f"{Fore.CYAN}Iniciando Port Scan em {target_ip} (Portas: {ports})...{Style.RESET_ALL}")
try:
nm = nmap.PortScanner()
Expand Down Expand Up @@ -74,7 +122,7 @@ def port_scan(target_ip, ports='1-1024'):

if __name__ == '__main__':
# Exemplo de uso (requer sudo para arp_scan)
# hosts = arp_scan("192.168.1.1/24")
# hosts = arp_scan("192.0.2.0/24")
# print(hosts)

# Exemplo de uso (não requer sudo)
Expand Down
5 changes: 0 additions & 5 deletions requirements.txt

This file was deleted.