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
wasm2c-tableflip — Évasion de sandbox wasm2c. Un module WebAssembly non fiable s'échappe de la sandbox C générée et exécute une commande shell arbitraire sur l'hôte. | Kitploit
Outils/GitHubGitHub/trustsig-eu/wasm2c-tableflip
Analyse des VulnérabilitésExploitationVirtualisation de SécuritéExploitation de Binaires
GitHubtrustsig-eu/wasm2c-tableflip

wasm2c-tableflip

Évasion de sandbox wasm2c. Un module WebAssembly non fiable s'échappe de la sandbox C générée et exécute une commande shell arbitraire sur l'hôte.

Voir le dépôt
533il y a 21 joursPas encore vérifié

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 →
Partager

Évasion de sandbox wasm2c : le module invité exécute une commande shell sur l'hôte

Lire le blog : trustsig.eu/blog

wasm_rt_allocate_funcref_table() dans wasm2c/wasm-rt-impl-tableops.inc définit table->size à partir du nombre d'éléments déclaré par le module, puis ignore le résultat de calloc(). Lorsque l'allocation échoue, la table reste avec data == NULL et la taille déclarée complète, donc tous les contrôles de bornes passent encore et table->data[i] devient l'adresse absolue i * sizeof(wasm_rt_funcref_t).

Le nombre d'éléments provient de l'invité, donc l'invité choisit la taille d'allocation et peut provoquer l'échec.

Reproduire

root@kitploit:~
git clone https://github.com/trustsig-eu/wasm2c-tableflip.git
cd wasm2c-tableflip
root@kitploit:~
docker build -t wabt-w2c-poc .
docker run --rm wabt-w2c-poc

L'image clone wabt au tag 1.0.41 depuis le dépôt amont, construit wat2wasm et wasm2c, compile le module invité et un embedder simple, puis l'exécute.

Sortie attendue :

root@kitploit:~
running guest
guest returned 0
--- file on host ---
goodbye sandbox

La dernière ligne est le contenu de /tmp/pwned.txt, un fichier qui n'existait pas avant que le module sandboxé ne s'exécute.

Vérifié sur linux/arm64 et linux/amd64. Rien dans le module n'est spécifique à une architecture : l'adresse de l'instance, l'emplacement GOT et le décalage de la libc sont tous résolus à la compilation à partir du binaire qui vient d'être construit et de la libc de cette image.

Sans Docker

Sur Linux, avec clang, cmake, ninja et binutils installés :

root@kitploit:~
git clone --depth 1 --branch 1.0.41 --recurse-submodules --shallow-submodules \
  https://github.com/WebAssembly/wabt ~/wabt
cmake -S ~/wabt -B ~/wabt/out -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DBUILD_TESTS=OFF -DBUILD_LIBWASM=OFF -DWITH_WASI=OFF
ninja -C ~/wabt/out wat2wasm wasm2c

python3 tableflip_poc.py --wabt-src ~/wabt --wat2wasm ~/wabt/out/wat2wasm \
  --wasm2c ~/wabt/out/wasm2c --run
cat /tmp/pwned.txt

macOS n'est pas une cible prise en charge pour ce PoC. Darwin n'applique pas RLIMIT_AS, donc le calloc surdimensionné réussit et le bug ne se déclenche jamais ; les builds arm64 de macOS sont toujours indépendants de la position, et Mach-O n'a pas de GOT ELF pour l'étape de fuite. Le défaut lui-même est indépendant de la plateforme ; seule cette chaîne d'exploitation est spécifique à Linux.

Autres versions et commandes :

root@kitploit:~
docker build --build-arg WABT_REF=main -t wabt-w2c-poc .
docker run --rm wabt-w2c-poc bash -c \
  "python3 tableflip_poc.py --run --command 'id > /tmp/pwned.txt' && cat /tmp/pwned.txt"

Ce que fait l'invité

  1. Déclare (table $t 2147483648 funcref). Le calloc de 68 Go échoue, data est NULL, size reste 2147483648, et les indices de table deviennent des adresses absolues.
  2. table.get à got_slot/32 lit le GOT de l'embedder à travers la table cassée et table.set stocke le résultat dans les propres globales du module, où le code wasm peut le lire comme un entier. Cela révèle l'adresse de malloc de la libc, et system s'en déduit à une distance fixe dans la libc cible.
  3. Construit une wasm_rt_funcref_t dans quatre globales consécutives : func_type pointant vers une copie du hash de type du site d'appel (func_types_eq_slowpath le compare avec memcmp, donc les octets contrôlés par l'invité passent le contrôle), func = system, et module_instance = la chaîne de commande, également conservée dans des globales.
  4. call_indirect à globals_addr/32. wasm2c émet ((t)entry.func)(entry.module_instance, ...), donc cela appelle system(command).

La seule donnée de disposition codée en dur dans le module est l'adresse de l'instance du module, qui est une globale et donc fixe dans un embedder non-PIE. L'ASLR reste activé ; l'adresse de la libc est révélée à l'exécution.

Condition de déclenchement

L'allocation de la table doit échouer. Le PoC utilise ulimit -v 1000000, une limite d'espace d'adressage du type de celle qu'un hôte exécutant du code non fiable définirait. Elle échoue aussi sur les hôtes 32 bits, où l'allocation ne peut pas du tout être satisfaite, avec vm.overcommit_memory=2, ou en cas de pression mémoire suffisante.

Sur un Linux 64 bits standard avec l'heuristique d'overcommit par défaut, l'allocation réussit et n'est jamais touchée, c'est pourquoi le bug survit aux tests normaux.

Versions concernées

Toutes les versions qui incluent les tables wasm2c. Le calloc non vérifié remonte au commit ab9e0b55 (#813). Vérifié contre la version publiée 1.0.41 et le main actuel.

L'allocateur mémoire du même runtime gère ce cas :

root@kitploit:~
  memory->data = (MEMORY_CELL_TYPE)calloc(byte_length, 1);
  if (byte_length != 0 && !memory->data) {
    abort();
  }

L'allocateur de tables a besoin de la même vérification.

Fichiers

  • Dockerfile construit wabt et exécute le PoC.
  • tableflip_poc.py génère le module invité, construit l'embedder, résout les trois constantes à partir du binaire construit et de la libc cible avec nm et readelf, puis l'exécute. L'embedder qu'il émet ne contient aucun code de support d'exploitation.
Télécharger l’outil