El permiso de ejecución de Unix se puede omitir fácilmente. ¿Es superfluo, o cuál es la intención detrás de esto?

58

El permiso de lectura de Unix es en realidad el mismo que el permiso de ejecución, por lo que, por ejemplo, un proceso tiene acceso de escritura y también puede ejecutar el mismo archivo.

Esto se puede hacer con bastante facilidad: primero, este proceso debe cargar el contenido del archivo, que se ejecutará, en un búfer. Luego, llama a una función de una biblioteca compartida que analiza el ELF en el búfer y lo carga en las direcciones correctas (probablemente sobrescribiendo el proceso anterior como siempre, al llamar a execvp). El código salta al punto de entrada del nuevo programa y se está ejecutando.

Estoy bastante seguro de que Dennis Ritchie y Ken Thompson estaban al tanto de ese problema. Entonces, ¿por qué incluso inventaron este permiso, cuál es la intención detrás de él y cuál es su sentido, si no puede evitar que se ejecute cualquier proceso de cualquier usuario que tenga acceso de lectura? ¿Existe tal sentido o es superfluo?

¿Esto podría ser un problema de seguridad grave? ¿Hay algún sistema que dependa de la fuerza de los permisos rw o r--?

    
pregunta Martin Erhardt 02.09.2014 - 01:28
fuente

6 respuestas

80

Hay una forma aún más fácil de omitir el permiso de "ejecución": copie el programa en un directorio que posea y establezca el bit de "ejecución".

El permiso "ejecutar" no es una medida de seguridad. La seguridad se proporciona a un nivel inferior, con el sistema operativo restringiendo acciones específicas. Esto se hace porque, en muchos sistemas similares a Unix (especialmente en los días de Ritchie y Thompson), se supone que el usuario puede crear sus propios programas. En tal situación, el uso del permiso "ejecutar" como medida de seguridad no tiene sentido, ya que el usuario simplemente puede crear su propia copia de un programa sensible.

Como ejemplo concreto, ejecutar fdisk como usuario sin privilegios para intentar mezclar la tabla de particiones del disco duro:

$ /sbin/fdisk /dev/sda 

Welcome to fdisk (util-linux 2.24.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

...

Changed type of partition 'Linux' to 'Hidden NTFS WinRE'.

Command (m for help): w
fdisk: failed to write disklabel: Bad file descriptor

La última línea es fdisk que intenta obtener un descriptor de archivo "escrito" para el disco duro y falla, porque el usuario que lo estoy ejecutando no tiene permiso para hacerlo.

El propósito del permiso de "ejecución" es doble: 1) para indicar al sistema operativo qué archivos son programas, y 2) para decirle al usuario qué programas pueden ejecutar. Ambas son de carácter asesor y no obligatorio: puede crear un sistema operativo perfectamente funcional sin permiso, pero mejora la experiencia del usuario.

Como indica R .., hay un caso particular en el que el permiso "ejecutar" se usa por seguridad: cuando un programa también tiene establecido el bit "setuid". En este caso, el permiso de "ejecución" se puede usar para restringir quién tiene permiso para ejecutar el programa. Cualquier método para omitir el permiso de "ejecución" también eliminará el estado de "setuid", por lo que no existe ningún riesgo de seguridad aquí.

    
respondido por el Mark 02.09.2014 - 03:40
fuente
26

Puede establecer el bit de ejecución, pero no el bit de lectura, en un archivo ejecutable. De esa manera, nadie podrá copiar el archivo, pero la gente puede ejecutarlo de todos modos.

Esto no tiene ningún sentido hoy porque a) funciona solo para programas compilados, no con scripts (en la mayoría de los sistemas); b) en estos días, con el 90% de todos los Unixes siendo Linux, la gente puede copiar ejecutables desde casi cualquier lugar, yc) el espacio en disco que toma un ejecutable copiado no importa realmente.

Aun así, hubo usos para eso en los viejos tiempos.

  

