Redirection de pointeurs

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Pointeurs de chaînes

Si un appel de fonction va utiliser l’adresse d’une chaîne située dans la stack, il est possible d’abuser du buffer overflow pour écraser cette adresse et y placer l’adresse d’une autre chaîne présente dans le binaire.

Par exemple, si un appel à la fonction system va utiliser l’adresse d’une chaîne pour exécuter une commande, un attaquant pourrait placer l’adresse d’une chaîne différente sur la stack, export PATH=.:$PATH, et créer dans le répertoire courant un script portant le nom de la première lettre de la nouvelle chaîne, puisque ce script sera exécuté par le binaire.

Sur des cibles réelles, rediriger un pointeur de chaîne sur la stack est généralement plus intéressant que de simplement changer le texte affiché :

  • Rediriger un argument ultérieur de system/popen/execl* vers un "/bin/sh" existant ou une chaîne de commande contrôlée par l’attaquant déjà présente en mémoire.
  • Rediriger un sink de read ultérieur tel que puts("%s", ptr) ou write(fd, ptr, len) pour leak des données de la stack, du heap ou du binaire.
  • Rediriger un sink d’écriture ultérieur tel que strcpy(dst, ...), memcpy(dst, src, len), ou une affectation de champ de structure via ptr->field = value pour transformer le stack overflow en une écriture arbitraire en second stade.

Lors de l’audit, priorisez les locaux sur la stack tels que char *cmd, char *path, char *buf, FILE *fp, ou les pointeurs à l’intérieur de structures temporaires request/response qui sont utilisés après l’overflow mais avant le retour de la fonction. C’est particulièrement utile lorsque l’overflow ne peut pas atteindre en toute sécurité l’adresse de retour sauvegardée à cause d’un canary ou parce que corrompre un pointeur proche suffit.

Si la corruption se limite à un écrasement partiel (par exemple parce que le bug ajoute un 0x00), essayez de rediriger le pointeur vers :

  • Une chaîne proche dans le même stack frame
  • Un autre objet dans le même module / image non-PIE
  • Une région contrôlée dont les octets de poids fort restent inchangés

Pour le cas connexe orienté ASLR où un NUL terminal modifie un pointeur stack existant au lieu d’une variable locale dédiée, consultez Ret2ret & Reo2pop.

Vous pouvez trouver un exemple de ceci dans :

Pointeurs de fonction

Même principe que pour les pointeurs de chaîne mais appliqué aux fonctions : si la stack contient l’adresse d’une fonction qui sera appelée, il est possible de la modifier (par ex. pour appeler system).

Les cibles utiles ne sont pas seulement des variables callback explicites comme void (*fp)(). En pratique, recherchez :

  • Callbacks stockés dans des structs locaux passés plus tard à des fonctions auxiliaires
  • Destructors / cleanup handlers invoqués sur des chemins d’erreur
  • Parser dispatch tables ou state-machine handlers copiés sur la stack
  • Structs / objets locaux qui dispatchent ensuite via un appel indirect

Dans l’exploitation moderne, la redirection de pointeur est souvent le dernier primitive disponible avant d’atteindre le canary. Un writeup d’exploitation 2024 pour CVE-2024-20017 illustre le schéma typique : l’overflow atteint plusieurs variables locales avant le stack canary, l’attaquant corrompt un pointeur sur la stack ainsi que sa longueur/valeur associée, et une affectation ultérieure via ce pointeur devient une écriture arbitraire sans jamais avoir besoin de retourner via la frame corrompue.

Corruption de pointeur vers des primitives de second stade

Si un pointeur proche est ensuite déréférencé pour un store, l’objectif n’est généralement pas de sauter directement avec le premier overflow, mais d’améliorer la primitive :

  1. Déborder un buffer local et corrompre un pointeur ainsi que toute longueur / entier / index associée.
  2. Attendre que la fonction effectue une déréférence post-overflow telle que ptr->len = x, memcpy(ptr, src, n) ou *ptr = value.
  3. Utiliser cette write-what-where résultante pour écraser une entrée GOT, un callback, un pointeur de config, ou un autre site d’appel indirect.

C’est une bonne option lorsque :

  • Le bug s’arrête au canary
  • Le pointeur de fonction lui-même n’est pas directement accessible
  • Une écriture de 4 octets ou 8 octets de données est plus facile à obtenir qu’un détournement immédiat du contrôle d’exécution

La même idée fonctionne aussi pour des primitives de read si le pointeur corrompu est ensuite passé à des helpers de logging, d’affichage ou d’envoi réseau.

Note moderne AArch64 : PAC / BTI

Sur les cibles AArch64 actuelles, un classique écrasement de l’adresse de retour sauvegardée peut échouer parce que l’épilogue authentifie x30 avec PAC. Dans ces cas, les détournements non-retour comme les pointeurs de fonction locaux corrompus ou les pointeurs de callback deviennent plus attractifs.

Cependant, si BTI est activé, la cible d’appel indirect écrasée doit toujours atterrir sur un landing pad valide (typiquement une entrée de fonction avec bti c, ou dans du code activé PAC une prologue commençant par paciasp/pacibsp). Par conséquent, lorsque vous redirigez un pointeur de fonction sur la stack sur AArch64, privilégiez :

  • De véritables entrées de fonction plutôt que des gadgets au milieu d’une fonction
  • Des cibles dont le prologue satisfait déjà BTI
  • Des cibles où le pointeur d’appel indirect n’est pas en plus authentifié avant usage

Pour un contexte connexe de stack-overflow AArch64, consultez ret2win-arm64.

Vous pouvez trouver un exemple dans :

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks