ZINES — underground e-zine archive source
text size: CRT glow:
~/BRAZILIAN/The Bug Magazine/0x02/0x03_kless-paper
[ --- The Bug! Magazine

                    _____ _              ___               _
                   /__   \ |__   ___    / __\_   _  __ _  / \
                     / /\/ '_ \ / _ \  /__\// | | |/ _` |/  /
                    / /  | | | |  __/ / \/  \ |_| | (_| /\_/
                    \/   |_| |_|\___| \_____/\__,_|\__, \/
                                                   |___/

                      [ M . A . G . A . Z . I . N . E ]


             [ Numero 0x02 <---> Edicao 0x01 <---> Artigo 0x03 ]



.> 14 de Fevereiro de 2007,
.> The Bug! Magazine < staff [at] thebugmagazine [dot] org >



               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
               kless, connecting to void and getting out alive
               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


.> 23 de Janeiro de 2007,
.> setuid_ < setuid [at] promisc [dot] org >
           < http://setuid.promisc.org >

[ --- Indice

+     0.     <--->     Abstrato
+     1.     <--->     Introducao
+     2.     <--->     Principios de backdoor em user-land
+       2.1.  <->        Conectando a uma porta fechada
+     3.     <--->     Connection-less connection
+       3.1.  <->        sniff, sniff!!!
+       3.2.  <->        Escrevendo pacotes
+     4.     <--->     Implementacao
+     5.     <--->     kless-echo
+     6.     <--->     Jogando pimenta no caldinho de feijao
+     7.     <--->     kless-bd
+     8.     <--->     O jeito como poderia ser
+     9.     <--->     Nova fronteira: multiple binds, TCP, etc...
+     10.    <--->     Seguranca, e' possivel?
+     11.    <--->     Conclusao
+     12.    <--->     Referencias


[ --- 0. Abstrato

 Este documento procura demonstrar uma maneira  de implementar backdoors    (em
 user-land) em um sistema, de forma que permita   a execucao remota de comandos
 utilizando a suite TCP/IP, porem sem que seja necessario   abrir nenhuma porta
 no servidor.
 A comunicacao ocorre transparente para o cliente, enquanto o servidor simula a
 pilha TCP/IP durante a execucao.  A intencao do texto e dos programas   desen-
 volvidos como prova   de conceito e'  apontar as diversas maneiras pelas quais
 e' possivel subverter a seguranca de um sistema.


[ --- 1. Introducao

 Backdoors sao a principal maneira pela qual um  atacante   mantem acesso  a um
 sistema que tenha sido comprometido. A  evolucao deste tipo de artefato e' co-
 mum e existem diversos  exemplos [1] sobre como eles podem ser  implementados,
 e este documento propoe mais uma maneira ;). 
   A intecao do texto e' implementar um modelo cliente/servidor para uma  back-
 door que permita acesso remoto utilizando a suite   TCP/IP    (especificamente
 UDP) porem  sem que nenhuma porta esteja efetivamente aberta no lado do   ser-
 vidor em momento algum durante a comunicacao remota,  de maneira  que     isso
 seja praticamente transparente para o cliente. 
   A escolha sobre qual protocolo da camada de transporte utilizar na implemen-
 tacao da backdoor e' exclusivamente ligado a complexidade de implementacao. 
 Enquanto a implementacao utilizando TCP  e'  totalmente viavel,  simular a pi-
 lha  TCP em todas/ou algumas de suas particularidades (tcp handshake,      re-
 transmition, ack, syn, rst,  window size  advertisements, etc...) se torna uma
 tarefa  altamente complexa  e   tediosa para o  simples proposito de uma back-
 door. No entanto a simplicidade do UDP nos permite uma implementacao bem  mais
 simplificada para a nossa prova de conceito, e serve o seu proposito de ser um
 meio de transporte orientado a  datagramas sem  fornecer nenhum meio de garan-
 tia sobre a   entrega  das mensagens ao destinatario.
   O leitor deste texto nao precisa necessariamente ter familiaridade com    os
 itens abaixo, mas facilitaria bastante a compreensao de certos trechos do  ar-
 tigo:
   - C [2]
   - Suite TCP/IP de protocolos[3], a interacao entre os pro-
     tocolos da camada de transporte e o protocolo de contro-
     le ICMP [3][4]
   - Construcao/captura de pacotes em user-land e bibliotecas  
     existentes para este tipo de trabalho (libpcap, libnet).

   Agradecimentos: dm, duhru@overt.org, todo  o pessoal do #0xff@freenode.net -
 o ultimo endereco da internet ;).
   
 Vale ressaltar   que todos os exemplos   aqui listados   foram testados em  um
 FreeBSD 6.2 e em um FreeBSD 6.1, mas a  maioria senao todos os  exemplos/casos
 ilustrados devem funcionar nas demais distribuicoes UNIX disponiveis por ai.
 O codigo fonte dos programas de prova de conceito utilizados no texto    estao
 disponiveis em: http://setuid.promisc.org


[ --- 2. Principios de Backdoors em user-land
 
 Enquanto backdoors em kernel-land  conseguem suprir  e  ate'   mesmo superar a
 capacidade e servicos fornecidos ao usuario,  as vezes e' impossivel manipular
 o kernel    (seja por falta de conhecimento sobre o sistema, seja por falta de
 codigo-fonte para utilizar - IBM AIX daria um bom exemplo deste  caso,    seja
 ainda por outros motivos que nao precisam ser listados) o que nao permite    a
 desqualificacao de backdoors em user-land mesmo apos toda a evolucao  ocorrida
 nos ultimos 6 anos.
   Em user-land a maioria das backdoors que  fornecem  acesso  remoto a maquina
 ou sao desprovidos de qualquer meio de  esconder os rastros do acesso  (contam
 com  a ineficiencia do administrador da maquina :), ou entao utilizam tecnicas
 nas quais a conexao utilizada e' disponivel  apenas  atraves  de passos segui-
 dos pelo cliente (port-knocking e' um bom  exemplo disso [5]). Ambos  os meios
 mencionados acima  permitem que um administrador perceba alguma atividade sus-
 peita   atravez de  simples comandos  administrativos   como    sockstat(1) ou
 netstat(1), ou lsof.
   A backdoor desenvolvida nesse texto subverte a maneira como simples  afirma-
 coes relacionadas ao TCP/IP devem ser encaradas:

   - Sempre que uma porta TCP/UDP estiver aberta necessaria-
     mente deve haver um aplicativo recebendo/enviando dados
     nessa porta (seja ele cliente ou servidor)
   - Sempre que um administrador perceber uma porta aberta e'
     possivel determinar qual aplicativo local esta conecta-
     do a ela.
   - Se uma porta nao estiver aberta nao pode haver  comuni-
     cacao entrando ou saindo por ela.

   A intencao do texto e'  subverter o significado das  duas primeiras  afirma-
 coes e provar que e' possivel simular  para todos os efeitos situacoes na qual
 a terceira afirmacao  se torne falsa.


[ --- 2.1. Conectando-se a uma porta fechada

 Enquanto o protocolo TCP fornece maneiras bem explicitas de    se verificar se
 uma porta TCP esta aberta ou fechada  atravez de um reset (ACK/RST) no entanto
 o UDP utiliza-se de outro mecanismo para notificar o evento de uma porta   fe-
 chada:
   Por exemplo, ao tentar enviar um  datagrama UDP para  uma  porta na qual nao
 existe nenhum processo ouvindo,  o resultado e' o seguinte:

 ---
 setuid@zion$ nc -u 192.168.0.102 333
 hello world
 setuid@zion$
 ---

 ---
 setuid@zion$ sudo tcpdump -i lo0 "ip proto \icmp or \udp"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on lo0, link-type NULL (BSD loopback), capture size 96 bytes
 06:54:52.887388 IP 192.168.0.102.60490 > 192.168.0.102.333: 
                 UDP, length 12
 06:54:52.887407 IP 192.168.0.102 > 192.168.0.102: 
                 ICMP 192.168.0.102 udp port 333 
                 unreachable, length 36
 ---
   Vale ressaltar que o cliente "nc" (netcat) termina a sua    execucao compul-
 soriamente apos ser notificado que a  porta 333 esta fechada no host de desti-
 no do pacote.
   Ou seja, quando o kernel recebe um pacote, ele o  empura   pilha abaixo ate'
 chegar ao header UDP do pacote quando e' possivel determinar a porta de desti-
 no deste datagrama. O proximo passo e' determinar se existe algum processo es-
 perando algum pacote naquela porta, no nosso caso nao existia nenhum processo,
 entao o kernel envia de volta para o endereco de origem um pacote ICMP  infor-
 mando que a  porta 333 e' "inalcancavel", ou seja,  nao existe ninguem  ouvin-
 do naquela porta.
   Esse e' o protocolo sobre   como informar  se uma porta UDP   esta' fechada.
 Porem a especificacao no lado do cliente e' um pouco menos rigida, ela permite
 que o cliente especifique se quer ou nao   ser notificado sobre o  recebimento
 deste pacote ICMP informando que a porta de destino esta' fechada. Vamos ilus-
 trar melhor sobre o caso:
   Considere um cliente UDP simples que apenas envia o  que     for digitado no
 stdin e espere por uma resposta do  servidor [6].   Basicamente os passos  que
 um cliente UDP  deve executar sao:

   - socket() - obtem um file descriptor para comunicacao
   - captura o input via stdin (fgets(), etc..)
   - sendto() - envia as informacoes recebidas do stdin
   - recvfrom() - recebe as informacoes enviadas como res-
		  posta.

   Veja o output:
 
 ---
 setuid@zion$ ./udp-client setuid.ath.cx 333
 hello world
 ---

 ---
 setuid@zion$ sudo tcpdump -ni ath0 "ip proto \icmp or \udp"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ath0, link-type EN10MB (Ethernet), capture size 96 bytes
 07:21:39.225719 IP 74.52.16.40.49268 > 192.168.0.103.333: UDP, length 12
 07:21:39.225746 IP 192.168.0.103 > 74.52.16.40: ICMP 192.168.0.103 
                 udp port 333 unreachable, length 36 
 ---

   Note que o cliente nao saiu como no primeiro teste usando o netcat mas ficou
 esperando que a chamada recvfrom() retorna-se. A diferenca entre os dois apli-
 cativos clientes explica a maneira como um cliente UDP e' notificado     sobre
 a disponibilidade de uma porta ou nao. 
   O 'netcat' faz apenas um passo a mais que o nosso cliente de exemplo   'udp-
 client', ele faz uma chamada a  syscall connect(2). Isso e' um fato muito  in-
 teressante das sockets BSD, quando uma socket e' usada com IPPROTO_TCP a  fun-
 cao da chamada connect(2) e' realmente tentar estabelecer  uma   conexao entre
 os dois pontos (fazendo o 3way handshake[3])  no entanto o significado do con-
 nect(2)em uma socket IPPROTO_UDP e' outro. 
   Em UDP nao existe o conceito de conectar-se a uma maquina ou estabelecer uma
 conexao, na camada de transporte nao existe garantia alguma de que um   pacote
 chegou ao destino, essa inteligencia deve ser implementada na camada do  apli-
 cativo, como faz o TFTP [7].  Portanto  se um cliente  UDP chamar    a syscall
 connect(2) o efeito e' diferente do obtido quando usando TCP.
   Erros assincronos nao sao retornado para a sockets UDP a    nao ser que elas
 tenham sido conectadas. Nao existe  handshake ou algo parecido, o kernel  sim-
 plesmente guarda o par IP/Port do destinatario dos datagramas, por tanto quan-
 do o sistema do destinatario receber o datagrama direcionado  a  porta fechada
 e   enviar um ICMP port  unreachable para  a  origem, o kernel da origem veri-
 fica se o IP/Porta  contido na mensagem ICMP esta'    armazenado devido a  uma
 chamada connect(2), caso esteja ele retorna o erro para o processo   caso con-
 trario o kernel silenciosamente descarta o  pacote ICMP.


[ --- 3. Connection-less connection

 Agora que ja sabemos como procede  o protocolo UDP  quando tenta se  comunicar
 com uma porta fechada, nos ja'  podemos delinear quais sao os obstaculos   que
 enfrentaremos    para fazer essa backdoor se tornar realidade:

       - nao pode haver nenhuma porta aberta no servidor
         que tenha relacao com a nossa comunicacao
       - nos devemos ser capazes de receber as informacoes
         que sao direcionadas a esta porta que vai estar
	 fechada
       - nos devemos ser capazes de responder aos pacotes
         do cliente, de maneira que pareca que eles estao
	 sendo enviados pela porta. Nos nao podemos  usar
	 read, write, sendto, etc, uma vez que nao  temos
	 nenhuma socket.
       - o cliente deve ignorar os pacotes ICMP port  un-
         reachable que serao recebidos uma vez que o ker-
	 nel identificara que a nossa comunicacao esta' 
	 direcionada para uma porta fechada.

   Estes sao os nossos problemas,  uns sao faceis de  lidar outros nao, os pas-
 sos mais cruciais sao  os passos  2 e  3  que envolvem simular   as funcoes de
 read/write que  normalmente sao auxiliadas pelo uso de sockets.
     
    
[ --- 3.1. sniff, sniff!!!

 Quando um pacote chega ate um interface de rede (ethernet, wireless, ppp, etc)
 ele e' empurrado pilha abaixo de  forma que o kernel vai analisando e  descar-
 tando conforme  necessario o pacote, por exemplo: MAC   address no header  nao
 e' o mesmo que a interface e a interface nao esta' em modo promiscuo - descar-
 ta o pacote,   checksum do ip  header esta' incorreta -   descarta o pacote, e
 assim por diante.
   O que e' importante e' que e'  possivel utilizar  certas  interfaces para se
 obter uma  copia dos pacotes  recebidos por uma ou todas as interfaces de rede
 de um sistema. Essa copia e' independente do processamento real recebido  pelo
 pacote, e' assim que funciona o tcpdump(1) e milhoes    de  outras ferramentas
 existentes por ai.
   Re-inventar a roda e' uma coisa feia de se fazer e algumas vezes resulta  em
 rodas quadradas, retangulares,    e' ai  que bibliotecas como libpcap[8]   sao
 extramamente uteis pois concetram em um unico local o esforco que seria   des-
 centralizado e estaria fadado a ser incompleto.
   
   Por tanto acabamos de resolver uma grande parte do nosso problema,    nos ja
 conseguimos com a libpcap ou com   qualquer outra maneira de "sniffar" os  pa-
 cotes obter uma copia exata dos pacotes que sao direcionados para uma    porta
 que esta' fechada. Outro ponto importante a ser ressaltado e' que devido a na-
 tureza do protocolo UDP nos conseguimos obter o conteudo dos pacotes    (o que
 realmente esta' sendo enviado em nossa direcao, a informacao em si, e nao  ca-
 madas de protocolos) de uma so' vez e com um unico pacote, o   que poderia ser
 diferente com o TCP.
   Essa habilidade  ja' elimina  a necessidade  de abrirmos portas afim de  re-
 ceber os dados que algum cliente   queira nos enviar. Vamos ver agora como li-
 dar com a outra   parte do problema.


[ --- 3.2. Escrevendo pacotes

 A outra parte do nosso problema e' como enviar   eventuais    respostas para o
 cliente (digamos que ele tenha enviado um comando whoami ou id por    exemplo)
 nos queremos  conseguir enviar para ele o resultado do comando, afim de prover
 uma interatividade de comunicacao.
   A outra parte do problema e' solucionada tambem de   uma   maneira a nao re-
 inventar a roda e denovo ganhar com  alta portabilidade, libnet [9]. 
   Esta e' provavelmente  a  parte mais  simples do  codigo    pois nos   temos
 todas as  informacoes relevantes a  nosso dispor: udp src/dst port, ip src/dst
 address,   checksums,  payload, informacoes adicionais dos headers e etc...
   E' so' uma questao de construir o pacote correto afim de simular uma respos-
 ta legitima, que pareca ter vindo de uma porta, que de fato esta' fechada. Va-
 le a pena  ressaltar que se nos estivessemos fazendo essa backdoor usando  TCP
 nos teriamos acesso a todos os syn's e ack's e  tudo  mais o que permitiria de
 maneira facil simular uma resposta autentica.
   Agora que nos ja estabelecemos as nossas maneiras de ler e escrever um paco-
 te (read/write ;)) vamos implementar um simples      exemplo para comecarmos a
 brincar.


[ --- 4. Implementacao

 As funcoes basicas que nos devemos implementar sao as funcoes de read e write,
 respectivamente, ler um pacote vindo da libpcap (usando pcap_loop()), e escre-
 vendo um pacote de volta para a rede (usando libnet_write()).
   O resto e' o resto, o que nos iremos fazer com os dados que foram transmiti-
 dos varia muito de caso para caso, e e' similar a abstracao fornecida  por BSD
 sockets, elas garantem a transmissao de dados e nao o que o seu  servidor/cli-
 ente irao implementar. Por tanto   vamos fazer um  exemplo simples,  um servi-
 dor echo.


[ --- 5. kless-echo

 Servidores echo sao uma verdadeira maravilha quando a  intencao e' se ter    o
 menor trabalho possivel afim de demonstrar que uma comunicacao esta'   aconte-
 cendo. Para quem   se interessar pode-se ler [10]. 
   Kless-echo e' um servidor UDP que responde de volta para o cliente "qualquer
 input que ele tenha recebido", o   seu codigo e' bem simples  e encontra-se em
 [11].
   Primeiro nos compilamos e executados o servidor:
 ---
 setuid@zion$ cd kless-echo/
 setuid@zion$ ls
 Makefile      README        kless-echo.c  udp-client.c
 setuid@zion$ make
 gcc kless-echo.c -o kless-echo -Wall -lpcap -lnet -L/usr/local/lib 
     -I/usr/local/include/ `libnet-config --libs --defines`
 gcc udp-client.c -o udp-client -Wall
 setuid@zion$ sudo ./kless-echo -i ath0 -p 333 -d
 setuid@zion$ sockstat -4 -p 333
 USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
 setuid@zion$ netstat -an -p udp | grep 333
 setuid@zion$
 ---

   Nos compilamos e executamos o kless-echo,   configuramos   ele para ouvir na
 interface "ath0", aguardando pacote vindos para a porta 333/UDP  (talvez agora
 seja um bom momento para mencionar que afim de nao recebermos todos os pacotes
 nos usamos os filtros do BPF para determinar que  queremos   apenas os pacotes
 filtrados pela seguinte regra: "udp dst port 333"), o -d coloca o nosso servi-
 dor em background como um daemon. Note que nada aparece no output do sockstat,
 do netstat...
   Em outra maquina situada em outro ponto do planeta   nos  executamos um tcp-
 dump(1) e o 'nc' ligeiramente alterado de forma a nao sair apos receber o ICMP
  port unreachable.

 ---
 vlima@cerveau$ nc -u setuid.ath.cx 333
 hello world          <--- input do cliente
 hello world          >--- resposta do kless-echo
 funcionou            <--- input do cliente
 funcionou            >--- resposta do kless-echo
 ^C punt!	      <--- control-c para sair do 'nc'
 vlima@cerveau$
 ---

   As linhas que nos interessam do tcpdump rodando no  cliente sao: (os  comen-
 tarios comecam com '#')

 ---
 vlima@cerveau$ sudo tcpdump -n -i rl0 "ip proto \udp or \icmp"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on rl0, link-type EN10MB (Ethernet), capture size 96 bytes

 06:49:45.098391 IP 74.52.16.40.58307 > 12.96.160.115.53:  6756+ A? 
                 setuid.ath.cx. (31)
 06:49:45.144893 IP 12.96.160.115.53 > 74.52.16.40.58307:  6756 1/5/5 A 
                 201.53.69.175 (227)
 # gethostbyname - resolvendo o endereco de IP 
 # associado ao setuid.ath.cx

 06:49:49.728784 IP 74.52.16.40.65120 > 201.53.69.175.333: UDP, length 12
 # enviados 12 bytes pela porta 65120/UDP para porta 333/UDP aonde esta'
 # rodando o kless echo (hello world\n = 12bytes ;))

 06:49:49.934125 IP 201.53.69.175 > 74.52.16.40: ICMP 192.168.0.103 
                 udp port 333 unreachable, length 36
 # resposta do servidor rodando kless-echo indicando que a porta 333/UDP
 # nao esta' aberta, note que e' um pacote ICMP

 06:49:49.937973 IP 201.53.69.175.333 > 74.52.16.40.65120: UDP, length 12
 # resposta do kless-echo enviando de volta o que o cliente
 # enviou (12 bytes) conforme aparece no output do netcat

 06:49:54.065045 IP 74.52.16.40.65120 > 201.53.69.175.333: UDP, length 10
 # enviados 10 bytes pela porta 65120/UDP para porta 333/UDP aonde esta'
 # rodando o kless echo (funcionou\n = 10bytes :))

 06:49:54.228556 IP 201.53.69.175 > 74.52.16.40: ICMP 192.168.0.103 
                 udp port 333 unreachable, length 36
 # resposta do servidor rodando kless-echo indicando que a porta 333/UDP
 # nao esta' aberta, note que e' outro pacote ICMP

 06:49:54.232536 IP 201.53.69.175.333 > 74.52.16.40.65120: UDP, length 10 
 # resposta do kless-echo enviando de volta o que o cliente
 # enviou (10 bytes) conforme aparece no output do netcat
 ---

   Tambem  deixamos rodando um tcpdump(1) no servidor aonde  o kless-echo esta'
 sendo executado, este e' o output:
 ---
 setuid@zion$ sudo tcpdump -n -i ath0 "ip proto \icmp or \udp"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ath0, link-type EN10MB (Ethernet), capture size 96 bytes
 10:48:11.178606 IP 74.52.16.40.65120 > 192.168.0.103.333: UDP, length 12
 # recebidos os 12 bytes direcionados para a porta 333/UDP 
 # (hello world\n = 12 bytes :))

 10:48:15.470810 IP 74.52.16.40.65120 > 192.168.0.103.333: UDP, length 10
 # recebidos os 10 bytes direcionados para a porta 333/UDP
 # (funcionou\n = 10 bytes ;))
 ---

   A interface de saida no servidor nao e' a mesma de  entrada, logo os pacotes
 ICMP port unreachable e as respostas do echo-server so' aparecem na outra  in-
 terface tambem rodando tcpdump(1):

 ---
 setuid@zion$ sudo tcpdump -n -i fxp0 "ip proto \icmp or \udp"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on fxp0, link-type EN10MB (Ethernet), capture size 96 bytes
 10:48:11.178633 IP 192.168.0.103 > 74.52.16.40: ICMP 192.168.0.103 
                 udp port 333 unreachable, length 36
 # o kernel enviando o ICMP port unreachable para o cliente
 # pois a porta 333/UDP nao esta' aberta
 
 10:48:11.180195 IP 192.168.0.103.333 > 74.52.16.40.65120: UDP, length 12
 # a respota do kless-echo, enviando de volta os 12 bytes enviados pelo
 # cliente.

 10:48:15.470836 IP 192.168.0.103 > 74.52.16.40: ICMP 192.168.0.103 
                 udp port 333 unreachable, length 36
 # o kernel enviando o ICMP port unreachable para o cliente
 # depois de receber o segundo datagram.

 10:48:15.472310 IP 192.168.0.103.333 > 74.52.16.40.65120: UDP, length 10
 # a resposta do kless-echo enviando de volta os 10 bytes do cliente.
 ---

   Ao que tudo indica o cliente esta' se comunicando   com  uma porta aberta, o
 servidor acha que nao tem porta alguma aberta, e o kless-echo esta' funcionan-
 do  independente de tudo isso ;)
   Chegou a hora de nos fazermos a coisa ficar mais interessante, e se os  sim-
 ples "hello world" fossem "whoami" e se ao invez de simplesmente repetir o que
 foi recebido se ele executasse aquilo como um comando?


[ --- 6. Jogando pimenta no caldinho de feijao

 Quem gosta de caldinho de feijao sabe que o gosto e'  outro depois que    voce
 joga 3 gotinhas de pimenta. Exatamente o que nos vamos fazer aqui. Basicamente
 o  kless-echo foi uma pequena prova de conceito para ilustrar como  ira proce-
 der a nossa backdoor. Ele implementou de maneira re-utilizavel  as  instrucoes
 de read/write, so nos falta agora, preencher o miolo com uma maneira de execu-
 tar os  comandos e receber a saida do mesmo.
   O que nos precisamos e' de um canal de comunicacao  entre dois pontos,   que
 seja bi-direcional em ambas as direcoes, ou seja, eu posso escrever/ler de  um
 lado e do  outro tambem. Existem varias maneiras de se conseguir isso,     uma
 delas e' a system call socketpair(2). 
   Ao executar  essa syscall   nos temos dois  descritores que formam um par, a
 segunda etapa e' criar um processo que execute os comandos recebidos. fork(2),
 nos serve   a esse proposito muito bem, pois ainda tem a  vantagem   de herdar
 os descritores ja' abertos,   entao a  comunicacao via  socketpair(2) fica ga-
 rantida.   O terceiro passo e' duplicar os descritores  de entrada     e saida
 desse   novo processo de maneira que nos podemos  ler/escrever no stdin/stdout
 /stderr dele,   dup2(2)  nos oferece  essa  funcionalidade.   Ao duplicarmos o
 descritor, nos o  amarramos a uma das sockets criadas com o socketpair(2)  as-
 sim a comunicacao fica direta, o que for escrito no  socket   vai  sair direto
 no stdin do processo criado e o inverso vale para o que for escrito no stdout,
 que saira no file descriptor...
   O ultimo passo vem ao executar "/bin/sh" via execve(2), ja' com todos os ho-
 oks necessarios nos seus devidos lugares: Como os descritores stdin / stdout /
 stderr ja foram duplicados para o nosso pipe com a execucao do /bin/sh nos te-
 mos uma shell sendo executada e possuimos o controle do seu meio de    escrita
 /leitura, so'  falta uma funcao    que execute os comandos, ou seja, envia pi-
 pe abaixo um comando recebido e espere por alguns mili-segundos a resposta es-
 sa por sinal e' a parte mais facil do codigo ;)


[ --- 7. kless-bd

 Ao prover as funcionalidades da secao anterior nos conseguimos transformar  um
 codigo do kless-echo para uma backdoor funcional, vamos testa'-la:
   
 ---
 setuid@zion$ l
 Makefile    kless-bd.c
 setuid@zion$ make
 gcc kless-bd.c -o kless-bd -Wall -lpcap -lnet -L/usr/local/lib 
                -I/usr/local/include/ `libnet-config --libs --defines`
 setuid@zion$ sudo ./kless-bd -i ath0 -p 333 -d
 Password:
 setuid@zion$ sockstat -4 -p 333
 USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
 setuid@zion$ netstat -an -pudp | grep 333
 setuid@zion$
 ---
 
 Backdoor esta' rodando devidamente, vamos colocar os sniffers nos lugares cor-
 retos para verificarmos a  comunicacao ocorrendo e tentar      executar alguns
 comandos  remotamente.

 ---
 vlima@cerveau$ nc -u setuid.ath.cx 333
 whoami            <--- comando digitado
 root              >--- resposta recebida
 uname -a          <--- comando digitado
 FreeBSD zion 6.2-RELEASE FreeBSD 6.2-RELEASE #14: Wed Jan 24 10:37:58 
         BRST 2007     
 root@zion:/usr/obj/usr/src/sys/zion.kernel  amd64 >--- resposta recebida
 ^C punt!
 vlima@cerveau$
 ---

 Os nossos sniffers capturaram a seguinte acao ocorrendo na interface de entra-
 da:

 ---
 setuid@zion$ sudo tcpdump -i ath0 -n "ip proto \icmp or \udp and port 333"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on ath0, link-type EN10MB (Ethernet), capture size 96 bytes
 09:55:55.378125 IP 74.52.16.40.64582 > 192.168.0.103.333: UDP, length 7
 # recebidos 7 bytes do comando "whoami\n"
 09:56:00.086185 IP 74.52.16.40.64582 > 192.168.0.103.333: UDP, length 9
 # recebidos 9 bytes do comando "uname -a\n" 
 ---

 Agora as respostas do kless-bd pela interface de saida:
 ---
 setuid@zion$ sudo tcpdump -i fxp0 -n "ip proto \icmp or \udp and port 333"
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
 listening on fxp0, link-type EN10MB (Ethernet), capture size 96 bytes
 09:55:57.456356 IP 192.168.0.103.333 > 74.52.16.40.64582: UDP, length 5
 # resposta ao comando "whoami" = "root\n" (5 bytes)
 09:56:02.163349 IP 192.168.0.103.333 > 74.52.16.40.64582: UDP, length 134
 # resposta ao comando "uname -a"
 ---

   Isso quer dizer que agora nos temos umas backdoor totalmente funcional, con-
 seguindo executar comandos com   a permissao de super-usuario,  pois ate' para
 executar a backdoor e' preciso ter esse nivel de acesso ao sistema.
   Agora existem algumas falhas dependentes do nosso modelo que tornam a  back-
 door um pouco fragil, pontos aonde as coisas poderiam ser melhor.


[ --- 8. O jeito como poderia ser 

 Criptografia:
 Toda a comunicacao poderia ser criptografada, de forma  a  esconder o conteudo
 viajando pelos fios, isso faria   com que mesmo tendo a tentativa  de se ler o
 conteudo dos  pacotes nao seria possivel enxergar ali nada de  significa tivo.
 Existem diversas maneiras de se criptografar o trafego que seriam de aplicave-
 is ao kless-bd.

 Escondendo o processo:
 Mesmo que nao seja listado nas saidas das ferramentas  comuns de procura   por
 portas abertas no sistema  (sockstat, netstat, e etc..),  um simples "ps -axu"
 revelaria o  processo sendo executado, portanto ao executar essa backdoor   e'
 bom alterar o codigo dela para nao receber nenhum parametro de linha de coman-
 do, que seja somente um ./cmd ou algo que seja nada suspeito, e ja ter as  op-
 coes de  porta e interface embutidas no programa. O melhor seria   ainda  usar
 o kless em conjunto com algum meio de se ocultar  a execucao de certos proces-
 sos [12].

 Emulacao total do terminal:
 Apesar de ser algo extremamente dificil e nao portavel na   maioria das vezes,
 isso seria uma otima funcionalidade de se ter. A  habilidade de  executar vir-
 tualmente  qualquer programa console-based seria de  agrado para muitas   pes-
 soas.
 

[ --- 9. Nova fronteira: multiple binds, TCP, etc...

 Uma coisa que o kless nos permite enxergar e' a possibilidade de se rodar mul-
 tiplos processos ouvindo (da maneira como o kless ouve as coisas) na     mesma
 porta. Isso   de maneira alguma representa alguma dificuldade de implementacao
 na verdade e' so' uma questao de construir o  seu servidor de maneira a "simu-
 lar" o application protocol do aplicativo que voce estiver emulando.
   A utilidade principal disso seria poder utilizar portas    ja' abertas em um
 firewall de forma a fazer a comunicacao entre o cliente e o servidor.    Outra
 utilidade seria ocultar a comunicacao ocorrendo como trafico autorizado,    ou
 na    pior das hipoteses como pacotes mal-construidos   ou  algum trafego ano-
 malo, mas dificilmente como uma tentativa de ataque.
   Deve-se tomar cuidado ainda com os possiveis logs gerados pelos  aplicativos
 autenticos e como eles responderiam aos nossos pacotes "mal-comportados".
   Bons servicos a serem alvos de um   multiple bind seriam DNS   (named) ou  o
 TFTPD, se tornando apenas uma questao de adaptar o codigo ja existente      do
 kless-bd para a peculiariedades dos seus protocolos a nivel  de    aplicativo,
 seria bom utilizar-se por exemplo de peculiaridades  do proprio    aplicativo,
 como no caso do DNS o campo de identificacao do seu cabecalho, e colocando  ao
 invez de "enderecos"  a  serem resolvidos comandos a serem executados de forma
 que a   backdoor em si   apenas execute o que vier com aquele ID,  e assim por
 diante.
   Implementar o kless ou algo similar utilizando  TCP e' uma tarefa viavel co-
 mo ja foi dito no texto, porem tediosa e possivelmente  deve dar mais trabalho
 do que utilidade mas existem casos em que se torna a unica opcao.   
   Existem partes do protocolo  TCP que nao  precisam ser implementadas tornan-
 do a construcao do codigo uma processo mais facil outra boa maneira seria  im-
 plementar um cliente   de forma similar ao servidor (ouvindo por pacotes dire-
 to  na interface e nao em uma porta utilizando  sockets)   dessa forma nao se-
 ria necessario nem implementar o protocolo corretamente,     pois uma copia do
 pacote (a que ficaria  no kernel) seria descartada, e o seu    cliente saberia
 que se trata de um pacote destinado a ele, mesmo que nao     tenha por exemplo
 o SYN correto  por exemplo,as  possibilidades sao imensas, resta experimentar.
 

[ --- 10. Seguranca, e' possivel?

 Obvio que para cada maneira de subverter a seguranca  de um sistema,     exis-
 te uma maneira de se proteger e outra  de se subverter essa medida e     assim
 por diante.
   Se por um lado com o kless o administrador perde a  capacidade  de  utilizar
 comandos como sockstat, ou   netstat afim de verificar a existencia de proces-
 sos fazendo comunicacao via UDP, alguns patches podem ser aplicados ao  kernel
 afim de verificar quais processos abriram o  /dev/bpf para leitura ou   alguma
 coisa do genero [13].
   O comando fstat em sistemas BSDs tambem indica que   um processo esta'com um
 descritor aberto para o  /dev/bpfXX, ou ainda existem programas como o bpfstat
 que e' capaz de ler essa informacao direto do kernel-land e mapear a  relacao:
 processo -> interface no sistema.  


[ --- 11. Conclusao

 A intecao deste texto foi mostrar uma maneira de se estabelecer uma conexao de
 maneira transparente para o cliente e ocultada no servidor.    Existem metodos
 que sao  muito mais eficazes do que esse, porem estou certo de que existem ca-
 sos no qual a utilizacao do kless ou seu   conceito satisfaz de maneira  sufi-
 ciente as necessidades de  alguem almejando manter o acesso remoto  a maquinas
 comprometidas.
   Se algum leitor extender o conceito aqui ilustrado   eu   encorajo o contato
 comigo afim de aprofundar a  discussao no assunto.
   O codigo fonte e demais projetos relacionados ao kless podem ser encontrados
 no endereco abaixo: http://setuid.promisc.org


[ --- 12. Referencias:

  [1] - Phrack 61 - Kernel Rootkit Experiences 
        stealth@segfault.net 
  [2] - The C programming Language
        Dennis Ritchie, Brian Kernighan
  [3] - TCP/IP Illustrated Vol.1
        W. Richard Stevens
  [4] - Unix Network Programming Vol.1
        W. Richard Stevens
  [5] - The Bug Magazine 01 - Port knocking
        hash@gotfault.net
  [6] - udp-client.c - kless/udp-client.c
  [7] - RFC 1350 - Trivial File Transfer
        Protocol version 2
  [8] - libpcap - www.tcpdump.org
  [9] - libnet - www.packetfactory.net/libnet
 [10] - RFC0862 - Echo Protocol, por incrivel
        que parece ela e' uma STD ;)   Talvez
	tenha sido por conta da sua simplici-
	dade. Existem mais ou menos uns  3000
        RFC e apenas uns 80 STD, o status  de
	padrao atingido por RFC's apos  serem
	aprovadas pelo IETF.
 [11] - kless/kless-echo/
 [12] - Confesso que seria bem mais facil es-
        crever um modulo para  o kernel   que 
        esconda a existencia de um  processo,
	do que  um  que simule  o jeito  como
	kless opera.
 [13] - O autor possui um patch ou dois  para
        FreeBSD que imprimem uma mensagem  no
	syslog e no console com o PID de cada
	processo que abre um descritor para o
	/dev/bpf e outros pontos criticos  do
	kernel nesse assunto.