Limited Entropy Dot Com Not so random thoughts on security featured by Eloi Sanfèlix

15Nov/075

Smart cards: Introducción

Posted by Eloi Sanfèlix

Puesto que este cuatrimestre estoy haciendo una asignatura basada al 90% en smart cards, aprovecho para contar aquí algunas cosillas de las mismas que tal vez resulten de interés :). En este primer artículo veremos qué es exactamente una smart card, comentando sus principales bloques funcionales y para qué se pueden utilizar. Más adelante comentaré algunas peculiaridades de la programación de smart cards usando la plataforma JavaCard.

Arquitectura típica de una smart card

Básicamente una smart card es un computador embedido en un pequeño chip, capaz de almacenar y procesar de forma segura datos. Generalmente se divide en varios tipos de smart cards, en función de sus posibilidades:

  • Tarjetas de memoria: almacenan datos que pueden ser leídos a posteriori, posiblemente con cierto control de acceso o con mecanismos de memoria destructiva ( write-only ). Toda la funcionalidad de estas tarjetas está en una memoria ROM, de forma que siempre responden de la misma forma a una instrucción (leyendo la dirección de memoria correspondiente).
  • Tarjetas con microprocesador: Además de almacenar información, estas tarjetas incorporan un microprocesador para el tratamiento de dicha información mediante el software correspondiente.

A veces se incluye (vease tarjetas inteligentes en wikipedia) otro tipo de tarjetas llamado tarjetas criptográficas, que incluye además un coprocesador criptográfico capaz de realizar cifrado utilizando por ejemplo RSA, DES o triple DES. Sin embargo yo este tipo lo incluiría en el grupo de tarjetas con microprocesador.

Aquí me centraré en las tarjetas con microprocesador, puesto que las podemos programar y son capaces de ofrecer funciones de seguridad bastante interesantes. Generalmente estas tarjetas llevan 3 tipos de memoria:

  • ROM: Incluye el sistema operativo de la tarjeta.
  • EEPROM: El disco duro de estas tarjetas.
  • RAM:Espacio de trabajo donde encontramos la pila, variables temporales como claves criptográficas válidas durante la sesión actual, etc.

Según los datos que yo tengo de la asignatura HW & OS Security , una tarjeta actual típica puede tener unos 512 bytes de RAM, 16K de ROM y 64K de EEPROM. En principio se usaban SO propietarios y cada tarjeta se programaba con su propia API en C, pero actualmente existen sistemas como JavaCard que ofrecen una API común que los fabricantes pueden implementar en sus tarjetas. Más adelante veremos cómo realizar aplicaciones básicas con JavaCard ;).

Aplicaciones de las smart cards

Para finalizar con este post introductorio simplemente voy a comentar algunas de las aplicaciones comunes de las smart cards.

  • Firma digital: Puesto que las tarjetas son capaces de realizar funciones criptográficas, pueden utilizarse para firmar documentos digitalmente. Simplemente se almacenan en la tarjeta las claves criptográficas correspondientes al usuario (clave privada RSA por ejemplo) y cuando se le pasa un documento a la tarjeta ésta lo firma. El problema que puede surgir aquí es que realmente no sabemos lo que se está mandando a la tarjeta para firmarlo, así que habría que autenticar de alguna forma el terminal usado.
  • Dinero electrónico: Se pueden utilizar estas tarjetas como monedero electrónico. Por ejemplo, en Holanda tienen el sistema Chipknip.
  • TV de pago: televisiones como Digital+ utilizan este tipo de tarjeta para identificar al usuario. La tarjeta se introduce en el decodificador y con ella se tiene acceso al contenido de pago, mediante claves de cifrado contenidas en la tarjeta.
11Nov/071

inotify: notificación de eventos del FS en Linux

Posted by Eloi Sanfèlix

Mucha gente a día de hoy usa sistemas de búsqueda rápida de ficheros como Beagle (Linux y otros unix - web oficial no disponible ahora mismo) o Spotlight (OS X), que devuelven resultados de manera prácticamente instantánea. ¿Cómo funciona un software de este estilo? La idea que nos viene a todos a la mente es indexando los directorios en los que se quiere buscar para que todo vaya rápido, pero indexar cada cierto tiempo los directorios es poco eficiente y se debería buscar un compromiso entre la reducción de rendimiento producida por el indexado y la latencia con la que aparecen los archivos en el sistema de búsqueda.

