BOOK THIS SPACE FOR AD
ARTICLE ADAtualmente, a maioria das aplicações que utilizamos, tanto em dispositivos móveis quanto na web, interage constantemente com a internet. Grande parte dessas comunicações ocorre por meio de requisições web utilizando o protocolo HTTP.
O HTTP é um protocolo de nível de aplicação utilizado para acessar recursos da World Wide Web. O termo “hipertexto” refere-se a textos que contêm links para outros recursos, facilitando a interpretação por parte dos leitores.
A comunicação via HTTP é composta por um cliente e um servidor. O cliente envia uma solicitação ao servidor, que processa o pedido e retorna o recurso solicitado. A porta padrão para comunicação HTTP é a porta 80, embora essa configuração possa ser alterada conforme a necessidade do servidor web. O mesmo tipo de requisições é utilizado quando acessamos a internet para visitar diferentes sites, onde inserimos um Nome de Domínio Completamente Qualificado (FQDN) como um Localizador Uniforme de Recursos (URL) para acessar o site desejado, como www.exemple.com.
Os recursos acessados via HTTP são acessados por meio de uma URL, que fornece muito mais informações do que apenas indicar o site que desejamos visitar.
Estrutura de uma URL
O diagrama acima ilustra a anatomia de uma requisição HTTP em um nível bastante alto. Quando um usuário insere uma URL (por exemplo, exemplo.com) no navegador pela primeira vez, ele envia uma requisição a um servidor DNS (Sistema de Nomes de Domínio) para resolver o domínio e obter seu endereço IP. O servidor DNS procura o endereço IP correspondente a exemplo.com e o retorna. É importante notar que todos os nomes de domínio precisam ser resolvidos dessa forma, pois um servidor não pode se comunicar sem um endereço IP.
Nota: Os navegadores normalmente verificam primeiro os registros no arquivo local /etc/hosts. Se o domínio solicitado não estiver presente nesse arquivo, o navegador entrará em contato com outros servidores DNS. O arquivo /etc/hosts pode ser utilizado para adicionar registros manualmente à resolução de DNS, inserindo o IP seguido pelo nome do domínio.
Uma vez que o navegador obtém o endereço IP associado ao domínio solicitado, ele envia uma requisição GET para a porta HTTP padrão (por exemplo, 80), pedindo pelo caminho raiz /. Em seguida, o servidor web recebe a solicitação e a processa. Por padrão, os servidores são configurados para retornar um arquivo de índice quando recebem uma solicitação para /.
Nesse caso, o conteúdo do arquivo index.html é lido e retornado pelo servidor web como uma resposta HTTP. A resposta também inclui o código de status (por exemplo, 200 OK), que indica que a solicitação foi processada com sucesso. O navegador, então, renderiza o conteúdo de index.html e o apresenta ao usuário.
Neste artigo, vamos explorar como enviar requisições web utilizando duas ferramentas essenciais para qualquer testador de penetração: um navegador, como Chrome ou Firefox, e a poderosa ferramenta de linha de comando cURL.
cURL (Client URL) é uma ferramenta versátil de linha de comando e uma biblioteca que suporta principalmente o protocolo HTTP, além de diversos outros protocolos. Sua flexibilidade a torna uma excelente escolha para scripts e automação, sendo fundamental para enviar diferentes tipos de requisições web diretamente da linha de comando — uma habilidade indispensável em muitos testes de penetração.
Podemos facilmente enviar uma requisição HTTP básica para qualquer URL, passando-a como argumento para o cURL. Abaixo, segue um exemplo de como isso é feito:
malwarilia@htb[/htb]$ curl inlanefreight.com<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
...SNIP...
Percebemos que o cURL não renderiza o código HTML/JavaScript/CSS, ao contrário de um navegador, mas imprime-o em seu formato bruto. No entanto, como testadores de penetração, estamos principalmente interessados no contexto das requisições e respostas, o que costuma ser mais rápido e conveniente do que usar um navegador.
Também podemos usar cURL para baixar uma página ou arquivo e salvar o conteúdo em um arquivo usando a flag -O. Se quisermos especificar o nome do arquivo de saída, usamos a flag -o e indicamos o nome desejado. Caso contrário, podemos usar -O e o cURL utilizará o nome do arquivo remoto, como no exemplo a seguir:
malwarilia@htb[/htb]$ curl -O inlanefreight.com/index.htmlmalwarilia@htb[/htb]$ ls
index.html
Como podemos ver, o resultado não foi impresso desta vez, mas sim salvo no arquivo index.html. Observamos também que o cURL ainda imprimiu alguns status durante o processamento da requisição. Podemos suprimir esses status usando a flag -s, como no exemplo a seguir:
malwarilia@htb[/htb]$ curl -s -O exemple.com/index.htmlDesta vez, o cURL não imprimiu nada, pois o conteúdo foi salvo no arquivo index.html. Por fim, podemos usar a flag -h para ver outras opções disponíveis com o cURL:
malwarilia@htb[/htb]$ curl -hUsage: curl [options...] <url>
-d, --data <data> HTTP POST data
-h, --help <category> Get help for commands
-i, --include Include protocol response headers in the output
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to a file named as the remote file
-s, --silent Silent mode
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
This is not the full help, this menu is stripped into categories.
Use "--help category" to get an overview of all categories.
Use the user manual `man curl` or the "--help all" flag for all options.
Essa não é a lista completa de opções. Esse menu é dividido em categorias. Use “ — help category” para obter uma visão geral de todas as categorias. Use o manual do usuário man curl ou a flag "--help all" para ver todas as opções.
Como mencionado na mensagem acima, podemos usar --help all para imprimir um menu de ajuda mais detalhado ou --help category (ex.: -h http) para imprimir a ajuda específica de uma flag. Se precisarmos de documentação mais detalhada, podemos usar man curl para visualizar a página completa do manual do cURL.
Nas próximas seções, abordaremos a maioria das flags mencionadas e veremos em quais situações devemos usar cada uma delas.
Na seção anterior, discutimos como as requisições HTTP são enviadas e processadas. No entanto, uma das principais desvantagens do HTTP é que todos os dados são transferidos em texto claro, o que significa que qualquer pessoa entre a origem e o destino pode realizar um ataque de Man-in-the-Middle (MiTM) para visualizar os dados transferidos.
Para resolver esse problema, foi criado o protocolo HTTPS (HTTP Secure), no qual todas as comunicações são transferidas em um formato criptografado. Assim, mesmo que uma terceira parte intercepte a requisição, não será capaz de extrair os dados. Por esse motivo, o HTTPS se tornou o esquema padrão para sites na internet, e o HTTP está sendo gradualmente descontinuado. Em breve, a maioria dos navegadores web não permitirá o acesso a sites que utilizam apenas HTTP.
Se examinarmos uma requisição HTTP, podemos observar os riscos de não impor comunicações seguras entre um navegador web e uma aplicação web. Por exemplo, o seguinte é o conteúdo de uma requisição de login HTTP:
Podemos ver que as credenciais de login são transmitidas em texto claro. Isso facilitaria para alguém na mesma rede (como uma rede sem fio pública) capturar a requisição e reutilizar as credenciais para fins maliciosos.
Em contraste, quando alguém intercepta e analisa o tráfego de uma requisição HTTPS, o que se vê é algo como:
Como podemos observar, os dados são transferidos como um único fluxo criptografado, o que torna muito difícil para qualquer pessoa capturar informações como credenciais ou outros dados sensíveis.
Os sites que utilizam HTTPS podem ser identificados pelo prefixo https:// em suas URLs (por exemplo, https://www.google.com), assim como pelo ícone de cadeado na barra de endereços do navegador, à esquerda da URL:
Portanto, ao visitar um site que utiliza HTTPS, como o Google, todo o tráfego será criptografado.
Nota: Embora os dados transferidos pelo protocolo HTTPS possam estar criptografados, a requisição ainda pode revelar a URL visitada se for feita uma consulta a um servidor DNS em texto claro. Por essa razão, é recomendado utilizar servidores DNS criptografados (por exemplo, 8.8.8.8 ou 1.1.1.1), ou utilizar um serviço de VPN para garantir que todo o tráfego esteja devidamente criptografado.
Se digitarmos http:// em vez de https:// ao visitar um site que utiliza HTTPS, o navegador tenta resolver o domínio e redireciona o usuário para o servidor web que hospeda o site de destino. Primeiramente, uma requisição é enviada para a porta 80, que utiliza o protocolo HTTP não criptografado. O servidor detecta isso e redireciona o cliente para a porta 443, que é a porta segura do HTTPS. Esse redirecionamento é feito por meio do código de resposta 301 Moved Permanently, que discutiremos em uma seção futura.
Em seguida, o cliente (navegador) envia um pacote “client hello”, fornecendo informações sobre si mesmo. Depois disso, o servidor responde com um “server hello”, seguido por uma troca de chaves para intercambiar certificados SSL. O cliente verifica a chave/certificado e envia um de seus próprios. Após isso, uma troca de chaves criptografadas é iniciada para confirmar se a criptografia e a transferência estão funcionando corretamente.
Uma vez que o handshake é concluído com sucesso, a comunicação HTTP normal continua, agora criptografada. Esta é uma visão geral muito simplificada da troca de chaves, que está além do escopo deste módulo.
Nota: Dependendo das circunstâncias, um atacante pode ser capaz de realizar um ataque de downgrade de HTTP, que rebaixa a comunicação de HTTPS para HTTP, fazendo com que os dados sejam transferidos em texto claro. Isso é feito configurando um proxy Man-in-the-Middle (MITM) para transferir todo o tráfego através do host do atacante, sem que o usuário perceba. No entanto, a maioria dos navegadores modernos, servidores e aplicações web protegem contra esse tipo de ataque.
O cURL deve gerenciar automaticamente todos os padrões de comunicação HTTPS, realizando um handshake seguro e, em seguida, criptografando e descriptografando os dados de forma automática. No entanto, se tentarmos acessar um site com um certificado SSL inválido ou desatualizado, o cURL, por padrão, não prosseguirá com a comunicação para se proteger contra os ataques Man-in-the-Middle (MITM) mencionados anteriormente:
malwarilia@htb[/htb]$ curl https://inlanefreight.comcurl: (60) SSL certificate problem: Invalid certificate chain
More details here: https://curl.haxx.se/docs/sslcerts.html
...SNIP...
Os navegadores web modernos fazem o mesmo, alertando o usuário sobre a visita a um site com um certificado SSL inválido.
Podemos enfrentar esse problema ao testar uma aplicação web local ou uma aplicação web hospedada para fins de prática, pois essas aplicações podem ainda não ter implementado um certificado SSL válido. Para ignorar a verificação do certificado com o cURL, podemos usar a flag -k:
malwarilia@htb[/htb]$ curl -k https://inlanefreight.com<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
...SNIP...
As comunicações HTTP consistem principalmente em uma requisição HTTP e uma resposta HTTP. A requisição HTTP é feita pelo cliente (por exemplo, cURL ou navegador) e é processada pelo servidor (por exemplo, servidor web). As requisições contêm todos os detalhes necessários que desejamos do servidor, incluindo o recurso (por exemplo, URL, caminho, parâmetros), quaisquer dados da requisição, cabeçalhos ou opções que especificamos, além de muitas outras opções que discutiremos ao longo deste módulo.
Uma vez que o servidor recebe a requisição HTTP, ele a processa e responde enviando a resposta HTTP, que contém o código de resposta, conforme discutido em uma seção posterior, e pode incluir os dados do recurso, caso o solicitante tenha acesso a ele.
Vamos começar analisando o seguinte exemplo de requisição HTTP:
A imagem acima mostra uma requisição HTTP GET para a URL:
http://inlanefreight.com/users/login.htmlA primeira linha de qualquer requisição HTTP contém três campos principais, separados por espaços:
O próximo conjunto de linhas contém pares de valores de cabeçalho HTTP, como Host, User-Agent, Cookie e muitos outros cabeçalhos possíveis. Esses cabeçalhos são usados para especificar vários atributos de uma requisição. Os cabeçalhos são terminados com uma nova linha, o que é necessário para que o servidor valide a requisição. Por fim, uma requisição pode terminar com o corpo e os dados da requisição.
Nota: A versão HTTP 1.X envia requisições em texto claro e utiliza um caractere de nova linha para separar diferentes campos e diferentes requisições. A versão HTTP 2.X, por outro lado, envia requisições como dados binários em formato de dicionário.
Uma vez que o servidor processa nossa requisição, ele envia sua resposta. A seguir, está um exemplo de resposta HTTP:
A primeira linha de uma resposta HTTP contém dois campos separados por espaços. O primeiro campo é a versão do HTTP (por exemplo, HTTP/1.1) e o segundo indica o código de resposta HTTP (por exemplo, 200 OK).
Os códigos de resposta são usados para determinar o status da requisição, conforme será discutido em uma seção posterior. Após a primeira linha, a resposta lista seus cabeçalhos, de forma semelhante a uma requisição HTTP. Os cabeçalhos de requisição e resposta serão abordados na próxima seção.
Por fim, a resposta pode terminar com um corpo de resposta, que é separado por uma nova linha após os cabeçalhos. O corpo da resposta geralmente é definido como código HTML, mas também pode incluir outros tipos de código, como JSON, recursos da web, como imagens, folhas de estilo ou scripts, ou até mesmo um documento, como um PDF hospedado no servidor web.
cURL
Em nossos exemplos anteriores com o cURL, especificamos apenas a URL e recebemos o corpo da resposta em troca. No entanto, o cURL também nos permite visualizar a requisição HTTP completa e a resposta HTTP completa, o que pode ser muito útil ao realizar testes de penetração na web ou ao escrever exploits. Para visualizar a requisição e a resposta HTTP completas, podemos simplesmente adicionar a flag -v (verbose) aos nossos comandos anteriores, e isso deve imprimir tanto a requisição quanto a resposta:
* Trying SERVER_IP:80...
* TCP_NODELAY set
* Connected to inlanefreight.com (SERVER_IP) port 80 (#0)
> GET / HTTP/1.1
> Host: inlanefreight.com
> User-Agent: curl/7.65.3
> Accept: */*
> Connection: close
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< Date: Tue, 21 Jul 2020 05:20:15 GMT
< Server: Apache/X.Y.ZZ (Ubuntu)
< WWW-Authenticate: Basic realm="Restricted Content"
< Content-Length: 464
< Content-Type: text/html; charset=iso-8859-1
<
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
...SNIP...
Como podemos ver, desta vez, recebemos a requisição e a resposta HTTP completas. A requisição enviou simplesmente GET / HTTP/1.1, juntamente com os cabeçalhos Host, User-Agent e Accept. Em resposta, a resposta HTTP continha HTTP/1.1 401 Unauthorized, o que indica que não temos acesso ao recurso solicitado, conforme veremos em uma seção posterior. Assim como na requisição, a resposta também continha vários cabeçalhos enviados pelo servidor, incluindo Date, Content-Length e Content-Type. Por fim, a resposta incluiu o corpo da resposta em HTML, que é o mesmo que recebemos anteriormente ao usar o cURL sem a flag -v.
Exercício: A flag -vvv mostra uma saída ainda mais detalhada. Tente usar essa flag para ver quais detalhes adicionais da requisição e resposta são exibidos com ela.
A maioria dos navegadores modernos vem com ferramentas de desenvolvedor integradas (DevTools), que são principalmente destinadas a desenvolvedores para testar suas aplicações web. No entanto, como testadores de penetração na web, essas ferramentas podem ser um recurso vital em qualquer avaliação web que realizamos, já que um navegador (e suas DevTools) estão entre os recursos que mais provavelmente teremos em todos os exercícios de avaliação web. Neste módulo, também discutiremos como utilizar algumas das ferramentas básicas do navegador para avaliar e monitorar diferentes tipos de requisições web.
Sempre que visitamos um site ou acessamos uma aplicação web, nosso navegador envia várias requisições web e gerencia múltiplas respostas HTTP para renderizar a visualização final que vemos na janela do navegador. Para abrir as ferramentas de desenvolvedor do navegador, tanto no Chrome quanto no Firefox, podemos pressionar [CTRL+SHIFT+I] ou simplesmente clicar em [F12]. As DevTools contêm várias abas, cada uma com sua própria finalidade. Neste módulo, focaremos principalmente na aba Network, que é responsável pelas requisições web.
Se clicarmos na aba Network e atualizarmos a página, devemos conseguir ver a lista de requisições enviadas pela página:
Como podemos ver, as ferramentas de desenvolvedor nos mostram rapidamente o status da resposta (ou seja, o código de resposta), o método da requisição utilizado (GET), o recurso solicitado (ou seja, URL/domínio), juntamente com o caminho solicitado. Além disso, podemos usar o filtro de URLs para buscar uma requisição específica, caso o site carregue muitas requisições para analisar.
Exercício: Tente clicar em qualquer uma das requisições para visualizar seus detalhes. Você pode então clicar na aba Response para ver o corpo da resposta e, em seguida, clicar no botão Raw para visualizar o código-fonte bruto (não renderizado) do corpo da resposta.