Instalar a OpenSec
A versão publicada no repositório do projeto é a 0.1.0. O comando abaixo utiliza o índice Python configurado para a KatyushaSec.
python -m pip install --no-deps --index-url https://packages.katyushasec.net/simple/ opensec==0.1.0
Dependência de cifragem
O módulo MelisaCry importa a biblioteca
cryptography. Instala-a separadamente:
python -m pip install cryptography
O parâmetro --no-deps impede a instalação automática
de dependências. Se outros módulos da biblioteca vierem a exigir
dependências adicionais, estas terão de ser instaladas separadamente.
Importar os módulos
from OpenSec import Net, WebSec, MelisaCry
print(WebSec.resolve("example.com"))
print(Net.ports("192.168.1.10"))
Os nomes importados são os exportados pelo pacote. As operações de rede devem ser executadas apenas em equipamentos e redes sobre os quais tens autorização.
Como ler as assinaturas
Um parâmetro com valor atribuído, como timeout=10,
tem esse valor por omissão. Parâmetros sem valor predefinido
são obrigatórios, salvo indicação contrária.
Os métodos iniciados por _ são auxiliares internos.
Não devem ser considerados parte estável da API pública.
Net — análise de redes
Disponibiliza funções de descoberta de hosts, consulta de endereços MAC, verificação de portas TCP, identificação aproximada de sistemas operativos, recolha de banners e monitorização de tráfego.
Descoberta de hosts
Net.list_me()
Devolve uma lista com o endereço IP local e os hosts descobertos na rede.
Parâmetros: nenhum.
Retorno: list de endereços IP em formato textual.
from OpenSec import Net
hosts = Net.list_me()
for ip in hosts:
print(ip)
Net.list_me_mac()
Obtém um mapeamento de endereços IP para endereços MAC conhecidos.
Parâmetros: nenhum.
Retorno: dict no formato {IP: MAC}.
O IP local pode ter o valor None.
from OpenSec import Net
for ip, mac in Net.list_me_mac().items():
print(ip, mac)
Net.me
Propriedade que devolve o IP local guardado pela instância interna de rede.
Parâmetros: nenhum.
Retorno: endereço IP como str.
ip_local = Net.me
print(ip_local)
Portas TCP e identificação de serviços
Net.ports(ip, port_range=None, timeout=1.0)
Verifica a acessibilidade de portas TCP e tenta identificar o serviço através de um banner ou de uma tabela de serviços.
| Parâmetro | Tipo | Descrição |
|---|---|---|
ip | str, lista, tuplo ou conjunto | Endereço do alvo autorizado. Pode ser uma coleção de alvos. |
port_range | None, int ou intervalo de dois elementos | None usa as portas comuns; um inteiro testa uma porta; um tuplo/lista com início e fim inclui ambos os limites. |
timeout | float | Tempo limite de cada tentativa TCP, em segundos. Por omissão: 1.0. |
Retorno: dicionário ordenado de portas acessíveis para serviços identificados. Com vários alvos, devolve um dicionário por alvo e omite resultados vazios.
# Portas comuns
resultado = Net.ports("192.168.1.10")
# Uma porta
ssh = Net.ports("192.168.1.10", port_range=22)
# Intervalo inclusivo: 20 a 25
servicos = Net.ports("192.168.1.10", port_range=(20, 25))
# Vários alvos autorizados
rede = Net.ports(["192.168.1.10", "192.168.1.20"], timeout=1.5)
A ausência de uma porta no resultado não prova que o serviço não existe: firewalls, filtros, timeout e condições de rede podem influenciar a resposta.
Net.list_SO(ip)
Estima o sistema operativo com base no TTL e em sinais encontrados nos serviços acessíveis. Não é uma identificação definitiva.
Parâmetro: ip — endereço IP ou coleção de endereços.
Retorno individual: dicionário com so, confianca e detalhes. Para uma coleção, devolve um mapeamento de alvo para resultado.
info = Net.list_SO("192.168.1.10")
print(info["so"])
print(info["confianca"])
print(info["detalhes"])
A percentagem representa uma heurística implementada no código, não uma probabilidade estatística validada.
Net.ports_version(ip, port_range=None, timeout=1.0)
Verifica portas TCP acessíveis e tenta extrair a identificação e a versão de serviços através de banners.
ip | Endereço IP ou coleção de alvos autorizados. |
|---|---|
port_range | Portas comuns por omissão, uma porta inteira ou intervalo inclusivo em tuplo/lista. |
timeout | Tempo limite TCP em segundos; por omissão, 1.0. |
Retorno: dicionário de portas, cada uma com servico, versao e banner. A versão pode ser None se não for detetada.
versoes = Net.ports_version(
"192.168.1.10",
port_range=(20, 100),
timeout=1.5
)
for porta, dados in versoes.items():
print(porta, dados["servico"], dados["versao"])
Monitorização de tráfego
Net.static(clear_screen=False, sample_time=1.0)
Captura uma amostra de tráfego, converte os pacotes em linhas e apresenta o histórico guardado no terminal.
clear_screen | bool. Se True, limpa o terminal antes de apresentar os dados. Por omissão: False. |
|---|---|
sample_time | float. Duração da amostra em segundos. Por omissão: 1.0. |
Retorno: lista de linhas geradas para a amostra atual. A tabela apresentada no terminal utiliza o histórico interno, limitado a 500 linhas.
from OpenSec import Net
linhas = Net.static(sample_time=2.0)
print("Linhas desta amostra:", len(linhas))
A implementação apresentada utiliza a interface wlan0. Se essa interface não existir, a captura pode falhar. São também necessários Scapy ou tcpdump, conforme o caminho utilizado, e permissões adequadas.
Net.static_full(interval=1.0)
Repete a captura e a apresentação do tráfego continuamente até o utilizador interromper o processo.
Parâmetro: interval — intervalo de amostragem em segundos; por omissão, 1.0.
Retorno: não foi definido um valor de retorno útil; o método mantém o ciclo ativo e trata KeyboardInterrupt.
Net.static_full(interval=1.0)
# Para parar: Ctrl+C
WebSec — análise web e OSINT
Reúne métodos para consultar informações HTTP/TLS, DNS, WHOIS, conteúdo HTML, JavaScript, CSS, ligações, imagens, e-mails, contactos e verificações indicativas de XSS/CSRF.
Informação HTTP e TLS
WebSec.get_info(url, timeout=10)
Recolhe informações gerais sobre o URL, DNS, resposta HTTP, cabeçalhos, título da página, TLS (quando HTTPS) e um resumo WHOIS.
url | URL HTTP/HTTPS; se não tiver esquema, o código acrescenta HTTPS. |
|---|---|
timeout | Tempo limite do pedido HTTP em segundos; por omissão, 10. |
Retorno: dicionário com campos como host, ips, status, headers, titulo, tls e whois_resumo. Os campos disponíveis dependem do resultado da ligação.
info = WebSec.get_info("https://example.com", timeout=10)
print(info.get("status"))
print(info.get("ips"))
print(info.get("tls"))
WebSec.tls_info(host, port=443)
Estabelece uma ligação TLS e lê informações do certificado apresentado pelo servidor.
Parâmetros: host — nome de domínio ou host; port — porta TLS, por omissão 443.
Retorno: dicionário com emissor, sujeito, validade e dias restantes; em caso de falha, devolve um dicionário com erro.
certificado = WebSec.tls_info("example.com")
print(certificado)
DNS, reverso e WHOIS
WebSec.resolve(domain)
Resolve o domínio para os endereços IP encontrados pelo resolvedor do sistema.
Parâmetro: domain — nome do domínio.
Retorno: lista de endereços IP; lista vazia se a resolução falhar.
ips = WebSec.resolve("example.com")
print(ips)
WebSec.reverse(ip)
Tenta obter o nome de host associado a um endereço IP através de DNS reverso.
Parâmetro: ip — endereço IP.
Retorno: nome do host (str) ou None quando não é encontrado.
hostname = WebSec.reverse("8.8.8.8")
print(hostname)
WebSec.whois(domain)
Consulta o servidor WHOIS selecionado a partir do TLD e tenta converter linhas no formato chave/valor para um dicionário.
Parâmetro: domain — domínio a consultar.
Retorno: dicionário com campos encontrados e o texto original em _raw; em caso de falha, devolve erro.
dados = WebSec.whois("example.com")
print(dados)
A disponibilidade e o formato das respostas dependem do servidor WHOIS e do TLD. Nem todos os campos estarão presentes.
WebSec.trace(url_or_ip, max_hops=15)
Executa um rastreio de rota UDP com TTL progressivo.
url_or_ip | URL, nome de domínio ou endereço IP de destino. |
|---|---|
max_hops | Número máximo de saltos; por omissão, 15. |
Retorno: lista de dicionários com hop e ip. O valor "*" representa um salto sem resposta recebida dentro do timeout.
rota = WebSec.trace("example.com", max_hops=15)
for salto in rota:
print(salto["hop"], salto["ip"])
O código utiliza sockets UDP IPv4 e um timeout de dois segundos por salto. Firewalls e routers podem impedir respostas.
Extração de conteúdo web
WebSec.get_html(url, timeout=10)
Obtém o HTML da página, até ao limite de leitura definido no código.
Parâmetros: url — endereço HTTP/HTTPS; timeout — timeout em segundos, por omissão 10.
Retorno: dicionário com URL original/final, estado HTTP e html; em caso de sucesso inclui tamanho.
pagina = WebSec.get_html("https://example.com")
print(pagina.get("status"))
print(pagina.get("html"))
WebSec.get_js(url, timeout=10)
Extrai blocos JavaScript inline e referências a scripts externos presentes no HTML.
Parâmetros: url e timeout (segundos, por omissão 10).
Retorno: dicionário com js_inline e js_externos, além dos metadados da resposta.
scripts = WebSec.get_js("https://example.com")
print(scripts.get("js_inline"))
print(scripts.get("js_externos"))
As referências externas são extraídas do HTML, mas o método não descarrega o conteúdo desses ficheiros.
WebSec.get_css(url, timeout=10)
Extrai blocos CSS inline e referências a folhas de estilo externas.
Parâmetros: url e timeout (segundos, por omissão 10).
Retorno: dicionário com css_inline e css_externos, além dos metadados da resposta.
estilos = WebSec.get_css("https://example.com")
print(estilos.get("css_inline"))
print(estilos.get("css_externos"))
WebSec.get_links(url, timeout=10, internos=True, externos=True, unicos=True)
Extrai ligações HTML e classifica-as como internas ou externas em relação ao domínio da página.
url | URL da página a analisar. |
|---|---|
timeout | Timeout HTTP em segundos; por omissão 10. |
internos | Se True, inclui as ligações internas no resultado; por omissão, True. |
externos | Se True, inclui as ligações externas; por omissão, True. |
unicos | Se True, remove URLs duplicados; por omissão, True. |
Retorno: dicionário com links.internos, links.externos e links.outros_recursos (formulários e iframes).
links = WebSec.get_links(
"https://example.com",
internos=True,
externos=False,
unicos=True
)
print(links.get("links"))
WebSec.get_img(url, timeout=10)
Procura referências a imagens em etiquetas img, srcset, CSS inline e elementos input type="image".
Parâmetros: url e timeout em segundos, por omissão 10.
Retorno: objeto ImageSet, iterável e com os métodos urls() e save().
imagens = WebSec.get_img("https://example.com")
for imagem in imagens:
print(imagem)
print(imagens.urls())
Método associado: ImageSet.urls() devolve uma lista de URLs. ImageSet.save(pasta=".", timeout=15) descarrega as imagens para a pasta indicada.
pasta | Diretório de destino; por omissão, ".". |
|---|---|
timeout | Timeout por imagem, em segundos; por omissão, 15. |
Retorno de save(): dicionário com salvos, erros e pasta. O código limita cada leitura de imagem a 20 MB.
resultado = imagens.save(pasta="./imagens", timeout=15)
print(resultado["salvos"])
print(resultado["erros"])
E-mails e contactos
WebSec.get_email(url, timeout=10, whois=True, profundidade=0)
Procura e-mails no HTML da página e em páginas comuns de contacto. Opcionalmente consulta WHOIS e procura endereços ofuscados.
url | URL ou domínio de destino. |
|---|---|
timeout | Timeout de cada pedido em segundos; por omissão 10. |
whois | Se True, tenta obter e-mails através do WHOIS; por omissão, True. |
profundidade | Controla a procura adicional por ligações relacionadas com contacto. Por omissão, 0. |
Retorno: dicionário com dominio, emails, fontes e total.
resultado = WebSec.get_email(
"https://example.com",
timeout=10,
whois=True,
profundidade=0
)
print(resultado["emails"])
print(resultado["fontes"])
WebSec.get_ctt(url, timeout=10)
Extrai potenciais contactos e ligações sociais do HTML de uma página.
Parâmetros: url e timeout em segundos, por omissão 10.
Retorno: dicionário com url, emails, telefones, redes_sociais, possiveis_nomes e enderecos. Se a obtenção da página falhar, devolve os dados de erro disponíveis.
contactos = WebSec.get_ctt("https://example.com")
print(contactos.get("emails"))
print(contactos.get("telefones"))
print(contactos.get("redes_sociais"))
Os resultados são extraídos por padrões textuais e podem incluir falsos positivos ou omitir dados presentes em conteúdo dinâmico.
Verificações XSS e CSRF
WebSec.test_xss(url, payloads=None, timeout=10)
Identifica parâmetros em URLs e formulários, envia cargas de teste e regista possíveis reflexões na resposta. É uma verificação preliminar, não uma confirmação automática de vulnerabilidade explorável.
url | URL de uma aplicação autorizada a testar. |
|---|---|
payloads | Lista de cargas de teste. None utiliza os padrões definidos pela biblioteca. |
timeout | Timeout HTTP em segundos; por omissão 10. |
Retorno: objeto XssResult, com to_dict() para obter o dicionário e js(payload) para executar uma verificação com uma carga personalizada.
resultado = WebSec.test_xss(
"https://staging.example.com/search?q=test",
timeout=10
)
dados = resultado.to_dict()
print(dados["parametros_testados"])
print(dados["refletidos"])
print(dados["possiveis_xss"])
Para uma carga personalizada:
personalizado = resultado.js("<script>alert(1)</script>")
print(personalizado.to_dict())
O código não executa JavaScript no navegador: procura reflexões na resposta HTTP. A ausência de reflexão não prova que a aplicação está segura, e uma reflexão não prova, por si só, XSS explorável.
WebSec.test_crf(url, payloads=None, timeout=10)
Analisa formulários HTML à procura de campos cujos nomes pareçam indicar um token CSRF e regista se as cargas enviadas aparecem nas respostas.
url | URL de uma aplicação autorizada a testar. |
|---|---|
payloads | Lista de cargas personalizadas; None usa os padrões internos. |
timeout | Timeout HTTP em segundos; por omissão 10. |
Retorno: objeto de resultado com to_dict() e js(payload). O dicionário contém formularios, formularios_sem_token e testes.
resultado = WebSec.test_crf(
"https://staging.example.com/form",
timeout=10
)
dados = resultado.to_dict()
print(dados["formularios"])
print(dados["formularios_sem_token"])
print(dados["testes"])
Nota: o nome real do método no código é test_crf, não test_csrf. A deteção por nomes de campos não substitui a validação do mecanismo CSRF do servidor. Não executar estes testes em sistemas de terceiros sem autorização.
MelisaCry — cifragem de ficheiros
O módulo permite escolher um motor de cifragem, criar ou carregar
uma chave e cifrar/decifrar ficheiros individuais ou diretórios.
Requer o pacote externo cryptography.
MelisaCry.use(engine)
Define o motor de cifragem usado pelas operações seguintes.
Parâmetro: engine — "Fernet" ou "AES". A comparação não distingue maiúsculas de minúsculas.
Retorno: a própria classe MelisaCry, permitindo encadeamento. Um nome inválido gera ValueError.
from OpenSec import MelisaCry
MelisaCry.use("Fernet")
# ou
MelisaCry.use("AES")
Fernet usa a implementação fornecida por cryptography. O modo AES usa AES-256-GCM com nonce de 12 bytes. A escolha deve ser mantida consistente entre cifragem e decifragem.
MelisaCry.key(caminho="chave.txt")
Carrega uma chave existente do ficheiro indicado ou cria uma nova quando o ficheiro não existe ou está vazio.
Parâmetro: caminho — caminho do ficheiro da chave; por omissão, "chave.txt".
Retorno: objeto Key derivado de str, contendo a chave e a referência ao caminho usado.
chave = MelisaCry.key("./segredos/chave.txt")
print("Chave carregada/criada")
Protege a chave: não a publiques, não a envies em mensagens e não a guardes no mesmo local dos ficheiros cifrados sem uma estratégia de proteção. Perder a chave pode tornar os dados irrecuperáveis.
MelisaCry.crypt(caminho)
Prepara uma operação de cifragem para um ficheiro ou diretório.
Parâmetro: caminho — caminho existente para um ficheiro ou diretório.
Retorno: objeto de operação que disponibiliza by_key(chave).
chave = MelisaCry.key("./chave.txt")
resultado = MelisaCry.crypt("./documento.txt").by_key(chave)
print(resultado)
Após cifrar com sucesso, o ficheiro original é removido e o resultado recebe a extensão .melisa. Em diretórios, o código percorre os ficheiros recursivamente.
MelisaCry.decrypt(caminho)
Prepara uma operação de decifragem para um ficheiro cifrado ou diretório que contenha ficheiros com extensão .melisa.
Parâmetro: caminho — caminho do ficheiro ou diretório.
Retorno: objeto de operação que disponibiliza by_key(chave).
chave = MelisaCry.key("./chave.txt")
resultado = MelisaCry.decrypt("./documento.txt.melisa").by_key(chave)
print(resultado)
Na decifragem bem-sucedida, é criado o ficheiro sem a extensão .melisa e o ficheiro cifrado é mantido. A chave deve corresponder à utilizada na cifragem.
by_key(chave) — método da operação
Executa a operação preparada por crypt() ou decrypt().
Parâmetro: chave — objeto devolvido por MelisaCry.key(), string da chave válida ou caminho para um ficheiro que contenha a chave.
Retorno: dicionário com engine, operacao, alvo, arquivos_ok, erros, pulados e total.
# Cifrar
chave = MelisaCry.key("./chave.txt")
cifrar = MelisaCry.crypt("./ficheiros").by_key(chave)
# Decifrar
decifrar = MelisaCry.decrypt("./ficheiros").by_key(chave)
print(cifrar["total"])
print(cifrar["erros"])
print(decifrar["arquivos_ok"])
O código ignora ficheiros já cifrados durante a cifragem e ficheiros sem extensão .melisa durante a decifragem. Os ficheiros de chave identificados pela implementação são ignorados. Faz sempre uma cópia de segurança antes de testar.
Segurança, permissões e limitações
- Utiliza as funções de análise apenas em redes, sistemas e aplicações para os quais tens autorização.
- Resultados de deteção de SO, banners, e-mails, contactos e testes web são indicativos e podem conter falsos positivos.
- A captura de tráfego pode exigir privilégios elevados e ferramentas externas instaladas.
- A monitorização apresentada depende da interface
wlan0; adapta a implementação à interface real do sistema. - A cifragem remove o original após o sucesso. Mantém cópias de segurança e protege a chave antes de trabalhar com dados importantes.
- Não introduzas credenciais, chaves privadas ou dados pessoais nos exemplos públicos.