Construindo seu port scanner com bibliotecas internas do Python
Postado 16 Fevereiro 2020
Esse pequeno artigo mostrará, como você pode construir a port scanner com bibliotecas
internas do Python e sem a necessidade de instalar bibliotecas externas.
Muitas vezes quando nós estamos executando um troubleshooting ou um pentest, nós precisamos
verificar se há conectividade entre dois hosts. Normalmente nesse processo nos utilizamos
ferramentas tais como: nmap, NetCat, Telnet, Hping3 e etc. Companhias que tem uma política
de segurança executam um processo chamado "Hardening". Esse processo consiste
em remover todas as ferramentas desnecessárias para o propósito do servidor.
O script mostrado aqui te ajudará nessa tarefa, consequentemente se você está executando
um pentest gerará menos ruído. Ele executará um scan do tipo Full Connection, ou seja,
o three handshake irá completar. Posteriormente em outro artigo, eu mostrarei como nós
podemos executar um scan do tipo Stealth, Xmas e outros.
A seguir, eu listo todas as bibliotecas utilizadas no script.
A versão do Python utilizada foi: 3.8.1
Vamos começar!
Classe Principal
import sys
import errno
import os
import argparse
import ipaddress
class MyPortScanner(object):
def __init__(self, target, portlist):
self.target = target
if type(portlist) is str:
self.portlist = [int(x) for x in portlist.split(',')]
else:
self.portlist = portlist
Nessa primeira parte, nós somente importamos as bibliotecas necessárias e definimos o
construtor da classe. Ele receberá dois parâmetros: IP alvo e portas. Se o usuário passar
uma lista de portas separadas por virgulas, nos geraremos uma lista de inteiros com essa
lista de portas.
Função para verificar portas
def check_port_socket_v4_tcp(self):
print('--------------------------------')
print('[+] Iniciando o scan...')
print('[i] Host alvo: {}'.format(self.target))
print('[i] Portas: {}'.format(self.portlist))
try:
for port in self.portlist:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(3)
result = s.connect_ex((str(self.target), port))
if result == 0:
print('[+] Port {}: Open'.format(port))
else:
print('[!] Porta {}: Fechada'.format(port))
print('\t[-] Código de erro: {}'.format(errno.errorcode[result]))
print('\t[-] Mensagem: {}'.format(os.strerror(result)))
s.close()
except socket.error as e:
print(str(e))
print('[-] Erro de conexão!')
sys.exit()
print('[+] Script finalizado.')
Aqui nosso script começa a ser construído. Nós definimos a função chamada "check_port_socket_v4_tcp"
que espera um parâmetro: a instancia da classe. Após isso algumas informações são mostradas
e se inicia um loop para testar todas as portas na lista portlist. Na próxima
linha nós criamos um objeto da classe socket com os seguintes parâmetros: AF_INET == IPv4
e SOCK_STREAM == TCP. Após isso nós configuramos um timeout para 3 segundos e finalmente
nós testamos a porta e savamos o resultado do teste na variável "result"
Por fim nós verificamos o resultado, se o resultado é 0 então a porta está Aberta,
caso contrário estará fechada por váras razões.
Testando o script
joaopaulo@Joaos-MacBook-Air scanner % python3 sample_port_scanner.py -t 54.207.20.104 -p 80,443,445
--------------------------------
[+] Iniciando o scan...
[i] Host alvo: 54.207.20.104
[i] Portas: [80, 443, 445]
[+] Porta 80: Aberta
[+] Porta 443: Aberta
[!] Porta 445: Fechada
[-] Código de erro: EAGAIN
[-] Mensagem: Resource temporarily unavailable
[+] Script finalizado.
Para testar seu script, abra uma sessão do prompt de comando e passe 2 parâmetros:
-t para definir o alvo e -p (não é obrigatório) para definir as portas a serem
verificadas. Por exemplo: python3 sample_port_scanner.py -t 54.207.20.104
-p 80,443,445
Código completo
# Import modules
import socket
import sys
import errno
import os
import argparse
import ipaddress
# Main Class
class MyPortScanner(object):
# Constructor, receive two parameters: target = IP that will be scanned and list of port that will be tested
def __init__(self, target, portlist):
self.target = target
if type(portlist) is str:
self.portlist = [int(x) for x in portlist.split(',')]
else:
self.portlist = portlist
# Function that performs the scan on v4 family
def check_port_socket_v4_tcp(self):
print('--------------------------------')
print('[+] Initializing scan...')
print('[i] Target host: {}'.format(self.target))
print('[i] Ports: {}'.format(self.portlist))
try:
for port in self.portlist:
# Create the v4 socket, AF_INET == V4 Family, SOCK_STREAM == TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Define the timeout of response to 3 seconds
s.settimeout(3)
result = s.connect_ex((str(self.target), port))
# If the return code is 0 then the port is OPEN
if result == 0:
print('[+] Port {}: Open'.format(port))
# Otherwise, the port is closed
else:
print('[!] Port {}: Closed'.format(port))
print('\t[-] Code error: {}'.format(errno.errorcode[result]))
print('\t[-] Message: {}'.format(os.strerror(result)))
s.close()
# If have any problem with connection, the scan will be aborted
except socket.error as e:
print(str(e))
print('[-] Connection Error')
sys.exit()
print('[+] Script finished.')
# Performs the script
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Scan ports TCP\nVersion: 0.1')
# Target parameter, accept just IPV4 Address
parser.add_argument('-t', dest='target_host_v4', help='Target host IPv4', required=True, type=ipaddress.IPv4Address)
# Port that will be scanned, if this parameter not been set then the default ports will be scanned
parser.add_argument('-p', dest='ports', help='Ports separated by comma', type=str, default=[21, 22, 23, 53, 80, 443,
3389, 389, 3306, 1521,
8080, 8000])
params = parser.parse_args()
# Create an instance of MyPortScanner
m = MyPortScanner(params.target_host_v4, params.ports)
# Call the function check_port_socket_v4_tcp
m.check_port_socket_v4_tcp()
Download do código no GitHub: Simples port scanner
Qualquer pergunta, dúvida, crítica ou sugestão, mande-me um email