Leyendo el marco de la memoria física que antes pertenecía a otro proceso para leer el contenido de su página de memoria

26

Tuve una conversación con @ anger32 que dice que poner a cero un marco de página de memoria física al pasar la página respaldada por eso El paso a otro proceso no es responsabilidad de sistemas operativos como Windows y Linux (aunque lo hacen, no garantizan que esto suceda), sino una responsabilidad de los sistemas operativos con un certificado que le permita trabajar con información clasificada.

¿Es posible realizar el siguiente ataque en otro proceso (quizás más privilegiado)?

  1. asigne suficientes páginas de memoria y comience a consumir suficiente tiempo de CPU para evitar que el subproceso a cero, que tiene la prioridad más baja (al menos en Windows), obtenga tiempo de CPU.

  2. otro proceso coloca datos confidenciales en la memoria

  3. se produce un cambio de contexto

  4. solicitamos al sistema operativo una página de memoria, el sistema operativo desaloja la página del proceso y nos ofrece la nueva página respaldada por el mismo marco de página sin ponerla en cero.

  5. escaneamos la página en busca de secretos.

También afirma que hay formas de leer la memoria de otro proceso con mmap , sus marcas y direcciones físicas en Linux. ¿Conoce alguna? ¿Es realmente posible obtener la memoria de otro proceso en Linux, por ejemplo, la memoria del proceso de otro usuario o dominio SELinux? Si lo son, parece una vulnerabilidad muy peligrosa.

    
pregunta KOLANICH 13.01.2016 - 12:50
fuente

7 respuestas

23

En Linux, los procesos pueden leer otra memoria de proceso cuando se cumple alguna de las siguientes condiciones:

  1. El proceso tenía permiso de root o puede leer /proc/$PID/mem o /dev/mem , por defecto, /proc/$PID/mem y /dev/mem solo son accesibles por root
  2. El proceso principal puede fork() / clone() de tal manera que le permita leer parte o toda la memoria de sus procesos secundarios
  3. Un proceso padre puede bifurcar a un niño de tal manera que permita que el proceso hijo lea parte o toda la memoria de los padres
  4. Un proceso puede configurar el área de memoria compartida

Un proceso no puede leer o escribir en la memoria de un proceso arbitrario, no relacionado, a menos que el proceso se ejecute con privilegios elevados. En todos los demás casos, debe ser el proceso principal o el proceso objetivo tuvo que configurar deliberadamente el área de memoria compartida.

El proceso principal que puede acceder a una memoria de proceso secundaria es la característica que define a la mayoría de los sistemas Unix. En los sistemas Unix (incluido Linux), el nuevo proceso se crea utilizando la llamada al sistema fork() . fork() crea una copia del proceso existente al crear una nueva entrada en la tabla de procesos del sistema operativo, y configura la nueva memoria virtual de proceso como copia en escritura de la memoria virtual de los padres. Esto significa que el nuevo proceso puede leer la memoria del padre, pero en este punto, el nuevo proceso todavía está ejecutando el código del padre, por lo que este no es un problema de seguridad. El nuevo proceso puede luego llamar a una de las llamadas al sistema exec*() para reasignar un nuevo archivo ejecutable a su propia memoria y saltar al símbolo de inicio de ese archivo ejecutable. La reasignación significa que ahora la única entrada en la tabla de paginación en la nueva memoria virtual de proceso es el nuevo ejecutable. Cuando el nuevo proceso intenta leer / escribir en el área reasignada, provocará un error de página y el sistema operativo registrará la parte correspondiente del archivo ejecutable que fue exec*() -ed en la memoria. Si el nuevo proceso intenta leer / escribir en un área de memoria no asignada, esto causará una falla de segmentación. En los usos más avanzados de fork y exec, un proceso puede bifurcar y luego asignar la memoria del proceso secundario de tal manera que el padre pueda acceder a toda o parte de la memoria del niño después de exec*() .

En Linux, cuando un proceso asigna memoria (por ejemplo, usando malloc) del sistema operativo, el proceso llama a mmap() para asignar un mapa anónimo. Mapa anónimo se sirve desde la memoria RAM o swap. El mmap anónimo se rellena con cero por el kernel, a menos que el proceso solicite MAP_UNINITIALIZED , que solo se respeta en sistemas integrados muy restringidos por razones de rendimiento, el kernel tuvo que compilarse para permitir esto.

