¿Cómo probar si un binario de Linux fue compilado como código independiente de la posición?

38

Hace poco aprendí que (al menos en Fedora y Red Hat Enterprise Linux), los programas ejecutables que se compilan como ejecutables independientes de posición (PIE) reciben una protección más fuerte de aleatorización del espacio de direcciones (ASLR).

Entonces: ¿Cómo pruebo si un ejecutable particular se compiló como un ejecutable independiente de posición en Linux?

DW
fuente
1
No estoy seguro acerca de 32 bits, pero en x86_64 el código es independiente de la posición por defecto . Y, por supuesto, todos los paquetes del sistema se compilan de esta manera en cualquier arco.
Michael Hampton
1
@MichaelHampton, no creo que sea correcto. (Tenga cuidado con la diferencia entre un binario ejecutable y una biblioteca compartida; su declaración puede ser correcta para las bibliotecas compartidas, pero no creo que sea correcta para los ejecutables). Incluso en x86_64, los binarios no parecen ser PIE por defecto. Acabo de escribir un pequeño programa de prueba, y en x86_64, no fue compilado como PIE. Creo que debe pasar los -pie -fpieindicadores especiales del compilador para compilar un programa como PIE. Sin embargo, ese enlace tenía otra información interesante, ¡gracias!
DW
1
Este tipo tiene un script bash para la detección: blog.fpmurphy.com/2008/06/position-independent-executables.html
CMCDragonkai

Respuestas:

32

Puede usar el perlscript contenido en el hardening-checkpaquete, disponible en Fedora y Debian (as hardening-includes). Lea esta página wiki de Debian para obtener detalles sobre qué marcas de compilación están marcadas. Es específico de Debian, pero la teoría también se aplica a Red Hat.

Ejemplo:

$ hardening-check $(which sshd)
/usr/sbin/sshd:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes
Dawud
fuente
Buena respuesta, también aplicable a Ubuntu 16.04 LTS y posiblemente a otras versiones de Ubuntu. sudo apt-get install hardening-includesy luego el hardening-checkscript perl ejecutable está disponible en el usual PATH( /usr/bin/hardening-check); solo un poco: Sugiera eliminar el ./de la respuesta ;-)
Dilettant
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae ya no está en 17.10 :-(
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
En CentOS / RedHat, este paquete está disponible en EPEL repositorio
vikas027
@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae Parece que ya no está disponible en Ubuntu 18.04
Vadim Kotov
2
El paquete debian que contiene esto ahora se llama devscripts.
Tamás Szelei
15

Solía readelf --relocsprobar si la biblioteca estática o dinámica es PIC en x86-64 de la siguiente manera:

$ readelf --relocs /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_32
R_X86_64_32S
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSLD
R_X86_64_TPOFF32

Vemos aquí R_X86_64_32y R_X86_64_32S. Esto significa que el código no es independiente de la posición. Cuando reconstruyo una biblioteca con -fPIC obtengo:

$ readelf --relocs libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSGD
R_X86_64_TLSLD

Este método probablemente funcione para ejecutables, pero no lo he usado de esa manera.

usuario2387
fuente
8
¿Te gustaría explicar cómo interpretar la salida de esa línea? ¿Cuál es el criterio a utilizar para clasificar la biblioteca compartida como PIC frente a no PIC?
DW
Si construyó un ejecutable con -fPIE -no-pie, siempre se cargaría en la misma dirección, aunque podría haber sido vinculado como un ejecutable PIE. Usar file a.outy buscar ELF executable(no PIE) frente a objeto compartido ELF '(PIE): ¿ direcciones absolutas de 32 bits ya no se permiten en Linux x86-64?
Peter Cordes
12

Simplemente use fileen el binario:

$ file ./pie-off
./pie-off: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0dc3858e9f0334060bfebcbe3e854909191d8bdc, not stripped
$ file ./pie-on
./pie-on: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=962235df5bd188e1ec48c151ff61b6435d395f89, not stripped

Tenga en cuenta el tipo diferente impreso después de la información LSB.

p5yx
fuente
1
¿Cómo se muestra esto si se compila con PIE / ASLR?
Baruch
3
La única diferencia entre las salidas de pie-off y pie.on son executabley shared object. Supongo que los objetos compartidos deben ser reubicables, por lo tanto, en mi opinión, se han compilado con PIE.
Richard Braganza
Sí, los ejecutables PIE son objetos compartidos ELF; La forma más fácil de implementar ASLR para ejecutables era usar el soporte existente en el vinculador dinámico para el punto de entrada ELF en un objeto compartido. ¿Ver también direcciones absolutas de 32 bits que ya no se permiten en Linux x86-64? para obtener más información sobre las opciones de gcc que controlan PIE, y que gcc -fPIE -pieahora es el valor predeterminado en muchas distribuciones.
Peter Cordes
Las versiones más recientes del archivo mencionan explícitamente el pie: por ejemplo, ELF 64-bit LSB pie ejecutable, x86-64, versión 1 (SYSV), vinculado dinámicamente, intérprete /lib64/ld-linux-x86-64.so.2, para GNU / Linux 3.2.0, BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96, despojado
Brian Minton
1
@PeterCordes nota que file5.36 ahora puede reconocer PIE-ness basado en la DT_1_PIEbandera de DT_FLAGS_1, y claramente dice en pie executablelugar de shared object.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
9

file 5.36 lo dice claramente

file5.36 realmente lo imprime claramente si el ejecutable es PIE o no. Por ejemplo, un ejecutable PIE se muestra como:

main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped

y no PIE como:

main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

La característica se introdujo en 5.33 pero solo hizo una simple chmod +xcomprobación. Antes de eso solo se imprimió shared objectpara PIE.

En 5.34, estaba destinado a comenzar a verificar los DF_1_PIEmetadatos ELF más especializados , pero debido a un error en la implementación, realmente rompió las cosas y mostró los ejecutables GCC PIE como shared objects.

He interpretado el filecódigo fuente, incluido el error, y exactamente qué bytes del formato ELF verifica con un detalle insoportable en: https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object -en lugar de un binario-ejecutable-de acuerdo a / 55704865 # 55704865

Un resumen rápido del comportamiento del archivo 5.36 es:

  • Si Elf32_Ehdr.e_type == ET_EXEC
    • impresión executable
  • si no si Elf32_Ehdr.e_type == ET_DYN
    • si DT_FLAGS_1la entrada de sección dinámica está presente
      • si DF_1_PIEse establece en DT_FLAGS_1:
        • impresión pie executable
      • más
        • impresión shared object
    • más
      • si el archivo es ejecutable por usuario, grupo u otros
        • impresión pie executable
      • más
        • impresión shared object

GDB ejecuta el ejecutable dos veces y ve ASLR

Una cosa muy directa que puede hacer es ejecutar el ejecutable dos veces a través de GDB y ver si la dirección cambia a través de ejecuciones debido a ASLR.

He explicado cómo hacerlo en detalle en: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031 # 51308031

Si bien esta no es necesariamente la solución más práctica y no es posible si no confía en el ejecutable, es divertido y hace la comprobación final que realmente nos importa, que es si el kernel / cargador dinámico de Linux cambia la ubicación del ejecutable o no.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
fuente
1
"dirección de los principales cambios entre ejecuciones": esto no es efecto de PIE puro, es PIE y ASLR habilitado. Sí, está habilitado en casi cualquier lugar, pero para máquinas con dirección ASLR deshabilitada será la misma en ambas ocasiones. ASLR puede habilitarse globalmente pero deshabilitarse con setarch -R man7.org/linux/man-pages/man8/setarch.8.html " -R, --addr-no-randomize Deshabilita la aleatorización del espacio de direcciones virtuales. Se activa " ADDR_NO_RANDOMIZE. man7.org/linux/man-pages/man2/personality.2.html " ADDR_NO_RANDOMIZE(desde Linux 2.6.12) Con este conjunto de indicadores, deshabilite la aleatorización del diseño del espacio de direcciones".
osgx
2

Hay bash script checksec.sh en Github para verificar las propiedades de mitigación de los ejecutables (incluidos RELRO, Stack Canary, NX bit, PIE, RPATH, RUNPATH, Fortify Source).

Ejecutar checkseccon -fargumentos (entrada de archivo):

$ checksec -f /usr/bin/bash

RELRO           STACK CANARY      NX            PIE             RPATH     RUNPATH      FORTIFY Fortified Fortifiable
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH    YES      13        33
Sourc7
fuente