Es aquí donde sistemas de notificación de eventos del sistema de ficheros pueden ser útiles. Inotify es un subsistema del kernel Linux que ofrece la posibilidad de escuchar en ciertos ficheros/directorios para recibir notificaciones de eventos en los mismos. Viene por defecto en el kernel desde 2.6.13 :).

Los artículos Intro to inotify ( en Linux Journal, por Robert Love) y Monitor Linux file system events with inotify (IBM developerWorks) ofrecen una introducción bastante maja a inotify y su uso, así que no voy a comentar mucho sobre ellos aquí. Lo que sí voy a hacer es dejaros una pequeña utilidad ( watch.c , correspondiente a un ejercicio de la asignatura que está alimentando este blog últimamente) que escucha en $HOME y /tmp y notifica de los cambios.

Un pequeño fallo que le veo a inotify es que no proporciona la posibilidad de escuchar un directorio y todos sus subdirectorios de forma recursiva, pero eso no es tarea del subsistema del kernel, sino de algún wrapper que funcione sobre ello, por ejemplo dentro de la libc o de una hipotética libinotify. A falta de dicho wrapper, hay que hacer una función recursiva que añada watches a todos los subdirectorios (ver el código).

La mayor parte de la aplicación se concentra en la función report() que muestra la información de los eventos y actúa en consecuencia (eliminando watches en caso de borrado, actualizándolos en caso de cambios de nombre o movimientos de directorios, etc.), aunque no tiene mucha complicación.

Además decidí usar una lista enlazada para almacenar los watches, tanto los paths como los watch descriptor correspondientes.

Finalmente, notar el uso del campo cookie de la estructura inotify_event que permite sincronizar los eventos IN_MOVED_FROM e IN_MOVED_TO. De esta forma es posible saber si dos de estos eventos están relacionados (es el mismo archivo) o no. Además, inotify generará esos eventos de forma consecutiva, con lo que simplemente habrá que comprobar si el evento siguiente a un IN_MOVED_FROM es su correspondiente IN_MOVED_TO o no (comprobando la cookie ) y actuar en consecuencia.

La verdad es que me ha parecido curioso el tema de inotify y creo que la utilidad ha quedado bastante maja 🙂

Filed under: GNU/Linux, Seguridad 1 Comment
6Nov/074

Shamir’s secret sharing: Secretos digitales compartidos

Posted by Eloi Sanfèlix

Con este post voy a salirme un poco de lo que viene siendo la temática habitual para meterme en otra un poquito más freak si cabe: la criptografía. No vamos a hablar de ningún algoritmo de cifrado ni de ningún criptosistema, sino de una técnica para compartir secretos digitales.

¿Qué es eso de compartir secretos? Imaginemos que somos parte del comité ejecutivo de una compañía que ha creado un producto revolucionario y desea que sus detalles se guarden en secreto, pero nuestro comité ejecutivo desea poder acceder a dicho secreto. Sin embargo, no queremos que un único miembro de dicho comité pueda acceder al secreto, sino que haya un determinado número de miembros presentes para dicho acceso. De esta forma, si un miembro por la razón que sea intenta acceder al secreto solo, el acceso será denegado.

Cómo podemos conseguir eso? Todos sabemos que para crear una recta sólo necesitamos dos puntos, una parábola 3, etcétera. Por tanto, una forma sencilla conocida como el esquema de Shamir (en inglés) se basa en el hecho de que con k+1 puntos de un polinomio somos capaces de reconstruir el polinomio entero. Para ello, se usa la interpolación polinómica de Lagrange , y en base a un determinado número de puntos se obtiene el polinomio.

Así pues, lo que habría que hacer para un esquema de secretos compartidos con n usuarios totales y un mínimo de k para obtener el secreto es lo siguiente:

  • Codificar el secreto como un entero, S.
  • Elegir un polinomio de grado k-1, f(x)=S+a·x + b·x^2 + ...
  • Obtener n puntos de dicho polinomio y repartirlos a los n usuarios.