Además, para escenarios de alta seguridad, Linux permite que un proceso solicite que toda o parte de su memoria no se pueda cambiar mediante el uso de mlock y / o MAP_LOCKED. La memoria bloqueada siempre se sirve desde la memoria RAM y, por lo general, se usa para evitar que las claves de cifrado y la memoria utilizada para el descifrado se cambien al almacenamiento persistente.

    
respondido por el Lie Ryan 13.01.2016 - 13:37
fuente
23

Yo mismo sentí curiosidad por esto una vez, y escribí un pequeño programa en Linux que guardaba toda la memoria disponible y la descargaba en el disco.

Resultó que todo estaba en cero antes de ser entregado en mi solicitud.

Más tarde, también verifiqué el código del kernel, y pude confirmar que fue el kernel quien lo hizo.

-

Creo que tiene perfectamente sentido que es responsabilidad del sistema operativo asegurarse de que los datos antiguos no estén disponibles para otro proceso. ¿En qué otro lugar implementarías tal medida de seguridad?

Editar:

No recuerdo si probé contra la memoria SWAP. Debido al IO del disco requerido para poner a cero el espacio en disco asignado (memoria), podría implementarse de manera diferente.

    
respondido por el Dog eat cat world 13.01.2016 - 13:45
fuente
9

El ataque que describe no funciona en Windows. Dejar de lado el subproceso de reducción a cero de la página no impide la puesta a cero, solo lo retrasa. La existencia de la tarea de fondo de reducción de páginas es una optimización del rendimiento.

Básicamente, un administrador de memoria ingenuo con una garantía de privacidad funciona así:

  • reservar una página de la lista liberada
  • ponlo en cero
  • haga que esté disponible para el código de la aplicación (configure la entrada de la tabla de páginas para permitir el acceso al anillo 3)

La versión optimizada se parece más a:

  • obtener una página de la lista puesta a cero, si hay una
  • si el primer paso tuvo éxito, salte al último paso
  • reservar una página de la lista liberada
  • ponlo en cero
  • haga que esté disponible para el código de la aplicación (configure la entrada de la tabla de páginas para permitir el acceso al anillo 3)

Dejar de lado el subproceso de reducción a cero se traducirá en una asignación lenta, ya que la reducción a cero no se ha realizado todavía. No provocará fugas de datos, ya que la estructura de datos mantiene las páginas en cero y las páginas sobrantes segregadas, y cuando el asignador se queda sin páginas precasadas, tiene que hacer la reducción a cero justo a tiempo.

    
respondido por el Ben Voigt 13.01.2016 - 23:26
fuente
5

Es absolutamente posible leer la memoria de otro proceso, pero esto solo es posible con privilegios administrativos y, por supuesto, el sistema operativo no permitirá que ningún proceso acceda a ningún Espacio de la memoria que no está asignado a ese proceso.

Por supuesto, para usuarios administrativos es posible. En Windows, por ejemplo, esta funcionalidad se implementa de forma predeterminada para depurar un proceso. Puede hacerlo utilizando el Administrador de tareas como se describe en aquí .

Pero también es posible descargar toda la memoria, incluidos todos los procesos y todo lo que se almacena en la memoria en ese momento. Esto ya no es tan fácil porque los sistemas de Windows no proporcionan esta funcionalidad de forma predeterminada. Para hacer esto, la aplicación carga sus propios controladores de memoria, lo que les permite acceder a la memoria directamente y no a través del sistema operativo.

En sistemas Linux más antiguos, podemos descargar la memoria directamente a través del dispositivo de memoria en la partición /dev . Esto ya no es posible, pero hay módulos del kernel que también permiten descargar toda la memoria. Esto requiere también privilegios de root. También puede hacerlo manualmente para un proceso como el descrito aquí .

// EDIT : acabo de preguntar a un desarrollador senior con 40 años de experiencia al respecto. La respuesta es: se basa en varios factores. Me dijo que en C ++ y Java se inicializan las variables, lo que significa que una aplicación que está escrita en C ++ o Java no podrá obtener la información anterior porque se sobrescribe al inicializar esa variable. Pero C no hace esto, entonces podría ser posible, pero aún depende del sistema operativo.

    
respondido por el davidb 13.01.2016 - 12:59
fuente
2

