Como fazer uma proxy TCP em Golang para Pentesting

Como fazer uma proxy TCP em Golang para Pentesting

Monero Chan

Introdução

Existem diferentes formas de se criar uma proxy TCP, a que eu irei demonstrar se baseia num fluxo de turnos, no qual cada um espera a sua vez de transmitir dados. Dessa forma existem certas limitações pois pode ser que o Server no qual você deseja se conectar não envie o byte de controle EOF (sendo representado pelo NULL BYTE "\x00"). Sendo assim não é possível identificar se o Server terminou de enviar os pacotes ou não, por isso usaremos um Timeout de 1 segundo (ou mais dependendo de sua rede).

Fluxograma de como um Proxy funciona

Analisando os argumentos da linha de comando

Primeiro precisamos saber qual domínio e qual porta o usuário quer se conectar

A stdlib "flag" nos permite analisar os argumentos do comando que o usuário inseriu na prompt, infelizmente eles retornam um pointer para tipos de dados que são primitivos então eu simplesmente estou fazendo o dereference deles e retornando a função.

Ao buildar e rodar o programa ele seria utilizado da seguinte forma:


Função main

Primeiramente nós estamos simplesmente recebendo os parâmetros da linha de comando e mostrando eles na tela. Logo após nós iniciamos um listener TCP em nosso sistema operacional especificando o endereço 0.0.0.0:1337 que basicamente significa que queremos escutar em todas as interfaces de rede na porta 1337. Logo em seguida nós verificamos por qualquer um erro que possa ter ocorrido e adiamos conn.Close() para o término do programa (que nunca irá ocorrer devido ao nosso loop infinito).

Dentro do nosso loop infinito, nós aceitamos uma conexão nova e mostramos na tela e em seguida utilizamos uma goroutine pra lidar com essa conexão sem bloquear novas conexões.

Função handleConnection

Aqui nós temos bastante coisa acontecendo por trás dos panos, falando de forma objetiva acontece o seguinte:

  • Proxy se conecta ao servidor que o usuário requisitou
  • Usuário utiliza o netcat para enviar dados para a Proxy
  • Proxy envia dados para o servidor
  • Servidor responde enviando para a proxy
  • Proxy envia dados ao usuário
  • Os 2 sockets são finalizados

Primeiramente temos um bloco de definição e inicialização de variáveis que iremos utilizar. Em seguida utilizamos net.Dial para que a proxy se conecte ao servidor remoto utilizando o protocolo TCP. Eu criei apenas as funções de leitura de bytes devido a certas peculiaridades de cada ponta.

Como estaremos utilizando netcat para fazer uma requisição HTTP temos que ter em mente que o netcat envia pacotes TCP a cada \n e uma requisição HTTP válida termina com \r\n\r\n, esses problemas são resolvidos na função readFromNetcat.

Função readFromNetcat

Temos um totalBuffer que é a variável que armazenará todos os bytes que iremos receber de vários pacotes TCP diferentes. Como pode ver pelo break no último if, a única condição para a quebra desse loop é que os bytes recebidos terminem com 2 quebras de linha \n\n. Ou seja, precisamos apertar Enter duas vezes no netcat para "confirmar" que terminamos de enviar tudo.

No início do loop é criado um buffer de 4096 bytes que é um exagero para a exemplo que irei utilizar, porém 4096 é um número ideal para receber chunks de bytes pois não é um número grande para processar dados em tempo real e nem um número muito pequeno para que o loop seja executado muitas vezes, perdendo a eficiência.

Para facilitar a verificação do delimitador \n\n que indica que terminamos a mensagem eu utilizei bytes.Trim para remover todos os NULL BYTES e ter um byte slice no qual os últimos 2 bytes são os delimitadores, então eu faço essa verificação utilizando bytes.Equal e por fim adiciono \r\n\r\n pois sem isso o servidor não irá entender se terminamos de enviar a mensagem ou não.

Função readFromRemote

Essa função é bem simples, criamos um totalBuffer para armazenar todos os bytes e configuramos um Timeout de 1 segundo para que remote.Read não fique esperando para sempre por bytes. Dentro do loop nós colocamos os bytes dentro de tmpBuffer e removemos todos os NULL BYTE pois os pacotes podem vir em tamanhos diferentes, não exatamente irão preencher seu byte slice inteiro. Por fim nós pegamos esses bytes e acrescentamos ao nosso totalBuffer para então retorná-lo.

Conclusão

Exemplo de uso

Existem várias formas de se fazer uma proxy, foi apresentado um dos modelos mais básicos para que seja possível colocar em prática a manipulação em baixo nível de sockets e bytes. Golang oferece muitas ferramentas para facilitar as requisições HTTP, mas tudo depende das funcionalidades e complexidade que você deseja adicionar à sua proxy.

É extremamente útil em Pentests onde pode ser que o adversário não tenha Python instalado ou não existam as ferramentas necessárias no sistema. Também é útil caso você esteja num cenário onde você não pode fazer muito "barulho" para ser pego pelo sistema de detecção de intrusão.

Report Page