Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/robertdfrench/ifuncd-up
Análisis de VulnerabilidadesAnálisis Dinámico de Código (DAST)ExplotaciónIngeniería InversaAnálisis de BinariosSeguridad de Cadena de SuministroPapers e InvestigaciónAprendizaje y Educación
GitHubrobertdfrench/ifuncd-up

ifuncd-up

GNU IFUNC es el verdadero culpable detrás de CVE-2024-3094

Ver Repositorio
601hace 3 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Sitio web

En respuesta a Hacker News

Veo que vosotros, bromistas de [el sitio naranja][hn], me estáis poniendo las cosas difíciles. Haré algunas respuestas escogidas a continuación, pero primero ofrezco un desafío: enviaré $500 de mi propio dinero a la primera persona que pueda demostrar este ataque sin ifunc. Estoy genuinamente interesado y dispuesto a pagar por la iluminación. Haz un fork de este repositorio y envía un PR con tu PoC funcional; te pediré tu dirección postal en privado si ganas. Ahora, las respuestas:

Esto es ladrar al árbol equivocado.

Chaval, yo vivo en el árbol equivocado, puedo ladrarle a quien quiera.

No era esencial para el exploit,

Tú no eres esencial para el exploit!

Siempre está selinux si queremos añadir protección contra código arbitrario que se ejecute como root.

Una vez cargado, este ataque no necesitaba cruzar más límites de syscall. Así que sí, podríamos haber restringido una sesión root "extra", pero igualmente habríamos tenido invitados no deseados en la máquina!

¿Qué es esto, el cumpleaños de Bilbo?? ¡¡Prohibida la entrada salvo asuntos de la fiesta!!

  1. IFUNC difícilmente es la única forma de ejecutar código antes de main.

Pero es una forma innecesaria de ejecutar código antes de que se configure la protección de memoria.

  1. La alternativa que presentan es posiblemente menos segura porque el puntero a función permanecerá escribible durante toda la vida del proceso,

¡Podemos improvisar con mprotect! Ve la última frase justo encima de la subsección Modificando LD_PRELOAD.

Sí, este blog está equivocado.

Disculpa, este blog estaba sin guía. Hice todas estas travesuras yo mismo! Nadie me engañó para ser tan estúpido.

IFUNC debería ser implementado por el propio software [cliente],

@CountWSS 💯 ¡claro que sí!

una serie de fallos de proceso flagrantes desde el mantenedor de Github hasta ...

Este es el único punto al que responderé seriamente:

Creo que es extraordinariamente injusto para el mantenedor de xz-utils y bastante peligroso para la comunidad pensar en esto como comenzando con un error de su parte. Comenzó con que a nadie le importaba un comino ayudar a mantener este proyecto. El atacante dependía de ifunc como una vulnerabilidad técnica y de nuestra negligencia colectiva hacia xz-utils como una vulnerabilidad social. Me parece vergonzoso ver las acciones del Sr. Collin como algo distinto a una heroica dedicación de años al servicio de la comunidad.

Además, Bruce Schneier está de acuerdo conmigo, así que... lo siento por ti, tu argumento está acabado.

El lenguaje puede haber sido más duro de lo necesario

No te vas a creer cuánto me hicieron mis amigos suavizar esto primero.

Las distribuciones Linux no deberían tener tan alta opinión de sí mismas como para esperar que OpenBSD se conforme y se adapte a su desorden

@debazel!!! Me gusta.

Qué sarta de mierda.

Vale, esa parte es exacta.

IFUNC'd up

Por qué deberías dejar de culpar a xz-utils por [CVE-2024-3094][nvd]. ¡También echa un vistazo a mi ETSA Talk!

Creo que la he liado con IFUNC

CVE-2024-3094, más conocido como "La puerta trasera de xz-utils", fue un casi desastre para la ciberseguridad global. Si este ataque no hubiera sido descubierto en el momento justo por [Andres Freund][freund], la mayoría de los servidores SSH de nuestro planeta habrían comenzado a otorgar acceso root al grupo responsable de este ataque.