Técnicamente, un sistema operativo podría reciclar páginas de procesos que tenían el mismo contexto de seguridad, ya que cualquier información que el nuevo proceso pudiera recopilar también sería accesible al proceso directamente.

Sin embargo, esto es completamente impráctico, ya que el contexto de seguridad de un proceso puede cambiar con el tiempo, y cuando se eliminan los privilegios (que es un patrón común), los datos contenidos en el proceso aún deben protegerse de cualquier persona con menos acceso permisos que el conjunto de privilegios original.

Teniendo en cuenta que los privilegios también pueden ser bastante específicos, el esfuerzo por realizar un seguimiento de los procesos a los que se puede otorgar una página sin restregarla primero es significativamente mayor que simplemente borrar cada página devuelta al sistema operativo, especialmente como memoria de computadora La arquitectura favorece en gran medida las escrituras secuenciales grandes.

Algunas arquitecturas integradas también usan el controlador DMA para esta tarea, reduciendo el tiempo de CPU a unos pocos ciclos para configurar el controlador y confirmar su finalización.

Si un proceso puede suponer que las páginas recién asignadas se borran es un contrato entre este y el sistema operativo, pero generalmente esto no se asume, y nuevamente, generalmente hay pocas razones para hacerlo, porque los procesos aún deben realizar un seguimiento de qué datos dentro de su espacio de direcciones consideran válidos, y solo lo harían para cualquier cosa que realmente contenga información.

Si una tarea asigna, modifica y desmarca las páginas rápidamente, esto aumentará la carga del sistema y los procesos pueden suspenderse mientras se espera un proceso de baja prioridad para borrar una página. Los sistemas operativos deben tener cuidado de no introducir inadvertidamente una inversión de prioridad aquí, aumentando temporalmente la prioridad de la tarea de reducción a cero de la tarea de mayor prioridad que intenta asignar una página.

    
respondido por el Simon Richter 13.01.2016 - 23:37
fuente
1

La mayoría de los sistemas operativos deben estar certificado para ser utilizados para ciertos fines / en ciertas organizaciones. La mayoría de ellos utilizan el marco Common Criteria para diferentes niveles de seguridad y algunos niveles requieren que el sistema operativo pase por una página antes de entregarla. otro proceso An

  

Una razón por la que se requieren páginas inicializadas con cero es para cumplir con varios   Requisitos de seguridad, como los criterios comunes. Más común   Los perfiles de criterios especifican que los procesos en modo usuario deben darse.   Se inicializaron los marcos de página para evitar que lean un mensaje anterior.   contenidos de la memoria del proceso. Por lo tanto, el administrador de memoria da   el modo de usuario procesa los marcos de página a cero a menos que la página se esté leyendo   desde una tienda de respaldo. Si ese es el caso, el administrador de memoria   Prefiere usar marcos de página no nulos, inicializándolos con los datos.   fuera del disco o almacenamiento remoto.

(de Windows Internals, Parte 2, 6ª ed. Por Mark E. Russinovich, David A. Solomon, Alex Ionescu. Copyright © 2012 por David Solomon y Mark Russinovich)

Para habilitar una característica de este tipo, la mayoría de las veces requiere que la arquitectura de administración de la memoria se diseñe en consecuencia y no tiene sentido excluir esta característica en una versión "civil" / insegura para obtener ganancias de rendimiento no obvias.

Específicamente, es importante que las páginas del kernel y las de otros usuarios no se filtren a procesos sin privilegios, por lo que tendrán que ser eliminadas en algún momento. También es ineficiente que una página se ponga a cero a menos que realmente cruce el límite superior (en caso de que una página se asigne nuevamente al mismo proceso / kernel). Por lo tanto, el único momento sensato para hacerlo es en el momento de la asignación y, dado que no se puede confiar en que el receptor haga esto, el sistema operativo tendrá que asumir la responsabilidad. (Por supuesto, el sistema operativo del mundo real adoptará todo tipo de optimizaciones para reducir el retraso en la asignación de páginas).

    
fuente
-3

La única forma práctica de realizar lo que estás hablando es un Ataque de arranque en frío , cuando estás destruyendo el kernel al apagarlo. O puede intentar jugar con kexec() calls, pero no funcionará en la mayoría de los casos.

    
respondido por el Alexey Vesnin 13.01.2016 - 17:28
fuente

Lea otras preguntas en las etiquetas