Explorando redes com ESP32 WIFI.
Recentemente, vivenciei uma situação peculiar em um banco durante uma revista em minha bolsa. Foi constatado que a entrada de notebooks não era permitida na área específica, levando o guarda encarregado da revista a retirar meu notebook, em conformidade com as normas estabelecidas.
No entanto, o que despertou minha curiosidade foi o fato de que outros dispositivos periféricos, como bateria, cabos e um ESP32, permaneceram na bolsa, possibilitando minha entrada na área restrita. Após adentrar o recinto, fui conduzido a uma sala para aguardar o gerente. Durante esse período, aproveitei para realizar uma análise do ambiente e, para minha surpresa, deparei-me com um papel sobre a mesa contendo as informações de login e senha da rede Wi-Fi interna.
Essa situação suscitou uma reflexão: se a restrição de entrada com notebooks visa à segurança, será que o ESP32 não poderia ser utilizado para efetuar ataques à rede? Com base nessa ponderação, optei por redigir este artigo com o intuito de explorar um estudo sobre redes, buscando compreendê-las sem a utilização de notebooks ou ferramentas avançadas como o nmap (por exemplo), concentrando-se apenas no ESP32.
É fundamental salientar que o propósito deste artigo é proporcionar informações relevantes sobre segurança, sendo estritamente um estudo teórico.
O que e arduino ?
Arduino é uma plataforma de prototipagem de código aberto que consiste em hardware e software projetados para facilitar o desenvolvimento de projetos eletrônicos. O hardware Arduino é baseado em placas de circuito integradas com microcontroladores e uma interface de programação. Já o software consiste em uma IDE (Ambiente de Desenvolvimento Integrado) que permite a programação dessas placas.
Principais características do Arduino:
- Microcontrolador: As placas Arduino são equipadas com microcontroladores que executam programas escritos em uma linguagem de programação derivada do C/C++.
- IDE Arduino: A IDE Arduino fornece um ambiente de programação simples e intuitivo, facilitando o desenvolvimento de código para controle de dispositivos e interação com sensores.
- Placas Variadas: Existem várias placas Arduino com diferentes especificações e tamanhos, desde placas básicas para projetos simples até modelos mais avançados com maior poder de processamento e recursos adicionais.
- Entradas e Saídas (I/O): As placas Arduino têm pinos de entrada/saída (I/O) que permitem a conexão a diferentes componentes eletrônicos, como sensores, LEDs, motores, entre outros.
- Comunicação: As placas Arduino suportam diferentes métodos de comunicação, como USB, UART, I2C e SPI, permitindo a interação com outros dispositivos e módulos.
- Comunidade Ativa: Arduino possui uma comunidade global ativa que compartilha projetos, códigos e oferece suporte, facilitando o aprendizado e a resolução de problemas.
O que é ESP32?
O ESP32 é um microcontrolador de baixo custo, baixa potência e altamente integrado, pertencente à família ESP8266. Desenvolvido pela Espressif Systems, uma empresa chinesa, este microcontrolador é amplamente utilizado em projetos de Internet das Coisas (IoT) devido às suas capacidades de conectividade Wi-Fi e Bluetooth.
Reconhecido por sua versatilidade e desempenho, o ESP32 oferece uma ampla gama de recursos, incluindo processador dual-core, conectividade sem fio, GPIOs (General Purpose Input/Output), capacidade de interface com sensores e periféricos, além de suporte a diversos protocolos de comunicação. Tais características fazem dele uma escolha popular para aplicações em IoT, automação residencial, projetos de eletrônica e desenvolvimento de protótipos.
Configuração Necessária
A seguir, listamos alguns itens essenciais para a realização do estudo de caso.
Conexao de rede.
No esp32 podemos se conectar na wifi e com isso iremos analisar o codigo simples que nos possibilita a conexao.
Segue abaixo o codigo:
#include <WiFi.h>
const char *ssid = "SEU_SSID";
const char *password = "SUA_SENHA";
void setup() {
Serial.begin(115200);
delay(10);
// Conectar-se à rede WiFi
Serial.println();
Serial.print("Conectando a ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Conectado ao WiFi");
Serial.print("Endereço IP: ");
Serial.println(WiFi.localIP());
}
void loop() {
}
Com referência ao exemplo anterior, procedemos com a explicação detalhada, partindo do código apresentado.
- Inclusão da Biblioteca WiFi:
#include <WiFi.h>
Isso inclui a biblioteca WiFi, necessária para lidar com as funcionalidades de conexão WiFi do ESP32.
- Definição das Credenciais da Rede WiFi:
const char *ssid = "SEU_SSID";
const char *password = "SUA_SENHA";
Substitua “SEU_SSID” e “SUA_SENHA” pelos respectivos SSID e senha da sua rede WiFi.
- Configuração do Ambiente no Método setup():
void setup() {
Serial.begin(115200);
delay(10);
Inicia a comunicação serial com uma taxa de 115200 bps e espera por 10 milissegundos.
- Conexão à Rede WiFi no Método setup():
Serial.println();
Serial.print("Conectando a ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
O programa imprime no console serial que está tentando se conectar à rede especificada.
WiFi.begin(ssid, password) inicia a conexão à rede WiFi usando as credenciais fornecidas.
O loop while espera até que a conexão seja estabelecida (WL_CONNECTED).
- Exibição de Informações Após a Conexão Bem-sucedida no Método setup():
Serial.println("");
Serial.println("Conectado ao WiFi");
Serial.print("Endereço IP: ");
Serial.println(WiFi.localIP());
Uma vez conectado, o programa imprime que foi conectado com sucesso e exibe o endereço IP atribuído ao ESP32.
- Método loop():
void loop() {
}
O método loop() está vazio neste exemplo. Este é o local onde você colocaria o código que deve ser executado continuamente após a inicialização.
O que faremos ?
Agora que adquirimos conhecimento sobre como realizar a conexão com o dispositivo, podemos ponderar sobre os seguintes aspectos:
- Possuo um periférico capaz de se integrar à rede.
- Esse periférico dispõe de capacidade de processamento.
- Ele opera utilizando uma linguagem de programação.
Diante dessas considerações, surge a pergunta: por que não desenvolver algo para explorar a rede?
A partir dessa premissa, exploraremos os endereços IP da rede para identificar portas abertas.
Atualmente, já possuímos:
- Conexão estabelecida com a rede WiFi.
- Atribuição dinâmica de endereço IP por meio do DHCP da rede.
Com base nessas informações, iniciaremos uma busca por portas abertas em possíveis computadores ou servidores.
A seguir, apresento o código correspondente:
#include <WiFi.h>
const char *ssid = "SEU_SSID";
const char *password = "SUA_SENHA";
// Lista de IPs a serem testados
IPAddress ips[255];
int currentIpIndex = 0;
// Lista de portas a serem testadas
int portas[] = {80, 443, 22};
void setup() {
Serial.begin(19200);
delay(10);
Serial.println("Conectando ao WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi conectado");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
scanner();
// Aguardar antes de repetir o teste
delay(5000);
}
void scanner() {
if (currentIpIndex >= 255) {
// Resetar o índice para começar de novo
currentIpIndex = 0;
}
// Extrair os três primeiros octetos do endereço IP
byte firstThreeOctets[3];
IPAddress localIP = WiFi.localIP();
for (int i = 0; i < 3; i++) {
firstThreeOctets[i] = localIP[i];
}
// Criar o IPAddress com base nos três primeiros octetos e no último octeto variável
IPAddress ipToTest(firstThreeOctets[0], firstThreeOctets[1], firstThreeOctets[2], currentIpIndex);
for (int j = 0; j < sizeof(portas) / sizeof(portas[0]); j++) {
WiFiClient client;
if (client.connect(ipToTest, portas[j])) {
Serial.printf("Conectado a %s na porta %d\n", ipToTest.toString().c_str(), portas[j]);
client.stop();
} else {
Serial.printf("Falha na conexão a %s na porta %d\n", ipToTest.toString().c_str(), portas[j]);
}
}
// Incrementar o índice para o próximo IP na próxima chamada
currentIpIndex++;
}
Inclusão de Bibliotecas:
#include <WiFi.h>
Essa parte do código inclui as bibliotecas necessárias para a comunicação com a rede WiFI.
const char *ssid = "SEU_SSID";
const char *password = "SUA_SENHA";
Substitua “SEU_SSID” e “SUA_SENHA” pelo nome e senha da sua rede WiFi.
Listas de IPs e Portas:
IPAddress ips[255];
int currentIpIndex = 0;
int portas[] = {80, 443, 22};
- ips: Uma lista de endereços IP a serem testados.
- currentIpIndex: Índice atual na lista de IPs.
- portas: Uma lista de portas a serem testadas.
Configuração no Método setup():
void setup() {
Serial.begin(19200);
delay(10);
Serial.println("Conectando ao WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi conectado");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
- Serial.begin(19200): Inicia a comunicação serial com uma taxa de 19200 bps.
- WiFi.begin(ssid, password): Inicia a conexão WiFi usando as credenciais fornecidas.
- while (WiFi.status() != WL_CONNECTED): Aguarda até que a conexão seja estabelecida.
Após a conexão bem-sucedida, o código imprime mensagens indicando que o WiFi foi conectado e exibe o endereço IP atribuído ao dispositivo.
Método loop():
void loop() {
scanner();
// Aguardar antes de repetir o teste
delay(5000);
}
O método loop() chama a função scanner() (que ainda não está definida neste código) para realizar o teste de porta e aguarda 5 segundos antes de repetir.
Método scanner():
void scanner() {
if (currentIpIndex >= 255) {
// Resetar o índice para começar de novo
currentIpIndex = 0;
}
- scanner(): Uma função que realiza a verificação de portas em diferentes IPs.
- if (currentIpIndex >= 255): Quando todos os IPs foram testados, o índice é resetado para reiniciar o processo.
Continuação do Método scanner():
// Extrair os três primeiros octetos do endereço IP
byte firstThreeOctets[3];
IPAddress localIP = WiFi.localIP();
for (int i = 0; i < 3; i++) {
firstThreeOctets[i] = localIP[i];
}
// Criar o IPAddress com base nos três primeiros octetos e no último octeto variável
IPAddress ipToTest(firstThreeOctets[0], firstThreeOctets[1], firstThreeOctets[2], currentIpIndex);
- firstThreeOctets: Extrai os três primeiros octetos do endereço IP local do dispositivo.
- IPAddress ipToTest: Cria um novo endereço IP usando os três primeiros octetos e o índice variável para o último octeto.
Continuação e Finalização do Método scanner():
for (int j = 0; j < sizeof(portas) / sizeof(portas[0]); j++) {
WiFiClient client;
if (client.connect(ipToTest, portas[j])) {
Serial.printf("Conectado a %s na porta %d\n", ipToTest.toString().c_str(), portas[j]);
client.stop();
} else {
Serial.printf("Falha na conexão a %s na porta %d\n", ipToTest.toString().c_str(), portas[j]);
}
}
// Incrementar o índice para o próximo IP na próxima chamada
currentIpIndex++;
}
Um loop que percorre a lista de portas e tenta conectar-se a cada combinação de IP e porta. Se a conexão for bem-sucedida, imprime a mensagem “Conectado”. Caso contrário, imprime “Falha na conexão”.
Exploração
Após a compilação e o upload no ESP32, o resultado na porta serial é apresentado da seguinte forma:
Com base nesse resultado, identificamos um IP (192.168.0.1) com a porta 80 aberta, possibilitando a enumeração de servidores e portas abertas no ambiente ao qual estamos conectados.
Vetores de Ataque
Considerando o ESP32, é possível realizar diversos tipos de ataques, tais como:
- Sniffer: Interceptação de dados em uma rede para análise.
- Scan de Portas: Identificação de portas abertas em um sistema.
- Scan de WiFi: Exploração de redes sem fio disponíveis.
- Ataque de Força Bruta: Tentativa de descobrir senhas por meio de repetidas combinações.
Com a proliferação de dispositivos portáteis no mundo da IoT, embora esses dispositivos ofereçam inovações significativas, também abrem oportunidades para ataques mais sofisticados, muitas vezes realizados com custos inferiores a 5 dólares.
Como se Proteger?
Para proteger-se contra esses vetores de ataques, é fundamental adotar práticas de segurança robustas, incluindo:
- Monitoramento Constante: Monitorar regularmente o tráfego e as atividades suspeitas na rede.
- Firewalls: Configurar firewalls para restringir o tráfego indesejado.
- Desabilitar Serviços Não Necessários: Desativar serviços que não são essenciais para reduzir a superfície de ataque.
- Filtro de Endereço MAC: Habilite o filtro de endereço MAC no roteador para permitir apenas dispositivos autorizados.Mantenha uma lista branca de endereços MAC permitidos.
- Desative o SSID Broadcasting: Desative a transmissão do nome da sua rede (SSID broadcast).Isso torna sua rede menos visível para scanners, mas não fornece segurança total.
Compartilhe seu carinho:
Estou verdadeiramente empenhado em criar conteúdo constante, explorando compras de equipamentos e ferramentas para trazer temas relevantes. Se você gostou deste artigo, ou de outros que compartilhei, e deseja oferecer seu apoio para me ajudar a continuar nessa jornada, ficaria imensamente grato. Cada contribuição é um passo significativo para manter viva essa paixão que compartilhamos.
Aqui está o link para apoiar: Buy Me a Coffee.
Obrigado pelo seu carinho e por fazer parte desta jornada! 🌟
Conclusão
Em conclusão, exploramos a conexão WiFi com o ESP32, aprendemos sobre a identificação de portas abertas na rede e discutimos medidas de segurança contra acessos não autorizados. O código apresentado mostrou como realizar um scanner de portas simples, ressaltando a importância de práticas seguras, atualizações regulares e consciência sobre potenciais vetores de ataques. Proteger sua rede WiFi é vital para garantir a segurança dos dispositivos conectados, e a implementação de medidas preventivas é fundamental para mitigar riscos e manter a integridade do ambiente digital.
Referências
https://www.espressif.com/en/products/socs/esp32
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html