Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
wasm2c-tableflip — wasm2c 沙箱逃逸。一个不受信任的 WebAssembly 模块突破了生成的 C 沙箱,并在主机上执行任意 shell 命令。 | Kitploit
工具/GitHubGitHub/trustsig-eu/wasm2c-tableflip
漏洞分析漏洞利用安全虚拟化二进制利用
GitHubtrustsig-eu/wasm2c-tableflip

wasm2c-tableflip

wasm2c 沙箱逃逸。一个不受信任的 WebAssembly 模块突破了生成的 C 沙箱,并在主机上执行任意 shell 命令。

查看仓库
4141天前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

wasm2c 沙箱逃逸:访客模块在主机上运行 shell 命令

阅读博客:trustsig.eu/blog

wasm2c/wasm-rt-impl-tableops.inc 中的 wasm_rt_allocate_funcref_table() 会根据模块声明的元素数量设置 table->size,然后忽略 calloc() 的结果。当分配失败时,表会留下 data == NULL 以及完整的声明 size,因此所有边界检查仍会通过,而 table->data[i] 会变成绝对地址 i * sizeof(wasm_rt_funcref_t)。

元素数量来自访客,因此访客可以选择分配大小并强制分配失败。

复现

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

该镜像会从上游克隆 tag 1.0.41 的 wabt,构建 wat2wasm 和 wasm2c,编译访客模块和一个普通嵌入器,然后运行它。

预期输出:

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

最后一行是 /tmp/pwned.txt 的内容,该文件在沙箱模块运行之前并不存在。

已在 linux/arm64 和 linux/amd64 上验证。模块中没有任何与架构相关的部分:实例地址、GOT 槽位和 libc 偏移量都是在构建时根据刚刚构建的二进制文件以及该镜像的 libc 解析出来的。

不使用 Docker

在 Linux 上,安装了 clang、cmake、ninja 和 binutils 后:

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 不是此 PoC 支持的平台。Darwin 不强制执行 RLIMIT_AS,因此超大的 calloc 会成功,该 bug 永远不会触发;arm64 macOS 构建始终是位置无关的,而且 Mach-O 没有可用于泄露步骤的 ELF GOT。缺陷本身与平台无关;只有这条利用链是 Linux 特有的。

其他版本和命令:

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"

访客做了什么

  1. 声明 (table $t 2147483648 funcref)。68 GB 的 calloc 失败,data 为 NULL,size 保持 2147483648,表索引变成绝对地址。
  2. 在 got_slot/32 处的 table.get 通过损坏的表读取嵌入器的 GOT,table.set 将结果存入模块自身的全局变量中,wasm 代码可以将其作为整数读取。这会泄露 libc 的 malloc 地址,system 则根据目标 libc 中的固定距离得出。
  3. 在四个连续全局变量中构建一个 wasm_rt_funcref_t:func_type 指向调用点类型哈希的副本(func_types_eq_slowpath 使用 memcmp 进行比较,因此访客控制的字节能通过检查),func = , = 命令字符串,也保存在全局变量中。

模块中唯一硬编码的布局事实是模块实例的地址,由于它是全局变量,因此在非 PIE 嵌入器中是固定的。ASLR 保持启用;libc 地址在运行时泄露。

触发条件

表分配必须失败。PoC 使用 ulimit -v 1000000,这是运行不可信代码的主机通常会设置的地址空间限制。它在 32 位主机上也会失败,因为分配完全无法满足,在 vm.overcommit_memory=2 时或内存压力足够大时也会失败。

在默认 overcommit 启发式策略的标准 64 位 Linux 上,分配会成功且永远不会被触碰,这就是该 bug 能在正常测试中存活的原因。

受影响范围

所有随 wasm2c 表一起发布的版本。未检查的 calloc 可追溯到提交 ab9e0b55(#813)。已在发布的 1.0.41 和当前 main 上验证。

同一运行时中的内存分配器处理了这种情况:

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

表分配器需要同样的检查。

文件

  • Dockerfile 构建 wabt 并运行 PoC。
  • tableflip_poc.py 生成访客模块,构建嵌入器,使用 nm 和 readelf 从构建的二进制文件和目标 libc 中解析出三个常量,然后运行它。它生成的嵌入器不包含任何利用支持代码。
下载工具
system
module_instance
  • 在 globals_addr/32 处的 call_indirect。wasm2c 会生成 ((t)entry.func)(entry.module_instance, ...),因此这会调用 system(command)。