Structure GIF et palette indexée
Le format GIF (Graphics Interchange Format) utilise un modèle de couleur indexé : l'image ne stocke pas directement les valeurs RGB de chaque pixel, mais un indice pointant vers une entrée dans une table de couleurs (la palette globale ou locale).
Cette palette contient jusqu'à 256 triplets RGB, et les pixels de l'image contiennent simplement des indices 0-255. L'image visible dépend des couleurs référencées par ces indices — mais pas de leur ordre dans la table.
Structure d'un fichier GIF : ┌─────────────────────────────────────────┐ │ Header : "GIF89a" │ │ Logical Screen Descriptor │ │ Global Color Table (palette) : │ │ [0] = (255, 0, 0) ← rouge │ │ [1] = (0, 255, 0) ← vert │ │ [2] = (0, 0, 255) ← bleu │ │ [3] = (255, 255, 0) ← jaune │ │ ... jusqu'à [255] │ │ Image Data (pixels = indices) : │ │ [2, 0, 1, 0, 3, 2, ...] ← no RGB │ └─────────────────────────────────────────┘ Si on permute les entrées [0] et [1] dans la palette ET qu'on met à jour les indices en image (0→1, 1→0) : → L'image est visuellement IDENTIQUE → Mais la palette a changé → bits cachés !
Réordonnancement de palette
L'approche de base consiste à encoder un message dans la permutation de la palette. Une palette de n couleurs admet n! permutations possibles. Pour n=256 : 256! permutations — un nombre astronomique qui permettrait en théorie de cacher des quantités massives d'information.
En pratique, chaque permutation doit être accompagnée d'une mise à jour des indices image pour que l'image reste visuellement identique. La capacité pratique est limitée par la complexité du décodage de la permutation.
Capacité théorique par réordonnancement :
Palette 4 couleurs : 4! = 24 permutations → 4.5 bits
Palette 8 couleurs : 8! = 40 320 → 15.3 bits
Palette 256 couleurs : 256! ≈ 8.58 × 10^506 → théoriquement 1683 bits
Problème pratique :
→ Décoder la permutation nécessite un calcul de rang de permutation
→ O(n²) minimum — coûteux pour n=256
→ La plupart des implémentations n'utilisent que quelques bits
de la permutation pour des raisons de performanceTechnique EzSteg
EzSteg est l'implémentation la plus connue de stéganographie par palette GIF. Elle encode des bits dans les paires de couleurs de la palette : pour encoder un bit 0, on laisse les couleurs dans l'ordre "naturel" (la plus sombre en premier) ; pour un bit 1, on les permute.
Comme les indices image sont mis à jour simultanément, l'image reste visuellement identique. La technique est robuste aux outils d'édition qui ne réordonnent pas la palette, mais fragile face aux exportations GIF qui trient la palette automatiquement.
Grouper les couleurs de la palette en paires (couleur 0+1, 2+3, 4+5...)
Pour chaque paire : ordre "naturel" (ex: plus sombre en premier) → bit 0
Bit 1 → permuter les deux couleurs dans la palette + mettre à jour les indices
Résultat : image identique, bits encodés dans l'ordre des paires de palette
LSB dans les valeurs de palette
Une deuxième approche consiste à modifier directement les bits de poids faible des valeurs RGB dans la palette. Au lieu de modifier chaque pixel individuellement (comme LSB classique), on modifie les 256 entrées de la table de couleurs.
Cette méthode a une capacité très faible (256 × 3 bits × k = quelques centaines de bits max) mais présente l'avantage que les modifications sont concentrées dans la palette, pas dans les données image. Elle est détectable par examen direct de la palette.
LSB dans palette GIF (exemple 4 couleurs) :
Palette originale :
[0] R=255 G=0 B=0 → binaire R : 11111111
[1] R=0 G=255 B=0 → binaire G : 11111111
[2] R=0 G=0 B=255 → binaire B : 11111111
[3] R=128 G=128 B=128 → binaire R : 10000000
Message à cacher : "A" = 65 = 01000001
Modifier les LSB des valeurs RGB dans l'ordre :
[0].R : 11111110 (LSB → 0)
[0].G : 11111111 (LSB → 1)
[0].B : 11111110 (LSB → 0)
[1].R : 11111110 (LSB → 0)
...
Capacité : 256 entrées × 3 canaux × 1 bit = 768 bits max = 96 octetsLimites et détection
La stéganographie par palette a des vulnérabilités importantes. La principale est la fragilitité face aux logiciels d'édition d'images qui réorganisent systématiquement la palette lors de l'exportation (par exemple par fréquence d'utilisation des couleurs ou par luminosité).
Zéro modification visuelle
L'image est bit-perfect identique visuellement. Aucun artefact n'est introduit dans les données pixel.
Faible capacité OK pour CTF
Quelques dizaines d'octets suffisent pour des messages courts. Très utilisé dans les challenges CTF GIF.
Fragile aux exportations
Tout logiciel réordonnant la palette (Photoshop, GIMP, ImageMagick) détruit le message caché.
Capacité très limitée
Au maximum quelques centaines de bits. Pas adapté à des messages longs.
→ En CTF : examiner la palette GIF avec `identify -verbose image.gif` (ImageMagick) ou `ffmpeg -i image.gif`. La commande `python -c "from PIL import Image; img=Image.open('f.gif'); print(img.palette.data)"` révèle l'ordre exact de la palette.
Questions fréquentes
Pourquoi les GIF ont-ils une palette et qu'est-ce qu'on peut en faire ?
Le format GIF date de 1987 et ne supporte que 256 couleurs maximum. Au lieu de stocker la couleur de chaque pixel directement, il stocke une table de 256 couleurs (la palette) et des indices. L'ordre de cette table est invisible visuellement mais encodable numériquement : en permutant des entrées tout en mettant à jour les indices correspondants, l'image reste identique mais la palette contient un message.
Combien d'information peut-on réellement cacher dans une palette GIF ?
Très peu. La technique EzSteg donne environ 1 bit par paire de couleurs, soit 128 bits (16 octets) pour une palette de 256 couleurs. La méthode LSB sur les valeurs RGB de la palette donne au maximum 768 bits (96 octets). C'est suffisant pour un identifiant court ou un flag CTF, pas pour un message substantiel.
Cette technique est-elle encore pertinente aujourd'hui ?
Dans la pratique courante, non — le GIF est remplacé par PNG (24 bits) et WebP pour les images statiques. En revanche, la technique reste très présente dans les challenges CTF qui utilisent des GIF anciens, et dans les outils de stéganographie forensique. Elle est aussi utile pour comprendre les concepts de base d'encodage dans les métadonnées de format.
Comment analyser une palette GIF en CTF ?
Avec Python Pillow : `from PIL import Image; img = Image.open('f.gif'); print(list(img.palette.colors.keys()))`. Avec ImageMagick : `identify -verbose image.gif | grep -A 300 'Colors'`. L'ordre de sortie révèle la palette. Vous pouvez aussi comparer avec un GIF de référence si vous en avez un.
Pourquoi les logiciels d'édition détruisent-ils le message ?
Quand vous ouvrez un GIF dans Photoshop, GIMP ou ImageMagick et le re-sauvegardez, ces logiciels réordonnent automatiquement la palette (par fréquence d'utilisation des couleurs, par luminosité, ou alphabétiquement selon les valeurs RGB). L'ordre original — et donc le message — est perdu. C'est la principale fragilité de la technique.
Expérimenter
Essayez notre outil LSB interactif sur des images PNG — le même principe, appliqué directement aux pixels.