lunes, 5 de febrero de 2024

Root en Android

 



    Tenemos nuestro móvil Android y queremos trastear su hardware y sacarle más provecho, ¿por qué Android no nos permite acceder a todo el hardware?

    Android utiliza un sistema de permisos basado en el principio de "privilegio mínimo necesario", controlando el acceso a recursos y funciones críticas del sistema. Este sistema está diseñado para garantizar la seguridad y la integridad del sistema operativo. Las versiones principales de Android se pueden distinguir en dos tipos de compilaciones, las compilaciones de desarrollo, destinadas a ingenieros y desarrolladores, que incluyen herramientas de depuración, acceso root y otras configuraciones para facilitar el desarrollo y la depuración. Tienen ninguna o pocas restricciones de seguridad. Y la compilación de dispositivo comercial destinada al usuario final, cuya consulta getprop ro.build.typeen una consola como “adb shell devuelve “user”. Cuenta con todas las restricciones de seguridad y no incluye herramientas de depuración. Por esta razón nuestro móvil no nos permite acceder a todo el hardware.

    ¿Cómo podemos ganar privilegios? ¿Cómo podemos obtener acceso root? Obtener el root en dispositivos que son comerciales es sencillo cuando se puede desbloquear el bootloader, pero puede ser un desafío en los otros casos en lo que no se puede desbloquear. En sistemas dónde el bootloader es desbloqueable se puede flashear la partición system por una que cambie el sistema operativo de una versión comercial a una versión de desarrollo, habilitando el acceso root. Esto se consigue modificando las propiedades ro.secure y ro.debuggable en el fichero “build.prop”.

  • ro.secure: Esta propiedad determina si el sistema se inicia en modo seguro. Si ro.secure está configurado como "1", el sistema se inicia en modo seguro, lo que significa que ciertas funcionalidades de depuración y acceso root pueden estar deshabilitadas o restringidas.

  • ro.debuggable: Esta propiedad indica si el sistema está configurado para ser depurable. Al configurarlo como "1", se permite la depuración del sistema. En una compilación de usuario final comercial, esta propiedad está configurada como "0" para mejorar la seguridad.

    Hay que tener en cuenta que desbloquear el bootloader provocará que la partición /data se borre, y que algunos bootloaders iniciarán un flag permanente indicando que el bootloader ha sido modificado, además este flag permanecerá incluso si se vuelve a bloquear.

    Al arrancar el sistema operativo con esta modificación en la partición System estaremos produciendo un cambio similar a como funciona una compilación de desarrollo y esto nos permite habilitar el acceso root. Al ejecutaradb rootestaremos consiguiendo una shell root. Además se puede instalar el binario “su”, asignándole el bit SUID y permitiendo el cambio al usuario root directamente.

    Puede ocurrir que la distribución comercial Android de nuestro móvil haya sido compilada sin definir la macro relativa al demonio adbd “ALLOW_ADBD_ROOT” que provoca que se ignoren las propiedades ro.secure y ro.debuggable, no permitiendo el acceso root. Si ALLOW_ADBD_ROOT está definido, el demonio adbd permitirá el acceso root.

    En esta situación aun nos quedaría el binario “su”, que habríamos agregado con el bit SUID, permitiendo el acceso root no solo desde la shell, sino también desde aplicaciones de terceros. Sin embargo las versiones actuales de Android tienen restricciones que impiden que las aplicaciones ejecuten binarios SUID, lo que limita la capacidad de las aplicaciones para elevar privilegios. Y desde hace unos años montan la partición System con la bandera nosetuid, lo que deshabilita el uso del bit SUID. También tenemos el sistema de control de acceso obligatorio (MAC) SELinux (Security-Enhanced Linux) que impone políticas de seguridad en el sistema. Por lo que incluso obteniendo acceso root, el proceso seguirá estando bajo las políticas de seguridad definidas por SELinux.

    Por otro lado Zygote es un componente que inicia junto al arranque de Android. Realiza tareas de inicialización y carga recursos comunes que son compartidos por varias aplicaciones. Cuando se lanza una nueva aplicación, Zygote crea un nuevo proceso hijo a partir de sí mismo. Este proceso hijo hereda el estado inicializado de Zygote, lo que acelera el tiempo de inicio de la aplicación. Zygote evita tener que cargar e inicializar recursos comunes cada vez que arranca una nueva aplicación, mejorando el tiempo de inicio de las aplicaciones y optimizando el uso de recursos del sistema. Zygote ayuda a acelerar el inicio de aplicaciones, pero cada aplicación se ejecuta en su propio proceso independiente. Además los procesos creados a partir de Zygote inician su ejecución con un conjunto limitado de capacidades, lo que refuerza la seguridad limitando las acciones que pueden realizar.

    En las versiones más antiguas de Android existía un método para conseguir el root mediante instalaciones Over-The-Air (OTA). Este método necesita de un recovery personalizado como TWRP ya que el recovery oficial del móvil sólo permite instalar OTA firmadas por el fabricante. Por lo que también necesita tener desbloqueado el bootloader para poder instalar el recovery personalizado. El método para escalar privilegios con una instalación OTA consiste en modificar el sistema de archivos. El paquete suele constar de binarios para la arquitectura ARM y x86, scripts para instalar demonios y el binario “su”, además suele haber una .apk que administra los permisos para el resto de aplicaciones. Básicamente lo que ocurre es que se copia el binario “su” y los demonios correspondientes a la partición system, y se configuran los permisos y las etiquetas de seguridad SELinux para poder ejecutar la elevación de privilegios.

    En la actualidad, Android implementa otras medidas de seguridad además de las ya comentadas, para prevenir el acceso root no autorizado. Entre estas medidas están, la verificación de integridad del sistema (Verified Boot) que verifica que solo se cargue el firmware firmado digitalmente en el momento del arranque. Si detecta que una partición ha sido modificada, el sistema puede mostrar un mensaje de advertencia al usuario o simplemente rechazar el arranque, dependiendo de la implementación específica del fabricante. Otra de las características de seguridad que incorpora Android es montar particiones críticas como de solo lectura.

    Desde hace unos años también incluye SafetyNet API, una medida de seguridad que permite a las aplicaciones verificar la integridad del dispositivo, verificando el estado del bootloader, la existencia de permisos de root y la detección de indicadores de compromiso que podrían indicar que el dispositivo ha sido rooteado o modificado. Esta API es utilizada por aplicaciones sensibles a la seguridad, como servicios bancarios y de pago, para determinar si el dispositivo permanece en un estado seguro y es confiable.

    Con todas estás medidas de seguridad, las aplicaciones de rooteo tienen que conseguir el root sin modificar las particiones del sistema directamente. Lo consiguen utilizando técnicas de inyección en el proceso Zygote, de esta forma producen modificaciones en tiempo de ejecución sin cambiar permanentemente el sistema, aplicando cambios como el remonte de la partición del sistema en modo lectura y escritura (mount -o remount,exec,dev,suid,rw /partición) temporalmente para aplicar modificaciones necesarias. Con estas propiedades surge la técnica "Systemless root" con la que las modificaciones necesarias para obtener acceso root y realizar otras personalizaciones se aplican en el espacio de usuario en lugar de modificar directamente las particiones de solo lectura. Estas modificaciones pueden incluir la instalación de binarios y archivos necesarios para el acceso root, así como la aplicación de parches en tiempo de ejecución para eludir restricciones. El espacio de usuario es donde se ejecutan las aplicaciones y los procesos del usuario. Este espacio es independiente de las particiones del sistema y generalmente es de lectura y escritura. Actualmente las aplicaciones de rooteo ocultan el acceso root a las aplicaciones que hacen uso de SafetyNet.

    Existen otra forma de escalar privilegios aprovechando la explotación de vulnerabilidades, fallos o configuraciones inseguras en aplicaciones que se ejecutan como root en el propio sistema. Se puede hacer uso de vulnerabilidades del kernel Linux para conseguir el root, como hace la aplicación TowelRoot. Otras aplicaciones hacen uso de vulnerabilidades conocidas y no parcheadas en el dispositivo. El uso de zero-days es menos frecuente, pero puede ser usados con fines de infiltración y ganancia de privilegios.

    La ganancia de privilegios es algo delicado y debe estar auditada en el proceso de instalación. Los instaladores de fuentes desconocidas pueden contener malware que con el poder del root puede ser catastrófico. Puede contener rootkit que sean indetectable para las medidas de seguridad estándar que hemos citado anteriormente, permaneciendo oculto y parasitando el dispositivo móvil para fines nocivos. Por eso siempre debemos conocer quien es la fuente y saber que es lo que hace en nuestro sistema. Actualmente la aplicación más usada es Magisk y su sitio oficial en github es https://github.com/topjohnwu/Magisk.

    Magisk utiliza un enfoque Systemless root, por lo que las modificaciones del sistema las realiza en el espacio de usuario. Desde la versión 22 de Magisk, lanzada en febrero de 2021, el método de instalación consiste sólo en descargarse una única apk que es a su vez un paquete zip flasheable desde un recovery personalizado como TWRP.

    Se instala la aplicación Magiskapp y al abrirla comprueba si el móvil tiene el “ramdisk” en la partición de arranque (boot). El "ramdisk" (disco RAM) en la partición de arranque (boot partition) es una parte del sistema de archivos que se carga en la memoria RAM durante el proceso de arranque. Sus funciones son la inicialización del hardware, la carga de módulos de kernel, la configuración de parámetros del sistema, y la ejecución de scripts de inicio. Magisk se instala en la partición de arranque y modifica el ramdisk, específicamente el archivo init, que es el script de inicio del sistema. Magisk utiliza el ramdisk para implementar la ocultación del acceso root, y para realizar un bypass de SafetyNet, engañando a las verificaciones de seguridad para que ciertas aplicaciones no detecten el estado de root.