Desafortunadamente, demasiado análisis se ha centrado en cómo el [código malicioso][JiaT75] llegó al repositorio de xz-utils. En cambio, me gustaría argumentar que dos decisiones de diseño de larga data en software de código abierto crítico son lo que hicieron posible este ataque: [enlazar OpenSSH contra SystemD][biebl], y la existencia de [GNU IFUNC][sourceware].

Antes de comenzar: Gran parte de esta discusión trata sobre las complejidades del enlazado dinámico en Linux. Si necesitas un repaso, consulta dynamic_linking.md.

Resumen rápido de CVE-2024-3094

Hay muchísimos buenos análisis que describen los detalles de alto nivel de la puerta trasera de xz-utils, como el artículo de Dan Goodin [Lo que sabemos sobre la puerta trasera de xz Utils que casi infectó al mundo][goodin1] y el gist de Sam James [Preguntas frecuentes sobre la puerta trasera de xz-utils (CVE-2024-3094)][thesamesam]. No necesitamos repetir todo eso aquí, así que para los propósitos de este artículo, aquí hay un resumen muy general:

  • Algunas distribuciones de Linux modifican OpenSSH para que dependa de SystemD
  • SystemD depende de xz-utils, que usa GNU IFUNC
  • Ergo, xz-utils termina en el espacio de direcciones de OpenSSH
  • Esto permite que ifunc modifique código en el servidor SSH```mermaid flowchart TD G["GNU IFUNC"] A["OpenSSH (OpenBSD)"] B["Portable OpenSSH
    (Linux / macOS / etc)"] C[OpenSSH + IFUNC] D[xz-utils] E["SystemD (Linux)"] A -->|Remove OpenBSD specifics| B B -->|Add SystemD specifics| C D --> E E --> C C --> F["Mayhem"] G --> D
root@kitploit:~
## ¿Por qué las distribuciones de Linux modifican OpenSSH?
La respuesta corta es que tienen que hacerlo. OpenSSH es desarrollado por la
comunidad de OpenBSD, para la comunidad de OpenBSD, y no les importa
Linux lo más mínimo.  El proyecto [Portable OpenSSH][mindrot] es una
recopilación de parches de mejor esfuerzo que reemplazan los componentes
específicos de OpenBSD por componentes POSIX genéricos, y algo de código
específico de cada plataforma cuando corresponde. La cadena de suministro de software para SSH acaba teniendo
un aspecto parecido a este en la práctica:```mermaid
flowchart TD
  subgraph OpenBSD Folks
    A[OpenBSD]
    B[OpenSSH]
    H[improvements]
  end
  B-->A
  A-->H
  H-->B

  B-->C
  C[Portable OpenSSH]

  subgraph Debian Folks
    D[Debian SSH]
    G[improvements]
  end
  C-->D
  D-->G
  G-->C

  subgraph Fedora Folks
    J[Fedora SSH]
    K[improvements]
  end
  C-->J
  J-->K
  K-->C

La versión de OpenSSH de OpenBSD es el origen upstream de todo lo demás, y la mayoría de las mejoras provienen de la propia comunidad de OpenBSD. Estos cambios fluyen río abajo hacia el proyecto Portable OpenSSH, que intenta reimplementar las nuevas funciones de maneras que no sean específicas de OpenBSD. Esto es lo que permite que SSH funcione en plataformas como Linux, macOS, FreeBSD e incluso Windows.

Pero no se detiene ahí. Algunos sistemas operativos aplican personalizaciones adicionales más allá de lo que ofrece Portable OpenSSH. Por ejemplo, Apple añade la opción [--apple-use-keychain][keith] a ssh-add para ayudarlo a integrarse con el administrador de contraseñas de macOS.