Así pues, cada usuario tiene su punto, y el polinomio se mantiene en secreto. Cuando se juntan k o más usuarios, simplemente aplican la fórmula de interpolación de Lagrange sobre esos puntos, y obtienen el término independiente del polinomio: nuestro secreto.

Este esquema se puede usar por ejemplo para el acceso a un sistema, siendo el secreto el password de acceso y teniendo cada usuario su propia clave. De esta forma, se proporcionan tres claves al sistema y éste reconstruye el polinomio mediante la fórmula de interpolación de Lagrange. Si el término independiente coincide con el esperado el acceso es permitido, y si no es denegado.

Un ejemplo simple e interesante de lo que pueden dar de sí las matemáticas, aplicando cosas sencillas que la mayoría conocemos de forma inteligente 🙂

28Oct/070

Trazando procesos con ptrace()

Posted by Eloi Sanfèlix

Esta vez vamos a hablar un poco de ptrace(), una llamada al sistema de los sistemas Unix (al menos la mayoría de ellos) que permite trazar procesos: ejecutarlos paso a paso, ver qué hay en su memoria, en los registros, etcétera. Aunque por ejemplo la implementación de ptrace() de OS X es bastante poco útil y sólo permite ejecutar paso a paso, continuar la ejecución y poco más... pero bueno, de eso hablaré un poco al final 😉

En este post voy a explicar cómo va ptrace y algunas de las posibilidades que ofrece en linux, aunque para eso ya está la página del manual pero siempre aportará algo. Finalmente enlazaré un código que he hecho como ejercicio de la asignatura Linux Kernel & Hackers Hut: se crea un hijo, se traza con ptrace() y se ejecuta un comando pasado como parámetro en el hijo, pero se modifican todas las llamadas a open("/etc/passwd",...) por open("/tmp/passwd",...). También añadí las llamadas a stat64() porque la utilidad cp tiene una pequeña protección: primero se llama a stat64 sobre el fichero origen, luego se abre el fichero, y se llama a fstat64() sobre el descriptor. Tras esto, se comprueba que las dos estructuras devueltas por stat64 y fstat64 sean del mismo fichero, mirando que el i-node y el identificador de dispositivo coincidan.

17Oct/072

LaTeX-Suite: Plugin para editar LaTeX en VIM

Posted by Eloi Sanfèlix

Puesto que aquí lo habitual es usar LaTeX en los trabajos, hace unos días me instalé gwTex en el macbook y empecé a trastear con el tema. Hace años toqué LaTeX para escribir un trabajillo, pero lo dejé ahí apartado y no lo había usado desde entonces (hará como 5 años).

Me puse a buscar si había algún editor de LaTeX majo, y me encontré con un plugin para Vim que puede resultar bastante cómodo a los que estén acostumbrados a vim y tengan que usar latex: Latex-Suite . Tras la instalación me leí un tutorial rápido y empecé a usarlo para uno de los problemas de Crypto1 que debo entregar esta semana, ya que es más cómodo para escribir los polinomios que andar usando OpenOffice, buscando en el menú 'Insertar fórmula', añadiendo la fórmula, saliendo con doble click, etc.

