Aprenda Python Pentest

  • Página Inicial
  • Contato!
  • Tudo sobre Python Pentest Parte 1!
  • Tudo sobre Python Pentest Parte 2!
  • Tudo sobre Python Pentest Parte 3!
  • Tudo sobre Python Pentest Parte 4!
  • Tudo sobre Python Pentest Parte 5!
  • Tudo sobre Python Pentest Parte 6!
  • Tudo sobre Python Pentest Parte 7!
  • Tudo sobre Python Pentest Parte 8!
  • Tudo sobre Python Pentest Parte 9!
  • Tudo sobre Python Pentest Parte 10!
  • Tudo sobre Python Pentest Parte 11!
  • Tudo sobre Python Pentest Parte 12!
  • Tudo sobre Python Pentest Parte 13!
  • Tudo sobre Python Pentest Parte 2

    Entendendo Funções

    Voltando ao Servidor TCP que criamos, podemos por exemplo criar log a cada acesso ao nosso servidor. Colocaríamos, por exemplo, esse código entre o sock.listen(1) e o primeiro print:

    
    log = open("servidor.log", "a")
    
    log.write(f"Aguardando conexão {ip}:{porta}...")
    log.close()
    
    

    No entanto, podemos colocar logs em vários trechos do código, então para facilitar e deixar o código mais limpo, podemos criar uma função assim:

    
    def criarLog(msg):
        log = open("servidor.log", "a")
        
        log.write(msg + "\n")
        log.close()
        
        print(msg)
    
    

    Daí, podemos fazer o código do nosso servidor assim:

    
    import socket
    
    def criarLog(msg):
        log = open("servidor.log", "a")
    
        log.write(msg + "\n")
        log.close()
    
        print(msg)
    
    ip = "0.0.0.0"
    porta = 8080
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    sock.bind((ip, porta))
    sock.listen(1)
    
    criarLog(f"Aguardando conexão {ip}:{porta}...")
    
    conn, cliente = sock.accept()
    
    criarLog(f"Conectado com {cliente}.")
    
    conn.send("Digite a senha: ".encode())
    senha = conn.recv(1024)
    
    if senha.decode().strip() == "senhafoda":
        criarLog(f"{cliente} acertou a senha!")
        
        while True:
            msg = input("> ")
    
            if msg == "sair":
                conn.send(f"Servidor encerrando conexão com {cliente}...")
                sock.close()
    
                break
    
            msg += "\n"
    
            conn.send(msg.encode())
    
            dados = conn.recv(1024)
    
            print(dados.decode(), end = "")
    else:
        criarLog(f"{cliente} errou a senha!")
        
        conn.send("Senha Incorreta!".encode())
        sock.close()
    
    

    PS: Podemos melhorar a escrita dos logs, usando, por exemplo, data e hora do site.

    Para escolher se ele printa na tela ou só escreve no log, podemos melhorar assim:

    
    def criarLog(msg, v = ""):
        log = open("servidor.log", "a")
    
        log.write(msg + "\n")
        log.close()
    
        if v == "-v":
            print(msg)
    
    

    E daí, onde tiver que colocar verbose, basta especificar o -v entre aspas, dessa forma:

    
    criarLog(f"Aguardando conexão {ip}:{porta}...",  verb) # verb teria o "-v" como argumento
    
    

    Usando com parâmetros:

    
    ip = "0.0.0.0"
    porta = int(sys.argv[1])
    
    try:
        verb = sys.argv[2]
    except:
        verb = 0
    
    

    Entendendo Classes

    Usando a POO, podemos criar uma classe pro servidor que trabalhe tanto com TCP quanto com UDP, dessa forma:

    
    import socket
    
    class Servidor:
        def tcp(self, ip, porta):
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
            sock.bind((ip, porta))
            sock.listen(1)
    
            print(f"Aguardando conexão TCP {ip}:{porta}.")
    
            conn, cliente = sock.accept()
    
            conn.send("Digite a senha: ".encode())
            senha = conn.recv(1024)
    
            if senha.decode().strip() == "senhafoda":
                while True:
                    msg = input("> ")
    
                    if msg == "sair":
                        sock.close()
                        break
    
                    msg += "\n"
    
                    conn.send(msg.encode())
    
                    dados = conn.recv(1024)
                    print(dados.decode(), end = "")
            else:
                sock.close()
    
        def udp(self, ip, porta):
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
            sock.bind((ip, porta))
    
            print(f"Aguardando conexão UDP {ip}:{porta}.")
    
            while True:
                dados, cliente = sock.recvfrom(1024)
    
                print(f"{cliente} - {dados.decode()}")
    
                msg = input("> ")
    
                sock.sendto(msg.encode(), cliente)
    
    

    Daí, num outro arquivo (como ncfoda.py) podemos chamar ele assim:

    
    from Servidor import Servidor
    
    ip = "0.0.0.0"
    porta = 8080
    
    serv = Servidor()
    
    serv.tcp(ip, porta)
    # serv.udp(ip, porta)
    
    

    Daí, é só rodar um cliente UDP ou TCP e vê se ele responde (teste com os dois).

    No nosso código principal, podemos melhorar ainda mais, assim:

    
    import sys
    from Servidor import Servidor
    
    ip = "0.0.0.0"
    arg = sys.argv[1]
    porta = int(sys.argv[2])
    
    serv = Servidor()
    
    if arg.lower() == "-t":
        serv.tcp(ip, porta)
    elif arg.lower() == "-u":
        serv.udp(ip, porta)
    
    

    Daí é só rodar na sintaxe python3 ncfoda.py -t 8080.

    Da mesma forma, criaremos uma classe pra cliente, usando a mesma base.

    Resolvendo Desafio da Aulas Passada

    Para fazer a classe do cliente, podemos fazer assim:

    
    import socket
    
    class Cliente:
        def tcp(self, ip, porta):
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            
            sock.connect((ip, porta))
            
            msg = sock.recv(1024).decode()
            senha = input(msg)
            
            sock.send(senha.encode())
            
            while True:
                print(sock.recv(1024).decode(), end = "")
                
                msg = input("> ")
                msg += "\n"
                
                sock.send(msg.encode())
    
        def udp(self, ip, porta):
           sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
           
           while True:
               msg = input("> ")
               
               sock.sendto(msg.encode(), (ip, porta))
               
               dados, serv = sock.recvfrom(1024)
               
               print(f"{serv} - {dados.decode()}")
    
    

    Como estamos criando um programa que funciona como o Netcat, podemos fazer que o mesmo programa seja tanto cliente como servidor. No ncfoda.py podemos fazer assim:

    
    import sys
    from Servidor import Servidor
    from Cliente import Cliente
    
    help = """Forma de uso:
    
    python3 ncfoda.py -s [tcp/udp] port
    python3 ncfoda.py -c [tcp/udp] ip port"""
    
    try:
        tipo = sys.argv[1]
    except:
        print(help, end = "")
        exit(0)
    
    if tipo.lower() == "-s":
        ip = "0.0.0.0"
        protoc = sys.argv[2]
        porta = int(sys.argv[3])
    
        serv = Servidor()
    
        if protoc.lower() == "tcp":
            try:
                serv.tcp(ip, porta)
            except KeyboardInterrupt:
                exit(0)
        elif protoc.lower() == "udp":
            try:
                serv.udp(ip, porta)
            except KeyboardInterrupt:
                exit(0)
        else:
            print(help, end = "")
            exit(0)
    elif tipo.lower() == "-c":
        protoc = sys.argv[2]
        ip = sys.argv[3]
        porta = int(sys.argv[4])
    
        clie = Cliente()
    
        if protoc.lower() == "tcp":
            try:
                clie.tcp(ip, porta)
            except KeyboardInterrupt:
                exit(0)
        elif protoc.lower() == "udp":
            try:
                clie.udp(ip, porta)
            except KeyboardInterrupt:
                exit(0)
        else:
            print(help, end = "")
            exit(0)
    elif tipo.lower() == "-h" or tipo.lower() == "--help":
        print(help, end = "")
        exit(0)
    else:
        print(help, end = "")
        exit(0)
    
    

    Daí, fazemos um programa tipo Netcat completo, com modo cliente e servidor, e com TCP e UDP. Podemos abrir dois terminais, um simulando o servidor e outro simulando o cliente.

    No servidor, podemos fazer, por exemplo, assim:

    
    python3 ncfoda.py -s tcp 8080    
    
    

    E no cliente:

    
    python3 ncfoda.py -c tcp 127.0.0.1 8080
    
    

    Resolvendo Subdomínios

    Vamos supor que nós temos poucas informações sobre um domínio qualquer, para descobrir informações sobre subdomínios existentes nesse domíno em si, por exemplo, o domínio twitter.com tem como subdomínios coisas como mail.twitter.com e mobile.twitter.com, nós podemos criar um script que realiza o bruteforce dos subdomínios de um domínio. Veja um exemplo abaixo:

    
    import socket
    
    dominio = str(input("Informe o domínio: "))
    
    dados = socket.getaddrinfo(dominio, None, socket.AF_INET)
    
    print(dados)
    
    

    Essa saída é o retorno de alguns itens que foram puxados do domínio informado, com uma lista com duas tuplas dentro uma da outra. Pra filtrar o IP, fazemos assim:

    
    print(dados[0][4][0])
    
    

    E pra fazer um filtro de subdomínios, podemos fazer assim:

    
    import socket
    
    dominio = str(input("Informe o domínio: "))
    
    sub = ("admin", "teste", "cpanel", "ftp", "ssh", "mail", "www", "mobile", "m")
    
    for s in sub:
        subdom = f"{s}.{dominio}"
    
        try:
            dados = socket.getaddrinfo(subdom, None, socket.AF_INET)
            print(f"{subdom} - {dados[0][4][0]}")
        except socket.gaierror:
            pass
    
    

    Mas o melhor é usar um arquivo txt com os subdomínios, podemos usar por exemplo um que está num repositório no GitHub, que clonamos digitando git clone https://github.com/danielmiessler/SecLists.git. Vá na pasta Discovery e DNS e pegue uma das wordlists lá. Ou baixe essa como exemplo, clicando aqui.

    Podemos usar a estrutura with open para abrir arquivos de textos muito grandes, como com a wordlist, assim:

    
    import socket
    
    dominio = str(input("Informe o domínio: "))
    
    with open("wordlist-dominios.txt") as wordlist:
        for w in wordlist.readlines():
            w = w.replace("\n", "")
            subdom = f"{w}.{dominio}"
            
            try:
                dados = socket.getaddrinfo(subdom, None, socket.AF_INET)
                print(f"{subdom} - {dados[0][4][0]}")
            except socket.gaierror:
                pass
    
    

    Para ele funcionar tanto com IPv4 quanto com IPv6, podemos criar com funções, assim:

    
    import socket
    
    def dnsIPv4(subdom):
        try:
            dados = socket.getaddrinfo(subdom, None, socket.AF_INET)
            print(f"{subdom} - {dados[0][4][0]}")
        except socket.gaierror:
            pass
    
    def dnsIPv6(subdom):
        try:
            dados = socket.getaddrinfo(subdom, None, socket.AF_INET6)
            print(f"{subdom} - {dados[0][4][0]}")
        except socket.gaierror:
            pass
    
    dominio = str(input("Informe o domínio: "))
    
    with open("wordlist-dominios.txt") as wordlist:
        for w in wordlist.readlines():
            w = w.replace("\n", "")
            subdom = f"{w}.{dominio}"
    
            dnsIPv4(subdom)
            dnsIPv6(subdom)
    
    

    PS: Podemos colocar a biblioteca sys e os parâmetros sys.argv[1] e sys.argv[2] no domínio e na wordlist.