En el caso de CVE-2024-3094, Fedora y Debian mantuvieron sus propios [parches de SystemD][biebl] para sus forks de OpenSSH con el fin de corregir una [condición de carrera en torno a los reinicios de sshd][schmidt]. Así que la verdadera cadena de suministro de SSH empezó a verse así:```mermaid flowchart TD A[OpenSSH] B[Portable OpenSSH] C[Debian SSH] D[Fedora SSH] A-->B B-->C B-->D C<-->|SystemD Patches|D

root@kitploit:~
Estos parches nunca llegaron a Portable OpenSSH, porque los responsables
de Portable OpenSSH ["no estaban interesados en asumir una dependencia de
libsystemd"][djmdjm]. Y nunca llegaron al OpenSSH upstream, porque
OpenBSD no tiene ninguna necesidad de soportar SystemD.



### Preocupaciones sobre la "Separación de Preocupaciones"
Esto parece bastante inofensivo, pero es un ejemplo de un problema mucho mayor
en el código abierto, particularmente en Linux: componentes críticos del
sistema operativo son desarrollados por personas que no se conocen entre sí, y
no hablan entre sí. 

* ¿Sabían (o les importaba) quienes parchearon OpenSSH para SystemD que
  libsystemd depende de xz-utils?
* ¿Sabían (o les importaba) los de SystemD que xz-utils había empezado a usar
  ifunc?
* ¿Sabían (o les importaba) los de OpenSSH que ifunc era algo? Desde
  luego no es algo en OpenBSD.



En cierto sentido, esta ruptura de la comunicación es una característica del código
abierto: puedo adaptar tu trabajo a mis necesidades sin tener que molestarte
por ello. Pero también puede conducir a un grado de indirección que impide
que se mantengan supuestos críticos de diseño (como un proceso tradicional de enlace
dinámico).



El corolario obvio de la [Ley de Conway][conway] es que si estás
publicando tu organigrama, también estás publicando los bugs que viven en las
grietas de tu organigrama. Ninguna persona o equipo cometió realmente un error
aquí, pero en retrospectiva es claro que los atacantes
percibieron que la mano izquierda del SSH de Debian/Fedora no sabía lo que la
mano derecha de xz-utils estaba haciendo.



## ¿Qué se *supone* que hace GNU IFUNC?
Te permite determinar, en tiempo de ejecución, qué versión de alguna función
te gustaría usar. Lo hace dándote la oportunidad de ejecutar
**código arbitrario** para influir en cómo el enlazador resuelve los símbolos.

![](https://assets.kitploit.com/production/public/readmes/31477/ea52603b42c9b38ff0f8f693b09c5d5c0d107a4175f3be4e1e48b39c9ca3eb55.png)



### Detección de características de la CPU
Supongamos que tienes una aplicación que debe ejecutarse en una amplia variedad de CPUs
x86. Dependiendo de las características específicas de la CPU actual, puedes
preferir usar diferentes algoritmos para la misma tarea. La idea original
detrás de IFUNC era permitir que los programas comprobaran las características de la CPU la primera
vez que se llama a una función, y a partir de entonces usar una implementación que
será la más adecuada para esa CPU.

Echa un vistazo a [`cpu_demo.c`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/cpu_demo.c):```c
void print_cpu_info() __attribute__((ifunc ("resolve_cpu_info")));
void print_avx2() { printf("AVX2 is present.\n"); }
void print_nope() { printf("AVX2 is missing.\n"); }

static void* resolve_cpu_info(void) {
    __builtin_cpu_init();

	if (__builtin_cpu_supports("avx2")) {
		return print_avx2;
	} else {
		return print_nope;
	}
}

int main() {
	print_cpu_info();
	return 0;
}

Este programa muestra el uso más común de IFUNC: le pregunta a la CPU si soporta o no ciertas características, y proporciona una implementación diferente de una función dependiendo de las características que estén soportadas. En este caso, nuestra función print_cpu_info acabará imprimiendo "AVX2 is present" o "AVX2 is missing" dependiendo de lo antigua que sea tu CPU.

Sondear el entorno del proceso

