Aller au contenu principal
own2pwn
C'est quoi un ELF, et pourquoi t'en croises partout

C'est quoi un ELF, et pourquoi t'en croises partout

Tour d'horizon du format ELF (Executable and Linkable Format) sous Linux x86_64 : compilation, identification d'un binaire avec file et strings, et premier apercu de la segmentation memoire.

Maxime J4 min de lecture

Un doute sur votre exposition ?

On audite votre surface d'attaque externe et on vous dit ce qui est exploitable.

Parler à un pentester

Prerequis

Hello ! o/

Je vais vous introduire le format ELF (Executable and Linkable Format) sous architecture Intel x86_64, qui est le format de fichier le plus populaire pour la conception d'un fichier executable sous systemes Unix-like.

Creation d'un Programme

Commençons par la base, c'est-a-dire comment vous, lecteur, pouvez concevoir un programme. Voici un exemple simple :

c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc > 1) {
        fprintf(stderr, "[!] Error: Usage: ./program\n");
        exit(EXIT_FAILURE);
    }
    fprintf(stdout, "Hello World !\n");
    return EXIT_SUCCESS;
}

Pour compiler et executer ce programme, vous pouvez utiliser les commandes suivantes :

bash
$ gcc source.c -o program
$ ./program
Hello World !
$ ./program ARG
[!] Error: Usage: ./program

Dans cet exemple, notre programme source est source.c et le programme executable est program. Lorsque nous utilisons la commande file, nous voyons que notre programme executable est bien de format ELF :

bash
$ file program
program: ELF 64-bit LSB pie executable, x86-64,
         version 1 (SYSV),
         dynamically linked,
         interpreter /lib64/ld-linux-x86-64.so.2,
         BuildID[sha1]=...,
         for GNU/Linux 3.2.0,
         not stripped

Cette sortie identifie le type ELF et l'ABI (Application Binary Interface) x86_64 de notre binaire compile.

Analyse du Programme Executable

Sans entrer dans les details, si nous executons strings sur program, voici un extrait de la sortie que nous obtenons :

text
/lib64/ld-linux-x86-64.so.2
libc.so.6
exit
stdout
stderr
fwrite
main
...

On remarque que certaines chaines de caracteres sont hardcodees (mises en brut) dans le programme executable. Parmi les motifs identifiables, nous avons :

  • libc.so.6
  • GCC: (Debian 8.3.0-6) 8.3.0
  • fwrite
  • main
  • exit
  • stderr

Ces elements nous donnent un apercu de ce qui est encapsule dans le programme executable, mais ne revelent pas beaucoup d'informations exploitables.

Pourquoi strings revele autant ?

Un binaire compile en dynamique embarque des symboles de debug et des references aux bibliotheques partagees qu'il utilise. Compiler avec -s (strip) reduit mais ne supprime pas totalement ces informations.

Segmentation de la Memoire

Un programme executable s'execute sur le CPU, et la memoire chargee peut se situer physiquement en cache, en RAM, sur le disque dur ou ailleurs. Le programme ne se charge pas dans un gros bloc d'adresses virtuelles ; il est divise en plusieurs segments dans la memoire.

memory-layout.txt
Disposition typique des segments d'un binaire ELF 64-bit en memoire virtuelle au moment de l'execution.

Veille sécurité

La suite, une fois par mois

Ce qui bouge vraiment sur la surface d'attaque externe, NIS2 et la sécurité applicative, écrit par le pentester qui signe ces articles. Un envoi par mois, désinscription en un clic.

Votre adresse ne sert qu'à cet envoi. Voir la politique de confidentialité.