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 6

    Identificando Index Of

    Agora nós vamos fazer o nosso script identificar pastas com Index Of, que tem listagem de arquivos e diretórios. Isso economiza tempo de execução, já que, com o Index Of, podemos identificar os arquivos sem fazer bruteforce.

    No caso, nós filtraremos vendo o que tem na tag title do HTML.

    Altere o if url da função check assim:

    
    if url + "/" == local:
        print(f"Pasta: {url}/ - CODE: {code}")
        re = requests.get(url + "/")
    
        if re.status_code == 200:
            html = re.text
    
            if "<title>Index of" in html:
                print("\u2514 -> Index of")
        else:
            pastas.append(url)
    
    

    Daí, pra pegar os arquivos dentro da pasta de Index of, podemos verificar os arquivos baseados na tag a do HTML. Deixe o if de url assim:

    
    if url + "/" == local:
        print(f"Pasta: {url}/ - CODE: {code}")
        re = requests.get(url + "/")
    
        if re.status_code == 200:
            html = re.text
    
            if "<title>Index of" in html:
                try:
                    for h in html.split("Parent Directory")[1].split("<a href=\""):
                        arq = h.split("</a>")[0].split("\"")[0]
    
                        if len(arq) > 2:
                            print(f"{'\u2514'} {arq}")
                except:
                    pass
            else:
                pastas.append(url)
        else:
            pastas.append(url)
    
    

    Implementando Threads

    Como explicado anteriormente, um thread permite que duas ou mais funções sejam executadas praticamente ao mesmo tempo.

    Para implementarmos um thread no nosso Dirb, podemos fazer a importação com import threading e do time acima do nosso código. E na função looping, faça assim:

    
    def looping(wordl, dom):
        for w in wordl:
            item = w.replace("\n", "")
            url = f"{dom}{item}"
            th = threading.Thread(target = check, args = (url,))
            th.start()
    
    

    O problema é que uma wordlist com 11 linhas, gerará 11 threads, mas pode dar problemas com wordlists maiores (como uma com 4000 linhas, tipo a do verdadeiro Dirb localizada em /usr/share/dirb/wordlists/common.txt).

    Diferente de um script de scan de portas, o HTTP trabalha em uma camada mais alta em redes, e isso acaba fazendo que tanto o servidor quanto o cliente tenha maior processamento para tratar as requisições. Então, criar muitas threads pode causar sobrecarga em ambos, fazendo que o teste fique mais lento do que com as funções normais.

    Para limtar as Threads, podemos usar um semáforo, assim, colocando na função looping:

    
    def looping(wordl, dom):
        global semaforo
        semaforo = threading.Semaphore(3)  # Definindo o semáforo
    
        for w in wordl:
            item = w.replace("\n", "")
            url = f"{dom}{item}"
            th = threading.Thread(target = check, args = (url,))
            th.start()
    
    

    E na função check, apenas temos que identar tudo dentro no with com o semáforo, veja como fica no início da função:

    
    def check(url):
        with semaforo:
            re = requests.head(url, allow_redirects = False)
            code = re.status_code
    
    

    Mas ele dará alguns bugs, então altere a função check assim, dentro do if url:

    
    if url + "/" == local:
        dirP = f"Pasta: {url}/ - CODE: {code}"
        re = requests.get(url + "/")
    
        if re.status_code == 200:
            html = re.text
    
            if "<title>Index of" in html:
                print(f"{dirP}\n{'\u2514'} -> Index of")
            else:
                print(dirP)
                pastas.append(url)
        else:
            print(dirP)
            pastas.append(url)
    
    

    Ele mostrará três condições, mas imprimirá apenas uma por execução da função (do thread, no caso).

    Só que o código ainda dará um erro que não exibirá os arquivos das pastas. Para isso, corrigiremos a função looping, que adicionará os threads numa lista e fará outra repetição:

    
    def looping(wordl, dom):
        global semaforo
        semaforo = threading.Semaphore(3)  # Definindo o semáforo
    
        thrd = list()
        for w in wordl:
            item = w.replace("\n", "")
            url = f"{dom}{item}"
            th = threading.Thread(target = check, args = (url,))
            thrd.append(th)
            th.start()
            
        for t in thrd:
            t.join()
    
    

    PS: Pra melhorar a exibição, podemos fazer assim, na função check, dentro do with semaforo:

    
    with semaforo:
        msg = f"Testando {url}"
        print(f"{msg}", end = "")
        print(" " * 100, end = "\r") # O \r sobreescreve a mensagem anterior
        re = requests.head(url, allow_redirects = False)
        code = re.status_code
    
    

    Criando um Spider

    Um spider é uma ferramenta que tem várias utilidades, mas a utilidade mais básica dele é acessar um site pra buscar links relacionados a ele, é uma forma de mapear o ambiente de uma forma interna. Uma outra função importante que ele tem é de mapear informações importantes, como endereços de e-mail e telefone. Ele pode procurar informações sobre algo dentro de uma página. No caso, nós procuraremos links internos dentro de um site, não links externos (como o do Facebook, por exemplo).

    Para criarmos nosso spider, precisaremos instalar a biblioteca beautifulsoup4. Pra começar, faça esse código:

    
    import requests
    
    url = str(input("Insira o domínio: "))
    
    re = requests.get(url)
    html = re.text
    
    print(html)
    
    

    Vendo isso aí, poderíamos verificar os links olhando as tags a. Nos exemplos anteriores usamos o split, mas ele pode dar alguns bugs, por isso usaremos o BeautifulSoup, que permite tratar linguagens de marcação como o HTML e o XML. Veja um exemplo básico:

    
    import requests
    from bs4 import BeautifulSoup
    
    url = str(input("Insira o domínio: "))
    
    re = requests.get(url)
    html = re.text
    soup = BeautifulSoup(html, "html.parser")
    
    print(soup)    
    
    

    Claro que o código acima faz praticamente o mesmo do anterior, mas podemos filtrar o que queremos, dessa forma:

    
    print(soup.find_all("a")) # Filtra apenas as tags "a" e salva numa lista
    
    

    E no lugar do print acima, faça esse for:

    
    for a in soup.find_all("a"):
        print(a)
    
    

    E pra pegar só o link dos atributos href:

    
    for a in soup.find_all("a"):
        print(a["href"])
    
    

    Os links externos já costumam estar completos (como o redirecionando pra algo no Facebook ou no Youtube), o que nós queremos é os links internos, que tem os caminhos absolutos (como /admin/login.php), nesse caso teremos que montar o link pra podermos acessar o mesmo. Pra isso, faça assim:

    
    for a in soup.find_all("a"):
        link = a["href"]
        
        if "://" in link:
            print(link)
    
    

    E pra extrair o domínio:

    
    if "://" in link:
        print(link.split("://")[1].split("/")[0])
    
    

    Só que dessa forma, pode dar alguns problemas e retornar coisas como facebook.com?callback=https://outrosite.com/, e a função pode não conseguir pegar o link que queremos, então alteraremos o código assim:

    
    import requests
    from bs4 import BeautifulSoup
    
    url = str(input("Insira o domínio: "))
    dominio = url.split("://")[1].split("/")[0]
    
    re = requests.get(url)
    html = re.text
    soup = BeautifulSoup(html, "html.parser")
    
    for a in soup.find_all("a"):
        link = a["href"]
    
        if "://" in link:
            domLink = link.split("://")[1].split("/")[0]
    
            if dominio == domLink:
                print(link)
    
    

    Pra ele pegar caminhos absolutos do site, coloque esse elif dentro do for, abaixo do primeiro if:

    
    if "://" in link:
        domLink = link.split("://")[1].split("/")[0]
    
        if dominio == domLink:
            pass
    elif link[0] == "/":
        print(link)
    
    

    Para pegar o protocolo, vá no início do script e faça isso:

    
    url = str(input("Insira o domínio: "))
    protocolo = url.split("://")[0]
    dominio = url.split("://")[1].split("/")[0]
    
    print(protocolo) 
    exit()
    
    

    E depois assim:

    
    url = str(input("Insira o domínio: "))
    protocolo = url.split("://")[0]
    dominio = url.split("://")[1].split("/")[0]
    semiurl = f"{protocolo}://{dominio}"
    
    print(semiurl)
    exit()
    
    

    Daí, retire o print ali e o exit. É importante a semiurl não ter a barra no final, pra não causar conflitos com o caminho absoluto.

    E daí, no elif, basta colocar assim:

    
    elif link[0] == "/":
        link = f"{semiurl}{link}"
        print(link)
    
    

    Daí, só falta fazer o caminho relativo, basta colocar o link no else, assim:

    
    if "://" in link:
        domLink = link.split("://")[1].split("/")[0]
    
        if dominio == domLink:
            pass
    elif link[0] == "/":
        link = f"{semiurl}{link}"
    else:
        link = f"{url}{link}"
        print(link)
    
    

    PS: Isso dará um bug na exibição dos links relativos, que corrigiremos ainda nessa aula.

    Daí no caso, colocaremos tudo isso acima numa função, dessa forma:

    
    def checkLink(link):
        if "://" in link:
            domLink = link.split("://")[1].split("/")[0]
    
            if dominio == domLink: # Coloque domínio como global
                print(link)
        elif link[0] == "/":
            link = f"{semiurl}{link}"
            print(link)
        else:
            link = f"{url}{link}"
            print(link)
    
    

    E no for apenas deixe isso:

    
    for a in soup.find_all("a"):
        link = a["href"]
        checkLink(link)
    
    

    Mas ele não pegará subdominíos, nesse caso podemos alterar a função assim, no if mais interno:

    
    if dominio in domLink:
        print(link)
    
    

    Podemos verificar outras tags, como a form, por exemplo, fazendo outro for abaixo do primeiro (que pode ser comentado por enquanto):

    
    for f in soup.find_all("form"):
        link = f["action"]
        print(link)
    
    

    Só que no caso, caso não encontre o atributo action na tag form, pode dar erro, nesse caso, podemos fazer um filtro assim nos dois fors:

    
    """ Comentado por enquanto:
    for a in soup.find_all("a"):
        try:
            link = a["href"]
            checkLink(link)
        except KeyError:
            pass
    """
    
    for f in soup.find_all("form"):
        try:
            link = f["action"]
            print(link)
        except KeyError:
            pass
    
    

    Depois, tire o print e coloque o a chamada da função, assim:

    
    for f in soup.find_all("form"):
        try:
            link = f["action"]
            checkLink(link)
        except KeyError:
            pass
    
    

    Comente o for acima também e coloque abaixo dele este, que segue o mesmo raciocínio pra pegar o iframe:

    
    for i in soup.find_all("iframe"):
        try:
            link = i["src"]
            checkLink(link)
        except KeyError:
            pass
    
    

    Agora descomente tudo e rode.

    Daí, coloque todos os fors numa função:

    
    def findLinks(soup):
        for a in soup.find_all("a"):
            try:
                link = a["href"]
                checkLink(link)
            except KeyError:
                pass
    
        for f in soup.find_all("form"):
            try:
                link = f["action"]
                checkLink(link)
            except KeyError:
                pass
    
        for i in soup.find_all("iframe"):
            try:
                link = i["src"]
                checkLink(link)
            except KeyError:
                pass
    
    

    E no final do código, basta invocar ela:

    
    soup = BeautifulSoup(html, "html.parser")
    
    findLinks(soup)
    
    

    Pra salvar tudo numa lista, faça assim:

    
    soup = BeautifulSoup(html, "html.parser")
    
    global linksF
    linksF = list()
    
    findLinks(soup)
    
    

    E altere a função checkLink assim:

    
    def checkLink(link):
        try:
            if "://" in link:
                domLink = link.split("://")[1].split("/")[0]
    
                if dominio in domLink:
                    if link not in linksF:
                        linksF.append(link)
                        print(link)
            elif link[0] == "/":
                link = f"{semiurl}{link}"
    
                if link not in linksF:
                    linksF.append(link)
                    print(link)
            else:
                link = f"{url}{link}"
    
                if link not in linksF:
                    linksF.append(link)
                    print(link)
        except IndexError:
            pass
    
    

    E no final do código, faça assim:

    
    findLinks(soup)
    
    print(linksF)
    
    

    Daí, apenas substitua o último print por isso:

    
    if len(linksF) >= 1:
        for l in linksF:
            protocolo = l.split("://")[0]
            dominio = l.split("://")[1].split("/")[0]
            semiurl = f"{protocolo}://{dominio}"
    
            re = requests.get(l)
            html = re.text
            soup = BeautifulSoup(html, "html.parser")
    
            findLinks(soup)
    
    

    O problema é que ele ainda dá uns bugs com alguns arquivos encontrados, para isso, vamos garantir que tenha uma barra no final, fazendo apenas isso:

    
    url = str(input("Insira o domínio: "))
    
    if url[:-1] != "/":
        url += "/"