El caso es que el plugin tiene muuuuchas cosas, y voy a resumir aquí algunas interesantes para tenerlas a mano y no tener que leerme el manual cada vez que busque alguna de estas en el futuro.

  • Exx añade un nuevo environment. Ejemplo: EDO añade un documento, y te situa en el \documentclass
  • Placeholders: cuando estás en algún comando, con Ctrl-J puedes moverte al símbolo <++> que muestra Latex-Suite.
  • F5 en el preámbulo sobre una palabra te añade un paquete. Por ejemplo, graphicx y <F5> resulta en \usepackage{graphicx}
  • F5 en una línea en blanco te ofrece una lista de environments ( equation, eqnarray, ...)
  • F9 sirve para completion, aunque tendré que cambiar las hotkeys de expose o este binding para poder usarlo en OS X.
  • F7 sobre una palabra la convierte en comando.
  • Fxx sirve para poner tipos de fuente: FBF --> \textbf{}. Te situa dentro de las llaves con un placeholder al final.
  • Sxx para poner secciones: SSE --> \section{}, SSS --> \subsection{} y así con algunos más.
  • Para poner letras griegas, se usa `x , con una a para alpha, b para beta, etc. Además con algunas mayúsculas también sirve ( S == sigma, W == omega, L==lambda , etc).

A parte de las mejoras para edición, latex-suite te permite compilar mediante \ll cuando estás en modo comando en vim, y en teoría visualizar mediante \lv, aunque a mí no me va y no me he parado mucho a mirarlo...

Seguro que me dejo muchas cosas, porque Latex-Suite tiene un montón de bindings y ayudas para muchos casos, y justo ahora empiezo a usar LaTeX en serio, y por ejemplo el tema de bibliografía y demás no lo he usado pero Latex-Suite lleva ayudas para ello.

Filed under: General 2 Comments
15Oct/073

En busca de un tema para el proyecto

Posted by Eloi Sanfèlix

El otro día estuve hablando con Andries Brouwer y parece ser que el hombre está dispuesto a supervisarme el proyecto, aunque me recordó que él era matemático y no experto en seguridad, aunque pensaba que había mucha gente en la universidad con conocimientos formales sobre seguridad pero que (en su opinión) fallaban en el aspecto práctico.

El problema es que el tema del proyecto no está nada claro.  De hecho, me dijo que hiciera el proyecto sobre lo que yo quisiera. Si él sabía del tema que elegía, entonces me podría ayudar, y si no sabía aprendería de mis investigaciones.

Me propuso comparar SMACK con SELinux, ver si pese a ser mucho más sencillo (por lo poco que he mirado hay cosas que se pueden ahcer con SELinux que no se pueden hacer con SMACK) sigue siendo suficiente seguro o no... pero quizás el tema puede resultar demasiado pesado de configurar y analizar en detalle.

Otra opción que había pensado yo es en tratar de desarrollar alguna herramienta de seguridad como por ejemplo sobre detección/prevención de rootkits en linux o algo por el estilo, o quizás analizar alguna solución como grsec.

De todas formas no estoy totalmente convencido por ninguna opción, así que si alguien tiene alguna idea que pueda resultar interesante desarrollar o analizar, le agradecería lo dejara en los comentarios :).

Filed under: General 3 Comments
15Oct/071

De nuevo fuera de servicio

Posted by Eloi Sanfèlix

Una vez más el blog ha estado fuera de servicio este fin de semana.  El problema fue la tormenta que cayó en Valencia el jueves pasado... al parecer los equipos estaban en marcha, pero la electrónica de red no estaba funcionando.

Hasta que esta mañana no han entrado de nuevo a trabajar en la escuela y se ha puesto todo en orden, el servidor ha estado caído 🙁 Esperemos que pase mucho tiempo hasta la próxima caída de este estilo jeje

Filed under: General 1 Comment
11Oct/074

Namespaces: una visión distinta del árbol de directorios para cada proceso

Posted by Eloi Sanfèlix

Sigo dando la coña con los ejercicios de Linux Kernel & Hackers Hut como viene siendo habitual 😛 Esta vez le ha tocado el turno a los namespaces. Es de sobra conocido el concepto de los chroot, que se viene utilizando desde hace mucho tiempo: cambiamos el directorio raiz de nuestro proceso (y todos los hijos que cree éste) por otro distinto, restringiendo su visión del árbol de directorios.

Esto se puede hacer desde la consola con la utilidad chroot o con la propia llamada al sistema chroot. Para ejecutar algo en un chroot necesitaremos tener disponibles dentro del mismo tanto los ejecutables como las librerías de las que dependa, o bien compilarlo de forma estática. Con esto y usando los mínimos privilegios para un servicio dado podremos reducir el impacto de una posible vulnerabilidad en dicho servicio.

Pues bien, el tema de los namespaces, aunque relativamente similar, es algo distinto. El namespace es el concepto que tiene un proceso dado del árbol de directorios. En un principio, todos los procesos comparten dicho concepto, heredándolo de init. Sin embargo, desde 2.4.19 el núcleo de linux incluye la posibilidad de ejecutar nuevos procesos con una copia del namespace de su padre.

¿Y en qué influye esto? Pues en que a partir de ahora, si nuestro proceso realiza un mount sobre un directorio cualquiera, solamente él y sus hijos lo podrán ver, pues son los únicos que tienen acceso a dicho espacio de nombres. Si desde otro proceso se monta cualquier dispositivo (o directorio usando --bind ) sobre un directorio dado, nuestro proceso tampoco lo verá.

Un ejemplo de uso sería montar un /tmp diferente para cada nueva sesión de usuario (por ejemplo un bind de /tmp/uid sobre /tmp en el namespace del usuario), de forma que no puedan ver los ficheros temporales de otros usuarios.

Se pueden ver varios ejemplos en este artículo de IBM developerWorks. Los artículos muestran como aplicarlo el login usando PAM; no los he probado, quizás un día de estos que tenga menos trabajo...

Para acabar, comentar que la forma de crear un proceso con una copia del namespace de su padre es llamando a clone() [similar a fork()] con el flag NEW_NS. Está todo explicado en el man de clone ;).

24Sep/073

Sparse files: posible ahorro de espacio

Posted by Eloi Sanfèlix

Una vez más, Andries Brouwer en su asignatura me ha enseñado algo interesante, esta vez incluso sin ir a clase pues estaba en España. Tras el ejercicio anterior de las syscalls, y otro que no posteé porque no lo consideraba interesante ( explotar una format string normal y corriente, sin protecciones tipo va_patch ni nada... ) esta vez toca crear una utilidad que copie un archivo normal a un 'sparse file'.

Y qué es eso? Pues según wikipedia :

In computer science, a sparse file is a type of computer file that attempts to use file system space more efficiently. When space has been allocated to a file but not actually filled with data it is not written to the file system. Instead, meta-information about these "empty" regions is stored until they are filled with data.

File systems supporting sparse files include: VxFS, Apple DOS, CP/M, NTFS, ext2, ext3, GPFS, XFS, JFS, ReiserFS, Reiser4, UFS, ZFS, VMFS

Y cómo creamos uno de estos archivos a partir de su equivalente 'normal' ? Pues muy sencillo: cuando leemos un bloque de 0's, en lugar de escribirlo en disco lo que haremos será un lseek para avanzar el puntero esas posiciones. En mi caso, lo que he hecho ha sido leer byte a byte y hacer el lseek si el byte leído era 0 y hacer un write si no lo era. Algo así:

while( (n=read(ifd,&buf,1))>0 ){
if(buf==0){
if(lseek(ofd,n,SEEK_CUR)==-1)
goto error;
} else {
if(write(ofd,&buf,n)==-1)
goto error;
}
}

En este caso, ifd es el descriptor del archivo de entrada, ofd del de salida, y buf es un char. Seguramente sería más eficiente leer bloque a bloque, y para ello tenemos dos opciones: leer un bloque de tamaño fijo o bien averiguar el tamaño de bloque del dispositivo de salida. Para lo primero yo he usado un simple #define, y me he creado un buffer auxiliar para rellenarlo con 0's usando memset( ) y hacer la comparación con memcmp( ), derrochando 4k de memoria pero evitando hacer la comparación a mano que tenía pereza 😉

La segunda opción no la he implementado, pero existe la syscall [f]statfs que nos devuelve una estructura con información de un sistema de ficheros montado, entre ella el tamaño de bloque.

Para probar el programita yo lo que he hecho es lo siguiente:

~/work/lk_hh $ dd if=/dev/urandom of=my_no_zeros bs=4096 count=22+0 records in
2+0 records out
8192 bytes (8,2 kB) copied, 0,0042889 s, 1,9 MB/s
~/work/lk_hh $ dd if=/dev/zero of=my_zeros bs=4096 count=5
5+0 records in
5+0 records out
20480 bytes (20 kB) copied, 0,000177221 s, 116 MB/s
~/work/lk_hh $ cat my_no_zeros my_zeros my_no_zeros my_zeros my_no_zeros > my_no_sparse_file
~/work/lk_hh $ ./cpsparse my_no_sparse_file my_sparse_file
~/work/lk_hh $ du -sh *sparse_file
64K my_no_sparse_file
24K my_sparse_file
~/work/lk_hh $

Se puede comprobar que en este caso se han ahorrado 40k, correspondientes a las diez veces que aparece un bloque entero de bytes nulos: cinco por cada vez que concatené el archivo my_zeros.

Esto de los sparse files podría ser interesante para archivos grandes como imágenes .iso o similares que pudieran contener bloques de bytes nulos, aunque no sé si en la práctica será útil o no, no he probado con archivos comunes. Alguien tiene idea? Alguna sugerencia sobre el código o algo que aportar al respecto?

PD: Lo de usar goto para el control de errores es lo que se hace en el kernel y sugerencia del profesor en su primera clase. Así tienes el control de errores localizado y no mil if's anidados por cada posible error del código.  En la etiqueta error lo que se hace es el cleanup, en mi caso simplemente cierro los archivos y me cargo mediante unlink( ) el que he creado puesto que no es correcto.

Filed under: GNU/Linux 3 Comments
13Sep/076

Varias formas de llamar a una syscall en C

Posted by Eloi Sanfèlix

Como trabajo inicial de la asignatura Linux Kernel & Hackers Hut, después de la primera clase nos mandó hacer un pequeño programa en C que creara un directorio, de tres formas distintas: con la llamada correspondiente de la libc, con la función syscall de libc y saltándose la libc por completo.

Las dos primeras formas son bastante sencillas... vamos a ver el ejemplo de mkdir. En el primer caso, haríamos una simple llamada como ésta:

#include <sys/stat.h>
#include <sys/types.h>

[...]

mkdir(argv[1],0777);

Donde argv[1] es el nombre del directorio y 0777 son los permisos dados en notación octal.

En el segundo caso, simplemente necesitamos saber que la llamada al sistema se llama mkdir y que las constantes con los nombres de las llamadas al sistema tienen la forma SYS_xxxx, con xxxx el nombre de la llamada. Es importante esto, pues yo estaba usando __NR_mkdir tal y como se llama en el kernel 😳 .


#include <sys/syscall.h>
#include <unistd.h>

[...]

syscall(SYS_mkdir,argv[1],0777);

Finlamente, la última es un poco más especial. Necesitamos saber: tipo del valor de retorno, número de parámetros y sus tipos, así como el nombre de la llamada al sistema. Las macros se llaman _syscallX, donde la X va de 1 a 5 según el tipo de parámetros.

Así pues, sabiendo la llamada al sistema que queremos hacemos un man 2 y vemos el prototipo. Con éste, llamamos a la macro _syscallX correspondiente antes de nuestro main, y luego en el main ya podemos usar la syscall como si de cualquier otra función se tratase:


#include <linux/unistd.h>
#include <sys/types.h>
#include <errno.h>

//Dirty hack so it compiles on my x86_64 machine
#ifndef MAX_ERRNO
#define MAX_ERRNO 4095
#endif

_syscall2(int,mkdir,const char *, pathname, mode_t, mode);

int main(int argc, char **argv){
return mkdir(argv[1],0777);
}

En mi caso he tenido que añadir ese define condicional puesto que no compilaba debido a que la constante MAX_ERRNO no estaba definida. Busqué en google y parece ser que es un fallo en la libc para x86_64, al menos en la versión que yo tengo así es.

Las dos últimas formas son interesantes para cuando se añade una llamada al sistema que queremos usar y la libc no nos ofrece todavía un wrapper para ella, con lo que la debemos llamar a mano. Otra opción sería meter un poco de inline assembly, pero teniendo estas opciones me parece que es un poco bestia hacerlo, además de que se vuelve dependiente de la arquitectura, lo cual no es muy bueno... a no ser que necesitemos velocidad o control máximo y así lo podamos ganar, que tampoco sé la diferencia de velocidad entre usar la macro _syscallX y llamar directamente a la syscall desde ensamblador.

Por último, comentar que si la llamada al sistema tiene más de 5 parámetros no se pueden usar las macros, sino que se deben poner los parámetros en la pila y pasando un único parámetro: un puntero al bloque de argumentos en la pila.

Notar también que es interesante conocer ambos métodos, porque dependiendo de la libc que se use puede que se tenga la función syscall() o no, y si no la tenemos deberemos apoyarnos en las macros para hacer las llamadas.

Filed under: Erasmus, GNU/Linux 6 Comments