Utilidades Pax para Gentoo
1.
¿De qué trata esta guía?
Introducción
La seguridad de un sistema es más que configurar decentemente un
cortafuegos y los servicios del mismo. Los binarios que se ejecutan y
las librerías que se cargan pueden ser también vulnerables a los ataques.
Aunque las vulnerabilidades exactas no se conocen hasta que son
descubiertas, hay algunas formas de evitar que ocurran.
Un vector posible de ataque es escribir y ejecutar segmentos en
un programa o librería, permitiendo a usuarios maliciosos ejecutar su
código a través de un aplicación o librería vulnerable.
Esta guía le informará acerca de cómo usar el paquete pax-utils
para encontrar e identificar binarios problemáticos. También hablaremos
del uso de pspax (una herramienta para ver las capacidades
específicas de PaX) y de dumpelf (una herramienta que
muestra una estructura C conteniendo una copia funcional de un objeto
dado).
Pero antes de empezar con esto, daremos alguna información sobre
objetos. Los usuarios familiarizados con los segmentos y el
enlazado dinámico no aprenderán nada en la siguiente sección y pueden
continuar con la sección Extraer información ELF
de los binarios.
Objetos ELF
Todos los binarios ejecutables de su sistema están estructurados de una
forma determinada, permitiendo al núcleo Linux cargar y ejecutar el
fichero. Realmente esto se aplica a más objetos que los binarios
ejecutables planos: esto también sirve para los objetos compartidos,
hablaremos de esto más adelante.
La estructura de estos binarios se define en el estándar ELF. El acrónimo
ELF significa Formato Ejecutable y Enlazable. Si está interesado
en los detalles internos, eche un vistazo a la
Especificación Genérica de ELF o a la página del manual
elf(5).
Un ejecutable ELF consta de las siguientes partes:
-
La cabecera ELF contiene información del tipo de
fichero (si es un ejecutable, una librería compartida,...), la
arquitectura destino, la localización en el fichero de la Cabecera
del Programa, Cabecera de Sección y de la Cabecera de las
Cadenas de Texto así como la localización de la primera
instrucción ejecutable.
-
La Cabecera del Programa informa al sistema acerca de cómo
debe crear un proceso desde el fichero binario. Realmente se trata
de una tabla que contiene entradas para cada segmento del programa.
Cada entrada contiene el tipo, direcciones (físicas y virtuales),
tamaño, derechos de acceso,...
-
La Cabecera de Sección es una tabla que contiene una entrada
para cada sección en el programa. Cada una de estas entradas contiene
el nombre, tipo, tamaño,... así como la información que
contiene la sección.
-
Datos, conteniendo las secciones y segmentos mencionados arriba.
Una sección es una pequeña unidad que contiene datos específicos:
instrucciones, datos variables, tabla de símbolos, información de
relocalización y demás. Un segmento es una colección de secciones.
Los segmentos son unidades que son transferidas a la memoria.
Objetos compartidos
Antiguamente, las aplicaciones binarias contenían todo lo que
necesitaban para operar de forma correcta. Estos binarios se
denominaban binarios enlazados estáticamente. Éstos consumían
mucho espacio debido a que las aplicaciones utilizaban las mismas
funciones una y otra vez.
Un objeto compartido contiene la definición e instrucciones para
esas funciones. Cada aplicación que las necesita puede enlazar
dinámicamente este objeto compartido de forma que puede
beneficiarse de la funcionalidad ya existente.
Una aplicación que está enlazada dinámicamente con un objeto compartido
contiene símbolos, referencias a la funcionalidad real. Cuando
se carga esta aplicación en memoria, en primer lugar pedirá la enlazador
dinámico que resuelva todos y cada uno de los símbolos que tiene
definidos. El enlazador dinámico cargará el objeto compartido apropiado
en memoria y resolverá las referencias simbólicas entre ellos.
Segmentos y secciones
El modo en que se revisa el fichero ELF, depende de la vista que
tengamos del mismo: cuando estamos tratando con un fichero binario en
Vista de Ejecución, el fichero ELF contiene segmentos. Cuando el fichero
está en Vista de Enlazado, el fichero contiene secciones. Un segmento
se extiende una o más secciones (continuas).
2.
Extraer información ELF de los binarios
La aplicación scanelf
La aplicación scanelf es parte del paquete
app-misc/pax-utils. Con esta aplicación se puede mostrar
información específica de la estructura del binario ELF. La siguiente
tabla resume las distintas opciones.
| Opción |
Opción larga |
Descripción |
| -p |
--path |
Escanea todos los directorios en el entorno PATH |
| -l |
--ldpath |
Escanea todos los directorios en /etc/ld.so.conf |
| -R |
--recursive |
Escanea los directorios de forma recursiva |
| -m |
--mount |
No salirse de los puntos de montaje cuando se escanee de forma
recursiva
|
| -y |
--symlink |
No escanear enlaces simbólicos |
| -A |
--archives |
Escanear archivos (ficheros .a) |
| -L |
--ldcache |
Utiliza la información de ld.so.cache (usar con -r/-n) |
| -X |
--fix |
Intentar corregir aquello que vaya 'mal' (usar con -r/-e) |
| -z [arg] |
--setpax [arg] |
Ajustar EI_PAX/PT_PAX_FLAGS a [arg] (usar con -Xx) |
| Opción |
Opción larga |
Descripción |
| -x |
--pax |
Imprimir marcas PaX |
| -e |
--header |
Imprimir marcas GNU_STACK/PT_LOAD |
| -t |
--textrel |
Imprimir información TEXTREL |
| -r |
--rpath |
Imprimir información RPATH |
| -n |
--needed |
Imprimir la información NEEDED |
| -i |
--interp |
Imprimir información INTERP |
| -b |
--bind |
Imprimir información BIND |
| -S |
--soname |
Imprimir información SONAME |
| -s [arg] |
--symbol [arg] |
Buscar el símbolo especificado |
| -k [arg] |
--section [arg] |
Encontrar la sección especificada |
| -N [arg] |
--lib [arg] |
Encontrar la librería especificada |
| -g |
--gmatch |
Usar strncmp para cotejar librerías (usar con -N) |
| -T |
--textrels |
Localizar la causa de TEXTREL |
| -E [arg] |
--etype [arg] |
Imprimir solo aquéllos ficheros ELF que coinciden con ET_DYN, ET_EXEC ...
|
| -M [arg] |
--bits [arg] |
Imprimir solo los ficheros que coinciden con los bits numéricos indicados
|
| -a |
--all |
Imprime toda la información escaneada (-x -e -t -r -b) |
| Opción |
Opción larga |
Descripción |
| -q |
--quiet |
Solo muestra aquello que va 'mal' |
| -v |
--verbose |
Salida ampliada (se puede especificar más de una vez) |
| -F [arg] |
--format [arg] |
Usar un formato específico para la salida |
| -f [arg] |
--from [arg] |
Leer la entrada desde un fichero |
| -o [arg] |
--file [arg] |
Escribir la salida a un fichero |
| -B |
--nobanner |
No mostrar la cabecera |
| -h |
--help |
Imprimir esta ayuda y salir |
| -V |
--version |
Imprimir la versión y salir |
Los especificadores de formato para la opción -F se muestran en la
siguiente tabla. Anteponga un carácter % (salida ampliada) o
# (salida silenciosa) a cada especificador a su antojo.
| Especificador |
Nombre completo |
Especificador |
Nombre completo |
| F |
Nombre de fichero |
x |
Ajustes PaX |
| e |
STACK/RELRO |
t |
TEXTREL |
| r |
RPATH |
n |
NEEDED |
| i |
INTERP |
b |
BIND |
| s |
Símbolo |
N |
Librería |
| o |
Tipo |
p |
Nombre del fichero |
| f |
Base del nombre del fichero |
k |
Sección |
| a |
ARCH/e_machine |
|
|
Usar scanelf para relocalizaciones de texto
Como ejemplo, usaremos scanelf para encontrar binarios que
contienen relocalizaciones de texto.
Una relocalización es una operación que sobreescribe una dirección en un
segmento que se ha cargado. Esta sobreescritura de la dirección puede
ocurrir cuando un segmento referencia a un objeto compartido y ese objeto
compartido está cargado en memoria. En este caso, las referencias se
substituyen con los valores reales de la dirección. Pueden ocurrir
eventos similares dentro del propio objeto compartido.
Una relocalización de texto es una relocalización en el segmento de texto.
Ya que estos segmentos contienen código ejecutable, los administradores
del sistema puede que deseen que no se pueda escribir en estos segmentos.
Esto es perfectamente posible, sin embargo, ya que estas relocalizaciones
de texto realmente escriben el segmento de texto, esto no es siempre
viable.
Si quiere eliminar las relocalizaciones de texto, necesitará asegurarse
de que la aplicación y el objeto compartido se han construido con
Código Independiente de la Posición (PIC), haciendo obsoletas las
referencias. Ésto no solo incrementa la seguridad, también incrementa
el rendimiento para el caso de objetos compartidos (para permitir la
escritura en el segmento de texto, se requiere reservar un espacio de
intercambio y una copia privada del objeto compartido para cada aplicación
que lo utilice).
El siguiente ejemplo busca binarios ELF que contengan una relocalización
de texto en sus rutas de librería de forma recursiva, y siempre en el
sistema de ficheros montado, ignorando los enlaces simbólicos.
Listado de Código 2.1: Escanea el sistema para buscar binarios con relocalizaciones de texto |
# scanelf -lqtmyR
|
Si quiere escanear su sistema completo para buscar cualquier fichero
que contenga relocalizaciones de texto:
Listado de Código 2.2: Escanea el sistema completo para buscar ficheros con relocalizaciones de texto |
# scanelf -qtmyR /
|
Usar scanelf para cabeceras específicas
La utilidad scanelf se puede usar para identificar rápidamente ficheros que
contienen una cabecera de sección dada usando la opción -k .section.
En este ejemplo buscamos recursivamente todos los ficheros en
/usr/lib/debug que han sido recortados usando un modificador de formato
con el modo silencioso habilitado. Un fichero elf recortado no posee
la entrada .symtab, por lo que usamos el carácter '!' para invertir
la lógica.
Listado de Código 2.3: Escanea en busca de ejecutables recortados o no |
# scanelf -k '!.symtab' /usr/lib/debug -Rq -F%F#k
|
Usando scanelf para buscar marcas de segmento específicas
Cada segmento tiene definiciones específicas en la cabecera del programa
binario. Una de estas definiciones es el tipo de segmento. Algunos valores
interesantes son: PT_LOAD (el segmento debe cargarse en memoria desde el
fichero), PT_DYNAMIC (el segmento contiene información de enlace dinámico),
PT_INTERP (el segmento contiene el nombre del intérprete de programa),
PT_GNU_STACK (una extensión GNU para el formato ELF, usado por algunos
mecanismos de protección de pila), y PT_PAX_FLAGS (una extensión PaX para
el formato ELF, usado por el proyecto
PaX pensando en la seguridad.
Si queremos escanear todos los ejecutables en el directorio de trabajo
actual, en el entorno PATH y en las rutas de las librerías y queremos
ser informados de aquéllos que tengan una marca de escritura y ejecución
PT_LOAD o PT_GNU_STACK, puede usar el siguiente comando:
Listado de Código 2.4: Escanea en busca de definiciones de escritura/ejecución PT_LOAD y PT_GNU_STACK |
# scanelf -lpqe .
|
Usar el manejador de modificación de formato de scanelf
Una característica útil de la utilidad scanelf es el manejador
de modificación de formato. Con esta opción puede controlar la salida
de scanelf, simplificando por tanto la salida mediante el uso de
guiones.
Como ejemplo, usaremos scanelf para mostrar los nombres que
contienen relocalizaciones de texto:
Listado de Código 2.5: Ejemplo del manejador de modificación de formato de scanelf |
# scanelf -l -p -R -q -F "%F #t"
|
3.
Listando definiciones y capacidades de PaX
Acerca de PaX
PaX es un proyecto que a su
vez está alojado en el proyecto
grsecurity. Citando la documentación PaX, su
principal objetivo es "investigar los distintos mecanismos de defensa
contra la explotación de fallos en el software que dan a un atacante
acceso de lectura y escritura al espacio de direcciones del proceso
atacado. Esta clase de fallos contiene, entre otros, varias formas de
desbordamiento de buffer (basados tanto en pila como en heap), fallos
por cadenas de usuario especialmente formateadas, etc.".
Para beneficiarse de estos mecanismos de defensa, necesitará correr un
núcleo Linux en el que se apliquen los parches de código de la última
versión de PaX. El proyecto Gentoo Hardened ofrece soporte
de PaX y su proyecto padre: grsecurity. El paquete del núcleo con estos
cambios es sys-kernel/hardened-sources.
El proyecto Gentoo/Hardened incluye la Guía rápida de comienzo con
PaX para su lectura.
Ajustes y capacidades
Si su cadena de herramientas lo soporta, sus binarios pueden tener
ajustes PaX adicionales en sus cabeceras de programa. Se permiten
los siguientes ajustes.
| Ajuste |
Nombre |
Descripción |
| P |
PAGEEXEC |
Rechaza la ejecución de código, en páginas en las que se puede
escribir, basándose en el bit NX (o el bit NX emulado).
|
| S |
SEGMEXEC |
Rechaza la ejecución de código, en páginas en las que se puede
escribir, basándose en la lógica de segmentación de la arquitectura
IA-32.
|
| E |
EMUTRAMP |
Permite la ejecución de secuencias de ejecución de código conocidas,
en páginas en las que se puede escribir, que no deberían causar ningún
daño.
|
| M |
MPROTECT |
Evita la creación de nuevo código ejecutable en el espacio de
direcciones del proceso.
|
| R |
RANDMMAP |
Aleatoriza la base de la pila para evitar que algunos ataques de
desbordamiento de pila tengan éxito.
|
| X |
RANDEXEC |
Aleatoriza las direcciones a las que la aplicación mapea para evitar
que algunos ataques sean practicables.
|
El núcleo por defecto de Linux también soporta algunas capacidades,
agrupadas en las llamadas Capacidades POSIX.1e. Puede encontrar
un listado de estas capacidades en nuestro documento Capacidades de POSIX.
Usar pspax
La aplicación pspax, parte del paquete pax-utils, muestra las
capacidades en tiempo de ejecución de todos los programas para los que se
tiene permiso. Estos atributos también se muestran en los núcleos Linux
con soporte adicional para atributos extendidos (como SELinux).
Cuando se ejecuta, pspax muestra la siguiente información:
| Columna |
Descripción |
| USER |
Propietario del proceso |
| PID |
Identificador del proceso |
| PAX |
Ajustes PaX en tiempo de ejecución (si se puede aplicar) |
| MAPS |
Marcas de escritura/ejecución para el mapa de proceso |
| ELF_TYPE |
Tipo de ejecutable del proceso: ET_DYN o ET_EXEC |
| NAME |
Nombre del proceso |
| CAPS |
Capacidades POSIX.1e (ver nota) |
| ATTR |
Atributos extendidos (si se puede aplicar) |
Nota:
La aplicación pspax únicamente muestra estas capacidades cuando
está enlazada con la librería de capacidades externa. Esto requiere que
se construya pax-utils con -DWANT_SYSCAP.
|
Por defecto, pspax no muestra ningún proceso del núcleo. Si quiere
que estos procesos sean tratados también, deberá usar la opción -a.
4.
Programar con ficheros ELF
La utilidad dumpelf
Con la utilidad dumpelf puede convertir un fichero ELF en un
fichero de código C legible por los humanos que define una estructura
con la misma imagen que el fichero ELF original.
Listado de Código 4.1: Ejemplo de dumpelf |
$ dumpelf /bin/hostname
#include <elf.h>
struct {
Elf32_Ehdr ehdr;
Elf32_Phdr phdrs[8];
Elf32_Shdr shdrs[26];
} dumpedelf_0 = {
.ehdr = {
|
El contenido de este documento, a no ser que se especifique
expresamente, está registrado bajo los términos de la licencia
CC-BY-SA-2.5. Se aplican las
Pautas de
Utilización del logotipo y nombre de Gentoo.
|