El propósito de este artículo es aclarar unas ideas básicas sobre la manera de obtener información acerca del funcionamiento de un protocolo determinado en el nivel de aplicación. Para la mayoría de los protocolos standard que están en funcionamiento es obligada una lectura previa de los
RFCs (requests for comments) que le correspondan, ya que en ellos se definen las bases y especificaciones de este. Dicho método no siempre será posible, ya que hay protocolos cerrados y a veces la única manera de saber algo más es mediante ingeniería inversa.
Además de la documentación que podamos encontrar, nos valdremos de la ayuda de un sniffer. Los sniffers son programas de análisis de la red, permiten capturar la información que pasa a través de un interface de red. En nuestro caso, hemos escogido el
ethereal, ya que está disponible en varias plataformas y además tiene una GUI que facilita mucho el análisis de los datos.
Conceptos preliminares.
Para poder establecer comunicaciones en una red, se requieren una serie de procesos que transforman los datos y los envían entre un remitente a un destinatario. Así mismo, son necesarias ó deseables una serie de características que permitan controlar factores como establecimiento de conexiones, sincronización, corrección de errores, etc... para todo esto, lo más práctico es separar estas tareas en capas o niveles, de manera que en cada capa se realiza una función. El modelo standard OSI define las siguientes capas:
- Aplicación.
- Presentación.
- Sesión.
- Transporte.
- Red.
- Enlace.
- Física.
TCP/IP asume la capa física en la de enlace, la de sesión la incluye en la de transporte y la de presentación se realiza a nivel aplicación. De esta manera, engloba todo el proceso en 4 niveles: aplicación, transporte, red y enlace.
En cada nivel podemos encontrar a su vez varios protocolos:
- Aplicación: telnet, ftp, dns, http, irc...
- Transporte: TCP, UDP.
- Red: IP, ICMP, IGMP.
- Enlace: ARP, RARP.
Nuestro propósito, es analizar los protocolos que residen en la capa de aplicación. Para ello, sería recomendable tener unos conceptos previos sobre las restantes capas, el establecimiento de conexiones, las direcciones IP / MAC y alguna que otra cosa. Se pueden obtener muy buenas referencias sobre esto en el primer volumen de el libro
TCP/IP Illustrated.
Primer contacto con el sniffer.
Al cargar el ethereal, lo primero con lo que nos encontramos es una ventana similar a la siguiente:
En dicha ventana, podemos distinguir claramente las siguientes partes (de arriba hacia abajo):
- Barra de menús - desde ella, podemos acceder a todas las opciones
del programa.
- FILE: operaciones genéricas (cargar, grabar, imprimir, salir).
- EDIT: localización de datos, filtros, y configuración del
programa.
- CAPTURE: inicia o detiene una captura.
- DISPLAY: visualización de los datos.
- TOOLS: procesado de los datos.
- HELP: diálogos de ayuda e información general.
- Ventana superior - será nuestra área principal de trabajo, ya que
es donde se muestran de una manera clara los paquetes. Además cuenta con una
serie de pestañas en la parte de arriba:
- Número: orden numérico de los paquetes.
- Tiempo: tiempo transcurrido.
- Origen: quién es el remitente del paquete.
- Destino: a quién va dirigido el paquete.
- Protocolo: protocolo del paquete.
- Información: muestra información adicional.
NOTA:
En cualquier momento, podemos pulsar cualquiera de estas pestañas para poder
ordenar los paquetes con un determinado criterio.
- Ventana central - muestra un esquema en arbol con información del
paquete. Podemos desglosarla en tramas, datagramas y segmentos pulsando los
[+] correspondientes.
- Ventana inferior - muestra el volcado real del paquete
seleccionado. Si pulsamos alguna parte del arbol en la ventana anterior
(central) podremos ver marcada en esta, la sección correspondiente a la rama
del arbol seleccionada..
- Barra de status - Permite filtrar segun un criterio, mediante el
boton RESET se puede restaurar la captura inicial completa sin ningun
tipo de filtro.
NOTA: Es posible que alguna o varias de las ventanas anteriores (superior, central e inferior) no coincidan con la descripción anterior, ya que pueden reducirse en tamaño hasta llegar a ocultarse.
Comenzando a capturar.
Para comenzar una nueva sesión lo único que debemos hacer es seleccionar en la pestaña de
CAPTURE (en la barra de menús) la opción de
START. También podríamos haber usado el atajo de teclado:
CRTL+K. Acto seguido, nos aparecerá una ventana en la que seleccionaremos una serie de opciones para capturar los datos. En esta parte hay que destacar lo siguiente:
- Capture
- Interface: eth0 (es el interface en el que deseamos
capturar los datos, en caso de que existan varios, es aquí donde
podemos seleccionar cual de ellos usar, o incluso todos con
any).
- Limit each packet to xx bytes: establece un límite para los
paquetes. Para nuestro propósito no nos interesa, por lo que dejamos
esta opción desmarcada.
- Capture packets in promiscuos mode: activa el modo
promiscuo en la tarjeta, es decir, se capturará todo lo que se escuche
en el interface de red seleccionado. Podemos desactivarla, ya que solo
nos interesa capturar lo que enviamos/recibimos nosotros.
NOTA: en una switched-lan esta opción no tiene mucho efecto; si deseamos
capturar paquetes en una red de este tipo debemos usar otro tipo de
sniffer como el ettercap.
- Filter: nos permite aplicar un filtro a lo que estamos
capturando.
- Capture file(s)
- File: captura directamente a un fichero.
- User ring buffer
- Display options
- Update list of packets in realtime: actualiza los paquetes
capturados en tiempo real. Esto consume bastante CPU, con lo que no lo
seleccionaremos.
- Automatic scrolling in live capture: hace un scroll
automatico de la informacion segun la va capturando. Para esta opción
es necesario tener la casilla anterior activada.
- Capture limits
- Stop capture after xx packets captured: establece un límite
en el número de paquetes.
- Stop capture after xx kilobytes captured: establece un
límite de Kb en la captura.
- Stop capture after xx seconds captured: establece un límite
de segundos de captura.
- Name resolution
- Enable MAC name resolution: activa la resolución de
direcciones físicas.
- Enable network name resolution: activa la resolución de
nombres dns.
- Enable transport name resolution: activa la resolución de
servicios.

