Introdução
No projeto anterior, desenvolvemos um scanner de portas em Python que utilizava threading e sockets para escanear portas TCP. Embora eficaz, há margem para melhorias através do uso de pacotes de terceiros.
Neste projeto, vamos aprimorar nosso scanner de portas integrando a biblioteca python-nmap, que oferece capacidades de varredura muito mais robustas. Além disso, construiremos uma aplicação web usando Flask para fornecer uma interface amigável ao usuário. Este projeto passo a passo guiará você por todo o processo, garantindo que você possa acompanhar e expandir seus conhecimentos existentes.
👀 Prévia
🎯 Tarefas
Neste projeto, você aprenderá:
- Como configurar um projeto Flask e organizar sua estrutura
- Como usar o Flask-WTF para criar e manipular formulários web de forma segura
- Como implementar rotas no Flask para gerenciar requisições e envios de páginas web
- Como utilizar a biblioteca Nmap no Python para realizar varreduras de portas
- Como exibir resultados de varredura dinamicamente em uma página web usando Flask e templates HTML
- Como aplicar o Tailwind CSS básico para aprimorar o design do frontend
🏆 Conquistas
Após concluir este projeto, você será capaz de:
- Demonstrar uma compreensão fundamental do desenvolvimento web com Flask, incluindo roteamento, renderização de templates e manipulação de formulários
- Aplicar experiência prática na integração de scripts Python com interfaces web
- Exibir proficiência no uso da biblioteca Nmap para tarefas de varredura de rede
- Utilizar o Flask-WTF para criação e validação de formulários em uma aplicação web
- Demonstrar familiaridade com o uso do Tailwind CSS para estilizar páginas web e melhorar o design da interface do usuário
- Criar uma aplicação funcional baseada na web que interage com scripts Python no backend para realizar varreduras de rede
Implementando a Página Inicial
Para começar, abra o arquivo templates/index.html e adicione o código a seguir para garantir que o formulário esteja configurado corretamente para enviar as solicitações de varredura:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TCP Port Scanner</title>
<link
href="https://cdn.jsdelivr.net/npm/tailwindcss@2.0.3/dist/tailwind.min.css"
rel="stylesheet"
/>
<script>
function updateButton() {
var submitButton = document.getElementById("scanButton");
submitButton.value = "Scanning...";
submitButton.classList.add("cursor-not-allowed", "opacity-50");
submitButton.disabled = true;
}
</script>
</head>
<body class="bg-gray-100 flex items-center justify-center h-screen">
<div class="bg-white p-8 rounded-lg shadow-md">
<h1 class="text-2xl font-bold mb-4">TCP Port Scanner</h1>
<form action="" method="post" class="space-y-4"
{{ form.hidden_tag() }}
<div>
{{ form.host.label(class="block text-sm font-medium text-gray-700") }}
{{ form.host(class="mt-1 block w-full rounded-md border-gray-300
shadow-sm focus:border-indigo-500 focus:ring-indigo-500") }}
</div>
<div>
{{ form.ports.label(class="block text-sm font-medium text-gray-700")
}} {{ form.ports(class="mt-1 block w-full rounded-md border-gray-300
shadow-sm focus:border-indigo-500 focus:ring-indigo-500") }}
</div>
<div>
{{ form.submit(id="scanButton", class="w-full flex justify-center py-2
px-4 border border-transparent rounded-md shadow-sm text-sm
font-medium text-white bg-indigo-600 hover:bg-indigo-700
focus:outline-none focus:ring-2 focus:ring-offset-2
focus:ring-indigo-500") }}
</div>
</form>
</div>
</body>
</html>
O template index.html fornece uma interface intuitiva para que o usuário informe o host e o intervalo de portas para a varredura. O formulário HTML inclui dois campos principais: um para o endereço do host e outro para especificar o intervalo de portas.
O Flask-WTF, uma extensão do Flask para trabalhar com WTForms, é utilizado para renderizar esses campos no template. O envio do formulário é aprimorado por uma pequena função JavaScript updateButton() que altera o texto do botão de envio para "Scanning..." assim que o formulário é enviado. Esse feedback visual informa ao usuário que sua solicitação de varredura está sendo processada.
A estilização da página é feita com o Tailwind CSS, um framework CSS utilitário que permite o desenvolvimento rápido de interfaces.
Implementando a Página de Resultados da Varredura
Abra o arquivo templates/results.html e certifique-se de incluir o código a seguir para exibir os resultados da varredura:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scan Results</title>
<link
href="https://cdn.jsdelivr.net/npm/tailwindcss@2.0.3/dist/tailwind.min.css"
rel="stylesheet"
/>
</head>
<body class="bg-gray-100">
<div class="flex flex-col items-center justify-center min-h-screen">
<div class="bg-white p-8 rounded-lg shadow-lg w-full max-w-4xl">
<h1 class="text-2xl font-bold mb-4 text-center">
Scan Results for {{ host }}
</h1>
<div class="overflow-x-auto">
<table class="table-auto w-full text-left whitespace-no-wrap">
<thead>
<tr
class="text-xs font-semibold tracking-wide text-left text-gray-500 uppercase border-b dark:border-gray-700 bg-gray-50"
>
<th class="px-4 py-3">PORT</th>
<th class="px-4 py-3">STATE</th>
<th class="px-4 py-3">SERVICE</th>
<th class="px-4 py-3">VERSION</th>
</tr>
</thead>
<tbody
class="bg-white divide-y dark:divide-gray-700 dark:bg-gray-800"
>
{% for result in scan_results %}
<tr class="text-gray-700 dark:text-gray-400">
<td class="px-4 py-3 text-sm">{{ result.port }}/tcp</td>
<td class="px-4 py-3 text-sm">{{ result.state }}</td>
<td class="px-4 py-3 text-sm">{{ result.name }}</td>
<td class="px-4 py-3 text-sm">
{{ result.product }} {{ result.version }} {{ result.extra }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
O template results.html é responsável por mostrar o desfecho da varredura de portas. Ele apresenta os resultados em formato de tabela, listando cada porta com seu estado correspondente, nome do serviço e versão do serviço, caso esteja disponível.
Este template utiliza Tailwind CSS para a estilização, garantindo que a página de resultados seja responsiva e visualmente atraente. O uso do motor de templates Jinja2 (integrado ao Flask) permite a renderização de conteúdo dinâmico, onde os resultados da varredura são passados da aplicação Flask para o template e percorridos para preencher a tabela.
Inicializando a Aplicação Flask
Nesta etapa, criaremos o script Python principal para nossa aplicação Flask.
Adicione o seguinte código em app.py:
## Import necessary modules
from flask import Flask, render_template, request, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Regexp
import nmap
## Initialize Flask app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'labex'
## Initialize Nmap PortScanner
nm = nmap.PortScanner()
## Define Flask-WTF form for scanning inputs
class ScanForm(FlaskForm):
host = StringField('Host', validators=[DataRequired()])
ports = StringField('Port Range', validators=[DataRequired(), Regexp(r'^\d+-\d+$', message="Format must be start-end")])
submit = SubmitField('Scan')
Nesta etapa, a aplicação Flask e a classe do formulário são inicializadas.
O script app.py começa importando os módulos necessários, incluindo o próprio Flask, o Flask-WTF para manipulação de formulários e o Nmap para realizar as varreduras de portas. A instância da aplicação Flask é criada e configurada com uma chave secreta para proteção contra ataques CSRF.
A classe ScanForm define os campos do formulário para as entradas de host e intervalo de portas, utilizando validadores para garantir que os dados sejam fornecidos e estejam no formato correto (especificamente para o intervalo de portas).
Substitua 'your_secret_key' por uma chave secreta real, que é usada para proteger os formulários contra ataques CSRF.
Gerenciando a Rota Inicial
Nesta etapa, vamos gerenciar a rota inicial onde os usuários podem enviar o host e o intervalo de portas que desejam escanear. Adicione a seguinte função ao arquivo app.py:
## Define route for the index page
@app.route('/', methods=['GET', 'POST'])
def index():
form = ScanForm() ## Instantiate the form
if form.validate_on_submit():
## Get data from the form
host = form.host.data
ports = form.ports.data ## Format: "start-end"
## Redirect to the scan route with form data
return redirect(url_for('scan', host=host, ports=ports))
## Render the index page template with the form
return render_template('index.html', form=form)
Esta parte do script app.py define a rota para a página inicial da aplicação web. A função index() renderiza o template index.html junto com a instância do ScanForm.
Quando o formulário é enviado e passa pelas verificações de validação, a função redireciona o usuário para a rota de varredura, passando os dados do formulário (host e intervalo de portas) via parâmetros de URL. Esse redirecionamento inicia o processo de varredura.
Implementando a Rota de Varredura
Esta etapa envolve a criação de uma rota para realizar a varredura propriamente dita e exibir os resultados. Adicione a seguinte função ao arquivo app.py:
## Define route for the scan results
@app.route('/scan')
def scan():
## Retrieve host and ports from the query string
host = request.args.get('host')
ports = request.args.get('ports')
## Perform the scan using Nmap
nm.scan(hosts=host, ports=ports, arguments='-sV') ## -sV for service/version detection
scan_results = []
## Process scan results and store them in a list
for host in nm.all_hosts():
for proto in nm[host].all_protocols():
lport = nm[host][proto].keys()
for port in lport:
service = nm[host][proto][port]
scan_results.append({
'port': port,
'state': service['state'],
'name': service.get('name', 'Unknown'),
'product': service.get('product', ''),
'version': service.get('version', ''),
'extra': service.get('extrainfo', '')
})
## Render the results page template with the scan results
return render_template('results.html', scan_results=scan_results, host=host)
A função scan() gerencia a rota encarregada de realizar a varredura de portas real e exibir os resultados. Ela recupera o host e o intervalo de portas a partir dos parâmetros da string de consulta passados na URL.
Utilizando a instância do Nmap PortScanner, ela conduz uma varredura no host e portas especificados, com o argumento -sV para detectar as versões dos serviços.
Os resultados da varredura são processados e organizados em uma lista de dicionários, cada um contendo detalhes sobre uma porta escaneada. Esses detalhes são então passados para o template results.html, onde são exibidos para o usuário.
Executando a Aplicação Flask
Com todos os componentes prontos, você agora pode executar a aplicação Flask e dar vida ao seu scanner de portas TCP. O último trecho de código necessário no seu app.py garante que a aplicação Flask só será executada se o script for chamado diretamente, e não se for importado como um módulo em outro script. Este é um padrão comum em aplicações Python que incluem um script executável.
Coloque o seguinte trecho de código ao final do seu arquivo app.py:
if __name__ == '__main__':
app.run(debug=True, port=8080, host='0.0.0.0')
Este código instrui o Flask a iniciar sua aplicação com a depuração (debug) ativada, facilitando o rastreamento de erros. A aplicação escutará em todas as interfaces de rede (host='0.0.0.0') e usará a porta 8080. O modo de depuração deve ser usado apenas durante o desenvolvimento, pois pode ser inseguro em um ambiente de produção.
Para executar sua aplicação Flask, certifique-se de estar no diretório do projeto onde o arquivo app.py está localizado. Em seguida, execute o seguinte comando no terminal:
python app.py
Mude para a aba Web 8080 para acessar o scanner de portas TCP. Agora você pode inserir um host e um intervalo de portas para escanear e visualizar os resultados na página de resultados.
As portas 22 e 3306 são amplamente associadas aos serviços SSH e MySQL, respectivamente, enquanto a porta 3000 é utilizada para os ambientes WebIDE.
Resumo
Neste projeto, você aprendeu como construir um scanner de portas TCP baseado na web, simples porém poderoso, utilizando Flask e Nmap. Começamos configurando o ambiente do projeto e instalando as dependências necessárias. Em seguida, avançamos na criação da aplicação Flask, manipulando o envio de formulários, realizando a varredura de portas e exibindo os resultados de maneira amigável. Este projeto serve como uma excelente introdução ao desenvolvimento web com Flask e à varredura de rede com Nmap, oferecendo uma aplicação prática que combina ambas as habilidades.