Aunque IFUNC está pensado para sondear las capacidades de la CPU, nada te impide ejecutar código más complicado en tus resolutores. Por ejemplo, tty_demo.c muestra cómo puedes cargar una implementación de función diferente dependiendo de si STDOUT es un archivo o una terminal:```c // Print Green text to the Terminal void print_to_tty(const char *message) { const char *green_start = "\033[32m"; const char *color_reset = "\033[0m"; printf("%sTTY: %s%s\n", green_start, message, color_reset); }

// Print plain text to a file void print_to_file(const char *message) { printf("FILE: %s\n", message); }

void print_message(const char *message)
attribute((ifunc("resolve_print_function")));

void (*resolve_print_function(void))(const char *) { struct termios term;

root@kitploit:~
// Ask the kernel whether stdout is a file or a tty
int result = ioctl(STDOUT_FILENO, TCGETS, &term);
if (result == 0) {
    // stdout is a terminal
    return print_to_tty;
} else {
    // stdout is not a terminal
    return print_to_file;
}

}

int main() { print_message("Hello, World!"); return 0; }

root@kitploit:~
Este no es realmente el uso previsto de IFUNC, pero muestra lo que es
posible: puedes ejecutar código arbitrario antes de `main` en cualquier programa que
use un IFUNC que hayas declarado.





## IFUNC es probablemente una mala idea
![](https://assets.kitploit.com/production/public/readmes/31477/6d420d0d1b4f4c49a3ba8a4b2103d7f79d284c9d8fbda4449e6e6d0afa5b3cfa.png)

GNU IFUNC es difícil de implementar, difícil de usar correctamente y (como una
supuesta herramienta de rendimiento) no es mucho más rápido que las alternativas. Como hemos
visto con CVE-2024-3094, también es una herramienta muy poderosa para ataques
a la cadena de suministro de software.

IFUNC se usa ampliamente dentro de la GNU C Library, y eso está
probablemente bien. Esas son las personas para quienes se desarrolló
originalmente, y están estrechamente conectadas con los equipos de
compilador y enlazador que realmente implementan IFUNC. Están en la
mejor posición para entender las compensaciones, y hay muchísimas
funciones de libc que se benefician de implementaciones específicas
de CPU. Creo que deberíamos considerar IFUNC como una interfaz interna
para glibc, y evitar su uso en otras aplicaciones.



### Es demasiado confuso para usarse de forma segura
ifunc es demasiado difícil de usar. Hay demasiados [casos
límite][nagy], y la [documentación oficial][gnu-cfa] es
[escasa][sourceware]. Esto da a los usuarios la idea errónea de que
adoptar ifunc es sencillo.

Incluso varios años después de que ifunc estuviera disponible, la
interfaz anunciada [no funcionaba][agner]. Los desarrolladores de GCC
lo han llamado [un error][odonell] y han considerado añadir advertencias
para compensar la fragilidad de IFUNC:

> Las soluciones de glibc necesarias para hacer que IFUNC sea robusto no están en su lugar,
> y por lo tanto deberíamos hacer lo que podamos para advertir a los usuarios de que podría romperse.

Tampoco es solo IFUNC. Apple Mach-O tiene una característica similar llamada
`.symbol_resolver` que ["lamentan haber añadido"][rjmccall].



### Socava RELRO
Al permitir que se ejecute código arbitrario mientras la Global Offset Table
sigue siendo escribible, las protecciones que ofrece [RELRO](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/dynamic_linking.md#relro)
quedan [sin efecto][binarly-io]. 

Es importante señalarlo, porque RELRO se promociona como una forma de
proteger la integridad de los símbolos cargados dinámicamente. Desde la
perspectiva del usuario (tú, como usuario del compilador y del enlazador),
esto viola el [Principio de Menor Asombro][pola]: ninguna persona
razonable esperaría que *cargar una biblioteca dinámica* comprometa una
característica de seguridad diseñada para *proteger las bibliotecas dinámicas*.

![](https://assets.kitploit.com/production/public/readmes/31477/ad252f1cb2937e3f8b168ece1e3f15455dcb0d7647b8715dff7435f3babc0e1c.png)



### No siempre es necesario
Hay muchas otras formas de manejar esta situación. Cada una tiene
diferentes compensaciones, pero todas son mucho más simples que IFUNC.
Todas son más portables que IFUNC, más fáciles de entender y más
difíciles de explotar.

> "Ifunc es una forma absolutamente estúpida de hacer selección de código
> específico de microarquitectura en tiempo de ejecución."
>
> -- [Rich Felker](https://hachyderm.io/@dalias/112952237145378821),
> mantenedor de [musl](https://musl.libc.org).



#### Punteros a funciones globales
IFUNC es atractivo porque permite a los desarrolladores expresar la
selección de funciones *declarativamente* en lugar de *imperativamente*.
Pero hacer esto de forma imperativa no es realmente tan difícil.
Considera [`static_pointer.c`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/static_pointer.c), que resuelve un
puntero a función global en tiempo de ejecución:```c
static int (*triple)(int) = 0;
int triple_sse42(int n) { return 3 * n; }
int triple_plain(int n) { return n + n + n; }