Al pulsar OK, nos debe aparecer otra ventana, en la que empieza a dar unas estadísticas con los datos que se capturan y la posibilidad de parar el proceso.
Vamos a efectuar un proceso simple, abriremos una sesión ftp, listaremos los contenidos del directorio y cerraremos la sesión. Si nos fijamos en la ventana anterior (la de estadísticas) veremos que ha cambiado y refleja el número y tipo de paquetes capturados. Pulsaremos STOP en dicha ventana para finalizar la captura.
Análisis de datos.
Una vez que hemos parado la captura, la ventana principal debería semejarse a esto (a veces para refrescar la información hay que pulsar la pestaña de
RESET situada en la parte inferior de la ventana).
Analizaremos con un poco de detenimiento la información que hemos capturado. En primer lugar nos fijaremos en el orden de los primeros paquetes recibidos.
| No. | Time | Source | Destination | Protocol | Info |
| 1 | 0.000000 | 00:02:44:62:b2:4e | ff:ff:ff:ff:ff:ff | ARP | Who has 192.168.1.1 ? Tell 192.168.1.2 |
| 2 | 0.000348 | 00:02:44:62:b2:62 | 00:02:44:62:b2:4e | ARP | 192.168.1.1 is at 00:02:44:62:b2:4e |
1. ARP request: nuestro equipo quiere conectar con la
IP 192.168.1.1, pero no conoce su dirección física (MAC), por ello hace
una solicitud preguntando por broadcast.
2. ARP reply: el dueño
de la IP 192.168.1.1 escucha nuestra petición y nos contesta diciendonos
su direccion IP. |
| No. | Time | Source | Destination | Protocol | Info |
| 3 | 0.000406 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [SYN] |
| 4 | 0.001455 | 192.168.1.1 | 192.168.1.2 | TCP | 21 > 1024 [SYN, ACK] |
| 5 | 0.001617 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [ACK] |
Una vez que hemos averiguado la dirección física mediante el
protocolo ARP y que también conocemos la dirección IP del destino, podemos
saltar unos niveles más arriba en la capa de protocolos y establecer una
conexión TCP con el host remoto. Esto se hace entre los paquetes numero 3
y 5, mediante una conexión conocida como three-way handshake.
3. SYN: nuestro host envía una petición de conexión (FLAG SYN)
al host remoto.
4. SYN/ACK: el host remoto nos envía una
petición de conexión (SYN) confirmando la nuestra (FLAG ACK).
5.
ACK: nuestro host envía la confirmación (FLAG ACK). |
| No. | Time | Source | Destination | Protocol | Info |
| 6 | 0.015938 | 192.168.1.1 | 192.168.1.2 | TCP | 1024 > 113 [SYN] |
| 7 | 0.016024 | 192.168.1.2 | 192.168.1.1 | TCP | 113 > 1024 [RST, ACK] |
6. SYN: el host remoto intenta acceder a nuestro
puerto local 113 (identd) para autentificarnos.
7. RST/ACK: no
tenemos el servicio identd disponible en nuestro host, cerramos la
conexión (FLAG RST/ACK). |
Llegados a este punto, la conexión con el host remoto está establecida. En nuestro ejemplo de estudio, estábamos interesados en listar el contenido del directorio raiz del ftp. Si nos fijamos en la parte derecha (
Info) de la ventana superior, veremos que hay unas líneas que ponen
Respose: ..., esto es una pequeña parte de la información transferida, como deseamos verla toda, nos situaremos en el paquete donde la transferencia comienza (el número 8), pulsándolo en la ventana principal (superior) y a continuación haremos un filtrado de los datos para mostrar lo que realmente esta pasando en el nivel aplicación. Para ello usaremos la opción
FOLLOW TCP STREAM, del menú
TOOLS, también podríamos habernos situado con el raton en el paquete inicial y pulsar el boton derecho, para abrir una ventana de diálogo de menús, donde también aparecería dicha opción.
Este proceso de filtrado, extrae la información correspondiente a la capa de aplicación, que es la que en nuestro caso nos interesa analizar. Queremos saber cual es la estructura de los comandos del protocolo FTP y como se transmite la información (ASCII puro, binario...). Al pulsar la opción de FOLLOW TCP STREAM se nos abrirá otra ventana similar a esta:
Hay 2 partes diferenciadas:
- Datos: abarca la mayor parte, lo que recibimos sale en color azul y lo que enviamos en color rojo. En nuestro caso, el protocolo FTP usa
comandos en ASCII osea que es un texto legible, del cual podemos sacar
bastante información.
- Barra inferior.
- Pestaña izquierda: en ella podemos seleccionar lo siguiente:
- Entire conversation (por defecto) - muestra lo enviado y recibido en la
ventana de datos.
- 192.168.1.2:1024 ->; 192.168.1.1:21 : solo muestra
lo que enviado.
- 192.168.1.1:21 ->; 192.168.1.2:1024 : solo muestra
lo que recibido.
- Modo de visualización (ASCII / EBCDIC / Hex DUMP): son diferentes modos
de visualizar la información. Por defecto sale en ASCII y es la que nos
interesa.
- Print / Save as / Close: permite imprimir o grabar los datos de esta
ventana (ojo, solo estos).
Esta es la transcripción de paquetes que se suceden:
| No. | Time | Source | Destination | Protocol | Info |
| 8 | 0.152402 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 220 ProFTPD 1.2.5 Server (Debian)
[springfield.dns-local.net] |
| 9 | 0.152522 | 192.168.1.2 | 192.168.1.1 | TCP | 113 > 1024 [RST, ACK] |
| 10 | 0.153893 | 192.168.1.2 | 192.168.1.1 | FTP | Request: USER anonymous |
| 11 | 0.154195 | 192.168.1.1 | 192.168.1.2 | TCP | 21 > 1024 [ACK] |
| 12 | 0.158362 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 331 Anonymous login ok, send your complete
email address as your password. |
| 13 | 0.160653 | 192.168.1.2 | 192.168.1.1 | FTP | Request: PASS lftp@ |
| 14 | 170701 | 192.168.1.1 | 192.168.1.2 | TCP | 21 > 1024 [ACK] |
| 15 | 328063 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 230-Welcome, archive user
anonymous@192.168.1.2 ! |
| 16 | 0.328418 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 230- |
| 17 | 0.329057 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 230-The local time is: Tue Sep 3 16:57:45
2002 |
| 18 | 0.329355 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 230- |
| 19 | 0.361780 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [ACK] |
| 20 | 0.362268 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 230-This is an experimental FTP server. If
have any unusual problems,
230-please report them via
e-mail... |
| 21 | 0.362358 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [ACK] |
| 22 | 0.363816 | 192.168.1.2 | 192.168.1.1 | FTP | Request: PWD |
| 23 | 0.366798 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 257 "/" is current directory. |
| 24 | 0.369381 | 192.168.1.2 | 192.168.1.1 | FTP | Request: PORT 192,168,1,2,4,1 |
| 25 | 0.371912 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 200 PORT command successful. |
| 26 | 0.372797 | 192.168.1.2 | 192.168.1.1 | FTP | Request: LIST |
Pero nosotros, con el cliente de ftp habíamos hecho un listado del directorio raiz y sin embargo, no aparece reflejado en esta ventana, que ha pasado entonces ?. Si nos remitimos a la ventana principal del ethereal y pulsamos
RESET de nuevo, veremos que despues de los datos que van a partir del paquete 8, se abre otro socket por parte del servidor de ftp, a nuestro host, esta vez el puerto origen es el 20 (ftp-data) y el destino 1025, un puerto por encima del 1024, no privilegiado, que nuestro cliente de ftp ha especificado previamente en el paquete 24 con el comando PORT (podemos encontrar informacion de la estructura del comando PORT en el RFC).
Quizás haber empezado analizando el ftp no haya sido muy comodo y resulte algo confuso, ya que se usa un puerto para los comandos y otro para los datos, pero ya que estamos en ello, continuaremos. Al haber enviado el comando
LIST (paquete número 26) inmediatamente se abre el nuevo socket ftp-data (paquete 27) desde el puerto 20 del servidor al puerto que previamente habiamos definido 1025, de esta manera:
| No. | Time | Source | Destination | Protocol | Info |
| 27 | 0.375016 | 192.168.1.1 | 192.168.1.2 | TCP | 20 > 1025 [SYN] |
| 28 | 0.375153 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [SYN, ACK] |
| 29 | 0.375456 | 192.168.1.1 | 192.168.1.2 | TCP | 20 > 1025 [ACK] |
Se establece una nueva conexión mediante three-way
handshake, esta vez para el protocolo ftp-data. |
| No. | Time | Source | Destination | Protocol | Info |
| 30 | 0.376568 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 150 Opening ASCII mode... |
| 31 | 0.411776 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [ACK] |
La conexión se ha realizado con exito y nos lo confirma en
el puerto de ftp (21). Los siguientes paquetes deberían ser los
respectivos a los datos enviados por el puerto de ftp-data (el listado de
los contenidos del directorio que habíamos solicitado). |
| No. | Time | Source | Destination | Protocol | Info |
| 32 | 0.454864 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 58 bytes |
| 33 | 0.454999 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [ACK] |
| 34 | 0.455295 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 2 bytes |
| 35 | 0.455352 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [ACK] |
| 36 | 0.455947 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 58 bytes |
| 37 | 0.456017 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [ACK] |
| 38 | 0.456288 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 2 bytes |
| 39 | 0.456355 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [ACK] |
| 40 | 0.456966 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 63 bytes |
| 41 | 0.457042 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [ACK] |
| 42 | 0.457301 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 2 bytes |
| 43 | 0.458641 | 192.168.1.1 | 192.168.1.2 | FTP-DATA | FTP Data: 188 bytes |
Efectivamente se confirman nuestras sospechas, si nos fijamos en el protocolo del
paquete 32 es FTP-DATA. Además, si desplegamos en la ventana central la rama del arbol correspondiente a FTP-DATA, veremos que aparece una parte del listado del directorio. Volvemos a filtrar la informacion a partir de este paquete de la misma manera que antes, con la opción
FOLLOW TCP STREAM de la barra de menú
TOOLS.
Se nos abrirá otra ventana y en ella deberín aparecer los datos referentes al listado del directorio del ftp. El resultado debe ser similar a este:
En los siguientes paquetes, se nos confirma en el puerto de FTP, que la transferencia (listado del directorio) se ha realizado con éxito.
| No. | Time | Source | Destination | Protocol | Info |
| 44 | 0.460325 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 226-Transfer complete. |
| 45 | 0.460585 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 226 Quoutas off |
| 46 | 0.491803 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [ACK] |
| 47 | 0.491878 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [ACK] |
Llegados a este punto, ya hemos descubierto toda la parte de información que
buscábamos. A partir de aquí se cierran los sockets existentes, tanto el de
FTP, como el de
ftp-data. La conexion finaliza.
| No. | Time | Source | Destination | Protocol | Info |
| 48 | 0.4512769 | 192.168.1.2 | 192.168.1.1 | TCP | 1025 > 20 [FIN, ACK] |
| 49 | 0.512769 | 192.168.1.1 | 192.168.1.2 | TCP | 20 > 1025 [ACK] |
| 50 | 2.263758 | 192.168.1.2 | 192.168.1.1 | FTP | Request: QUIT |
| 51 | 2.264362 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [FIN, ACK] |
| 52 | 2.264674 | 192.168.1.1 | 192.168.1.2 | TCP | 21 > 1024 [ACK] |
| 53 | 2.267945 | 192.168.1.1 | 192.168.1.2 | FTP | Response: 221 Goodbye. |
| 54 | 2.266054 | 192.168.1.2 | 192.168.1.1 | TCP | 1024 > 21 [RST] |
Conclusiones del análisis.
El ftp, es un protocolo para intercambio de archivos (file transfer
protocol), usa 2 puertos TCP, el 20 para los datos y el 21 para los comandos.
Los comandos son en ASCII. La respuesta del servidor a nuestros comandos es
siempre numérica con una descripción despues del número, cualquier cosa
diferente a esta, se considera un comentario.
En este ejemplo no hemos analizado mas que una simple conexión para ejecutar
un comando de listado, sin tener en cuenta todos los factores que pueden
aparecer, como modos de transferencia ASCII/BINARY, modo PASSIVE para
transferencias detrás de un router o firewall y muchos otros. Podemos encontrar
toda la información que necesitemos en el RFC0959.
Provecho del análisis.
Intentaremos realizar en
Perl una
simulación de lo que hemos hecho previamente con nuestro cliente de FTP. He aquí
el listado de código que emula de un modo muy simple y mínimo la operación de
nuestro cliente de ftp:
#!/usr/bin/perl -w
#
# ftp-test by z0mbie (thesumidero@yahoo.com)
# example ftp-test code writted for the article
# "analyzing protocoles with ethereal"
#
# Copyright (C) 2002 Alejandro Portela, thesumidero@yahoo.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
require 5.005;
use strict;
use IO::Socket;
my $FTP_SOCK = IO::Socket::INET->new(
PeerAddr => "192.168.1.1",
PeerPort => 21,
Proto => "tcp"
);
unless ($FTP_SOCK) {
print "error, no se puede crear el socket\n";
exit(-1);
}
my $FTPDATA_SOCK = IO::Socket::INET->new(
LocalPort => 1025,
Proto => "tcp",
Listen => SOMAXCONN,
Reuse => 1
);
unless ($FTPDATA_SOCK) {
print "error, no se puede crear el socket\n";
exit(-1);
}
while (<$FTP_SOCK>) {
print "RECV <= ";
print;
if (/^220 /) {
print $FTP_SOCK "USER ftp\n";
print "SEND => USER ftp\n";
}
elsif (/^331 /) {
print $FTP_SOCK "PASS ftp\n";
print "SEND => PASS ftp\n";
}
elsif (/^230 /) {
print $FTP_SOCK "PWD\n";
print "SEND => PWD\n";
}
elsif (/^257 /) {
print $FTP_SOCK "PORT 192,168,1,2,4,1\n";
print "SEND => PORT 192,168,1,2,4,1\n";
}
elsif (/^200 /) {
print $FTP_SOCK "LIST\n";
print "SEND => LIST\n";
}
elsif (/^150 /) {
last;
}
elsif (/^425 /) {
exit(-1);
}
}
my $LIST = $FTPDATA_SOCK->accept();
while (<$LIST>) {
print "RECV <= ";
print;
}
close($LIST);
close($FTPDATA_SOCK);
print $FTP_SOCK "QUIT\n";
close($FTP_SOCK);
Puedes bajar una copia de este código fuente
aquí