El sistema Unix que usé en la escuela, hace 30 años, era muy limitado en RAM y espacio en disco. Especialmente, el sistema de archivos /usr/tmp era muy pequeño, lo que causó problemas cuando alguien intentó compilar un programa grande. Por supuesto, los estudiantes no debían escribir "programas grandes" de todos modos; Los programas grandes normalmente eran códigos fuente copiados de "algún lugar". Muchos de nosotros copiamos /usr/bin/cc a /home/<myname>/cc , y usamos dd para parchear el binario para usar /tmp en lugar de /usr/tmp , que era más grande. Por supuesto, esto solo empeoró el problema: el espacio en disco ocupado por estas copias era importante en esos días, y ahora /tmp se llenaba regularmente, impidiendo que otros usuarios incluso editaran sus archivos. Después de que descubrieron lo que sucedió, los administradores de sistemas hicieron un chmod go-r /bin/* /usr/bin/* que "solucionó" el problema y eliminaron todas nuestras copias del compilador de C

Otro uso es decirle al shell qué archivos se deben ejecutar y cuáles no. No quieres que se ejecute un archivo de texto aleatorio porque escribiste su nombre; El bit x proporciona una forma de evitar esto. (En estos días, el shell solo puede ver el inicio del archivo y ejecutarlo solo si comienza con #! , pero esto se introdujo mucho más tarde). La función de finalización de bash también sugerirá archivos con bits ejecutables solo cuando se escribe un comando.

    
respondido por el Guntram Blohm 02.09.2014 - 10:07
fuente
7

Hay una forma prefabricada de ejecutar un archivo arbitrario: pasarlo como un argumento al vinculador dinámico (que es el intérprete apropiado para un ejecutable cargado dinámicamente). P.ej. bajo Linux,

cp /bin/ls /tmp/
chmod -x /tmp/ls
/lib/ld-linux.so.2 /tmp/ls

Sin embargo, esto viene con la misma restricción que leer el archivo y saltar al código: los bits setuid no se evalúan.

En los viejos tiempos, a menudo teníamos binarios como /bin/su :

-rwsr-xr-- root wheel  ...  /bin/su

Solo los miembros del grupo wheel , que los administradores de sistemas mantuvieron recortados para las personas que saben que la contraseña root podrían incluso ejecutar el comando su , por lo que incluso si hubiera un desbordamiento de búfer en ese binario, permitiendo a los llamadores para eludir la seguridad, la vulnerabilidad solo podría ser utilizada por personas que conocen la contraseña de todos modos.

    
respondido por el Simon Richter 02.09.2014 - 17:46
fuente
5

Me sorprende que nadie más haya hecho referencia a otro uso de + x bit: directorios. Tal vez esté después de la ejecución de (ejemplo) algo en / bin (shell script o de otro tipo), pero hay más para ejecutar bits que archivos (por supuesto, un directorio ES un archivo pero es un tipo diferente de archivo).

Si tienes + x acceso en un directorio pero -r en ese mismo directorio, tendrás las siguientes capacidades:

  • Si conoce el nombre de un archivo (o directorio) en ese directorio, puede listarlo (por ejemplo, ls en él). Sin embargo, debes saber el nombre.
  • No puede cambiarlo (mediante el comando cd o la llamada del sistema chdir).

Sin embargo, si tienes -x y + r, puedes hacer lo siguiente:

  • No puede cambiar al directorio (de la misma manera que anteriormente).
  • Puedes listar los archivos. Pero como no tiene acceso + x al directorio, no puede acceder a los archivos en sí mismos.
  • Esto también significa que no puede actualizar (marca de tiempo solamente o de otra manera) y tampoco puede abrirlos en un editor de texto (o cat, o ...).

Si tiene + rx, puede hacer todo eso (excepto que necesita + w para escribir en el directorio en sí mismo, es decir, crear nuevos archivos; editar archivos funciona, eliminarlos no, la creación no lo hace)

Y sí, esto significa que es posible que algunas personas vean o editen archivos, pero solo si conocen la ruta exacta (siempre que tengan los derechos para editar). Y sí: ls es list y eso va para buscar directorios. Entonces, en resumen: la ejecución de un directorio lo está cambiando (por cualquier razón). Por supuesto, todos los bits son lo que realmente importa.

    
respondido por el user54909 03.09.2014 - 20:42
fuente
4

Si por alguna razón desea mantener el código binario en secreto, puede hacer que el programa sea ejecutable sin que sea legible. Esto no es útil si esos usuarios tienen acceso físico a la máquina. Tampoco es útil si el código fuente o binario está ampliamente disponible. Así que este es un caso de uso bastante limitado.

Si el programa tiene un bit setuid o setgid, el acceso de ejecución hace algo más que lo que se puede lograr al leer el binario. Un enfoque es crear un ejecutable setuid que solo sea ejecutable para un grupo específico. Si era legible en todo el mundo, las personas fuera de ese grupo aún no podían copiarlo y hacer uso del bit setgid en el archivo ejecutable original. (Aunque en la mayoría de los casos prefiero usar setgid en lugar de setuid, y luego usar el grupo en el directorio para controlar quién puede acceder al ejecutable).

Por lo general, el bit ejecutable se usa simplemente para indicar qué archivos son programas en primer lugar. De esa manera, la finalización puede funcionar mejor y no ejecutas ejecutables no deseados por accidente.

Si desea evitar que los usuarios copien un ejecutable y lo ejecuten, puede montar los directorios de inicio con noexec . Para que esto tenga sentido, debe usar noexec para cada sistema de archivos, donde el usuario pueda escribir cualquier cosa.

    
respondido por el kasperd 02.09.2014 - 14:40
fuente
2

El kernel verifica el permiso de ejecución de bits al ejecutar la llamada al sistema exec (2) (y primos). Solo lo necesitará para ejecutar programas en el nivel del kernel.

Solo los programas que tengan ese bit activado (lo que se está comprobando como propietario, grupo u otros es lo que se está verificando) pueden ser exec () ed por el núcleo.

Otra cosa diferente es lo que hace el shell al interpretar un script de shell o perl, o cualquier intérprete que pueda tener. En las secuencias de comandos, el kernel comprueba el #!... al principio del archivo como un número mágico, e inicia el shell indicado allí (también necesitará permiso de ejecución para el shell), y no necesita lee los permisos en ese script, ya que el shell tiene que abrirlo y leerlo para que sea interpretado. Para los scripts de shell necesitará permisos de lectura y permisos de ejecución. Pero para los scripts de shell, usted sólo necesita permiso de lectura, ya que siempre puede ejecutar un script de shell ejecutando el shell y pasando el script de shell como parámetro (o archivo de entrada). )

Por supuesto, como se ha señalado, el bit de ejecución puede evitarse copiando el programa y haciéndolo ejecutable, pero no podrá copiarlo si no tiene permisos de lectura para hacer esa copia. (sigues siendo capaz de ejecutarlo).

Intente cambiar (como raíz del curso) los permisos a ls (1) y hágalo 0111 ( ---x--x--x ) e intente hacer una copia ejecutable de este, y vea cómo no puede obtener su copia ejecutable, incluso cuando sigue pudiendo ejecutarla.

En los directorios, ejecutar bit significa algo diferente. El kernel usa el permiso ' x ' cuando recorre la ruta (en la función del kernel namei () ) por lo que si no tiene permisos de ejecución en un directorio, no puede usarlo, ni Los archivos accesibles a través de él. Incluso puede leer el contenido de un directorio con permisos de lectura, pero no puede acceder a los archivos que contiene. O al contrario, puede tener permisos de ejecución en un directorio pero no acceso de lectura, y podrá usar los archivos internos, pero no podrá ver el contenido del directorio.

    
respondido por el Luis Colorado 04.09.2014 - 14:07
fuente

Lea otras preguntas en las etiquetas