void print_fifteen() {
	int fifteen = triple(5);
	printf("%d\n", fifteen);
}

int main() {
	__builtin_cpu_init();
	if (__builtin_cpu_supports("sse4.2")) {
		triple = triple_sse42;
	} else {
		triple = triple_plain;
	}
	
	print_fifteen();
	return 0;
}

¿Es realmente tan malo como para que necesitemos trucos especiales en el enlazador solo para evitarlo?

Una desventaja de este enfoque es que el puntero a función triple es escribible en tiempo de ejecución, mientras que IFUNC+RELRO aseguraría que las direcciones ifunc en la GOT son inmutables una vez resueltas. Sin embargo, con un poco de trabajo adicional, podríamos usar [mprotect(2)][mprotect] para marcar dichos punteros como de solo lectura.

Modificando LD_PRELOAD

Si sabes qué características de CPU necesita tu código, y tienes una copia separada de tu biblioteca dinámica para cada caso, entonces podrías lograr lo mismo especificando la biblioteca correcta con $LD_PRELOAD de la siguiente manera:```bash #!/bin/bash if (cat /proc/cpuinfo | grep flags | grep avx2 > /dev/null); then LD_PRELOAD=./myfunc_avx2.so ./my_app else LD_PRELOAD=./myfunc_normal.so ./my_app fi

root@kitploit:~
(Si no estás familiarizado con `LD_PRELOAD`, echa un vistazo al tutorial de catonmat ["Un sencillo tutorial de `LD_PRELOAD`"][catonmat].)



#### Binarios separados por combinación de características

¿Cuántas combinaciones únicas de características de CPU necesitas realmente soportar?
¿Cuántas existen siquiera?

En apariencia, esto parece una explosión combinatoria. Hay docenas de extensiones diferentes de aritmética vectorial, virtualización y seguridad para la ISA amd64. Pero estas características no se presentan de forma independiente en el mundo real. Por ejemplo, ninguna CPU que tenga AVX-512 carece de SSE4.2 o AES-NI.

Saber qué características de CPU necesita tu aplicación, y cuáles de ellas aparecen juntas en los chips reales, puede ayudarte a determinar cuántos binarios distintos tendrías que distribuir. Puede que no sean tantos como esperas. La mayoría de los gestores de paquetes permiten ejecutar scripts en el momento de la instalación; podrías distribuir varios binarios en un solo archivo rpm o deb y usar lógica de instalación para elegir el mejor para la CPU del sistema.



### No es mucho más rápido que las alternativas

> Lo que me ha resultado evidente durante mucho tiempo es que, incluso si
> ifunc tuviera una ventaja de rendimiento, solo podría darse cuando la
> llamada a la función completa es tan corta que la sobrecarga de la llamada
> puede ser una parte significativa del tiempo total.
>
> -- [Rich Felker](https://hachyderm.io/@dalias/113074264762553873),
> mantenedor de [musl](https://musl.libc.org).

Dado que la justificación habitual de ifunc está relacionada con el rendimiento, quería ver cuánta sobrecarga causa *el propio ifunc*. Después de todo, cualquier función que valga la pena optimizar probablemente se llame con frecuencia, por lo que merece la pena reconocer la sobrecarga de la invocación de la función.

Para averiguarlo, diseñé un experimento que llamara a una función *resuelta dinámicamente* una y otra vez en un bucle cerrado. Echa un vistazo a [`speed_demo/ifunc`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/ifunc/main.c) y a [`speed_demo/pointer`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/pointer/main.c). Ambos programas hacen el mismo trabajo (incrementar un contador estático), pero las funciones incrementadoras se resuelven de maneras diferentes: el primero utiliza GNU IFUNC, y el segundo se basa en los punteros a función de toda la vida.

Esta es la lógica general:

1. Llamar a una función resolutora para determinar qué incrementador usar.
1. Registrar esta respuesta en algún lugar (en el GOT, o como puntero a función).
1. Llamar a esta función incrementadora unos pocos miles de millones de veces para obtener una estimación de su costo.

Como control, también está [`speed_demo/fixed`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/fixed/main.c), que hace el mismo trabajo de incremento pero sin ninguna función resuelta dinámicamente. Esto puede usarse para ayudar a estimar qué parte del tiempo de ejecución se dedica a la invocación de funciones y qué parte es solo hacer sumas.

El objetivo `rigorous_speed_demo` del Makefile ejecuta varias veces cada uno de estos programas y produce algunas estadísticas simples sobre su rendimiento. Estas cifras cambiarán, por supuesto, según tu hardware, pero la prueba `fixed` debería servir como base de comparación.

| *Resultados* | BAJO | ALTO | PROM |
|-----------|------|------|-------|
| fixed     | 2.93 | 4.20 | 3.477 |
| ifunc     | 9.50 | 10.56| 9.986 |
| pointer   | 6.23 | 7.44 | 6.791 |

Lo que vemos aquí es que ifunc tiene una sobrecarga no insignificante en comparación con el uso de un puntero a función de toda la vida. En promedio, en mi hardware, tarda aproximadamente el doble en llamar a una función ifunc 2 mil millones de veces que en invocar un puntero a función 2 mil millones de veces.

¿Importa esto en la vida real? En absoluto. Las funciones que merecen ser optimizadas son mucho más costosas que las funciones "incrementar en uno" que estamos analizando aquí. Solo resulta interesante porque GNU IFUNC afirma ser una ventaja para el rendimiento, pero parece incurrir en más coste que los punteros a función.


#### Rendimiento de otras técnicas

Hay otras técnicas que son más lentas que ifunc. Echa un vistazo a `super_rigorous_speed_demo`, que pone en juego otros dos experimentos: [`speed_demo/upfront`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/upfront/main.c) y [`speed_demo/always`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/always/main.c).

`speed_demo/upfront` se comporta de manera similar a `speed_demo/pointer`, excepto que almacena los resultados de las comprobaciones de características de CPU en variables globales en lugar de llevar un puntero a función. Esto sigue requiriendo que una función «resolver» se ejecute primero para determinar qué implementación se utiliza, según el valor de estas variables globales. Esta técnica resulta ser más lenta que ifunc, pero también es más segura que almacenar punteros a función: mientras que los punteros a función pueden establecerse a valores arbitrarios, las banderas booleanas no. Así, un atacante que pueda modificar estas variables puede hacer que el programa sea *más lento*, pero no puede hacer que se comporte *de manera diferente*.

`speed_demo/always` está diseñado para ser la técnica más lenta: comprueba todas las características de CPU necesarias cada vez que se necesita una implementación y elige una sobre la marcha. Curiosamente, esta técnica no es significativamente más lenta que las demás. Solo es marginalmente más lenta que ifunc en el caso de que tengamos una sola característica de CPU que comprobar.

| PRUEBA   | BAJO | ALTO | PROM   |
|---------|------|-------|---------|
| fixed   | 5.02 | 5.70  | 5.37    |
| pointer | 6.40 | 7.02  | 6.66    |
| ifunc   | 8.56 | 11.11 | 9.64    |
| upfront | 9.24 | 9.41  | 9.33333 |
| always  | 10.07| 10.56 | 10.2333 |



## Conclusión

GNU IFUNC es una característica especializada de gcc/ld.so que pocas personas conocían antes de que se usara en CVE-2024-3094. Tiene escollos poco evidentes y documentación insuficiente. Al permitir que el enlazador ejecute código arbitrario antes de `main`, antes de que se hayan inicializado y protegido partes críticas de la imagen del proceso, socava una de las suposiciones más básicas de la programación: que el mero acto de cargar una biblioteca no *cambiará* inherentemente tu programa.

Los beneficios de rendimiento de IFUNC son reales, pero no significativamente mejores que las alternativas. La simplicidad de desplegar un único binario optimizado para múltiples CPUs es muy atractiva, pero puede lograrse con técnicas más simples (como punteros a función).

Creo que IFUNC debería estar deshabilitado por defecto en gcc. Habilitarlo debería requerir una opción de aspecto aterrador, como `--enable-cve-2024-3094`. Se debería esperar que cualquiera que lo use fuera de libc proporcione un argumento riguroso y bien investigado de que ninguna solución alternativa es apropiada.

![Sí, todas las bibliotecas compartidas](https://assets.kitploit.com/production/public/readmes/31477/039631e9f0441a38341d4f2299c0666f63a731c02cb2239257afd7613455461c.png)

<!-- REFERENCES -->
[aes-ni]: https://en.wikipedia.org/wiki/AES_instruction_set
[agner]: https://www.agner.org/optimize/blog/read.php?i=167
[biebl]: https://salsa.debian.org/ssh-team/openssh/-/commit/818791ef8edf087481bd49eb32335c8d7e1953d6
[binarly-io]: https://github.com/binarly-io/binary-risk-intelligence/tree/master/xz-backdoor
[catonmat]: https://catonmat.net/simple-ld-preload-tutorial
[conway]: https://en.wikipedia.org/wiki/Conway%27s_law
[djmdjm]: https://github.com/openssh/openssh-portable/pull/251#issuecomment-2027935208
[fr0gger]: https://infosec.exchange/@fr0gger/112189232773640259
[freund]: https://www.openwall.com/lists/oss-security/2024/03/29/4
[gnu-cfa]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-ifunc-function-attribute
[goodin1]: https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/
[hn]: https://news.ycombinator.com/item?id=48056749
[jasoncc]: https://jasoncc.github.io/gnu_gcc_glibc/gnu-ifunc.html#relocations-and-pic
[JiaT75]: https://github.com/tukaani-project/xz/commit/cf44e4b7f5dfdbf8c78aef377c10f71e274f63c0
[keith]: https://keith.github.io/xcode-man-pages/ssh-add.1.html#apple-use-keychain
[mindrot]: https://anongit.mindrot.org/openssh.git
[mprotect]: https://www.man7.org/linux/man-pages/man2/mprotect.2.html
[musl]: https://musl.libc.org
[nagy]: https://sourceware.org/legacy-ml/libc-alpha/2015-11/msg00108.html
[nvd]: https://nvd.nist.gov/vuln/detail/CVE-2024-3094
[odonell]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70082#c0
[OpenSSH9.8p1]: https://www.openssh.com/releasenotes.html#9.8p1
[openssh-unix-dev]: https://marc.info/?l=openssh-unix-dev&m=171288895109872&w=2
[pola]: https://en.wikipedia.org/wiki/Principle_of_least_astonishment
[rjmccall]: https://reviews.llvm.org/D139163#3993795
[schmidt]: https://bugzilla.redhat.com/show_bug.cgi?id=1381997#c4
[sourceware]: https://sourceware.org/glibc/wiki/GNU_IFUNC
[thesamesam]: https://gist.github.com/thesamesam/223949d5a074ebc3dce9ee78baad9e27#design
Descargar herramienta