pwn2own 24过后,wasm子系统一直是v8漏洞挖掘的热点,这次出到wasm模块相关的内容,因此想着过来看一下,但是比赛的时候笔者有一个步骤卡住了,导致没构造出最后的逃逸原语,可惜可惜赛后与@Tplus@Qanux师傅交流了下,解决了自己卡住的地方,感谢两位师傅。编译参数是,默认开启沙箱题目下发的commit hash是42f5ff65d12f0ef9294fa7d3875feba938a81904提交比较新,所以nday bypass的概率很低,就直接分析patch文件看下文件上传逻辑,算一个hash,然后直接上传,文件大小<102400,应该是考虑到了wasm-module-builder.js的因素,所以这么大注意这里的启动参数加了一个这个--no-memory-protection-keys,其实是为了防止intel cpu的pkey内存保护,简单的说就是构造出AAR和AAW之后,写一些内存页的时候会crash,详细的内容见这个issue环境搭建一下,方便本地调试修改编译参数为如下接着autoninja -C out/x64.release d8 编译提取下patch内容主要patch的位置在WasmFullDecoder类里,这个类主要负责解析wasm函数体的内容,追下函数TypeCheckStackAgainstMerge_Slow,发现是一个slow path的函数,所以大概率还有fast path判断的逻辑找到了上层函数,想要进入这slow path的话需要让栈值数量与函数签名不匹配,或者是一些复杂的函数同时也需要注意到这个check是针对于merge point的检查,所以构造某些参数数量正常的函数的时候,需要采用特殊的branch那么这里就可以简单构建一个poc,下一个断点来测试一下是否能抵达这个位置其实是可以的当前的栈回溯(部分那我们的推测是没问题的,构造一个wasm stack的值数量与实际函数签名不符合的情况/或者是一个比较复杂的函数,可以进入到被patch的函数,接着来看patch掉了什么逻辑首先被patch掉的是对于wasm stack的值数量与实际函数签名不相等,意味着可以去传递多个参数,也就是说可以通过传递多个返回值的方法去泄漏wasm stack上的内容,泄漏出的值大概率是v8沙箱之外的,这个也可以算上是沙箱逃逸的第一步了下发会调用IsSubtypeOf对于stack_values进行类型检查,如果不符合则会报错,详细的实现位于v8/src/wasm/wasm-subtyping.cc:L421这里的意思是wasm子类型检查被删去,因此可以实现类似于这样的类型混淆i64→struct。wasm的设计文档其实有很多,这里只是举了一个简单的例子,因此不难想到一些类型混淆的思路,下方的extern可以理解为js中的对象,struct可以通过get和set方式进行取值,也就是类似于指针解引的过程其中AAR和AAW笔者比赛的时候犯了一个错误,在一个函数体中,直接将i64 cast为ref struct,然后直接解引用,这就造成了问题。当对于一个struct类型进行kExprStructSet或者kExprStructGet操作的时候,会去检查底层的heaptype,因此当直接传入一个i64的值,不进行先进行类型混淆,而是直接cast使用就会造成问题。本质上就是触发了struct.get/set的检查,也并不是对于patch的利用,铸币了而如果提前进行混淆,采用将i64转换成ref struct的方式,这会进入到这个函数产生如下的调用链,将原本的i64标记为ref struct,因此后续利用的时候可以将这个i64接引,造成沙箱逃逸这里用到上面提到的思路,当然下方也可以采用i64,这样也方便泄漏出cage_base,也可以通过泄漏indirectcall的函数ref,思路很多下方就是addressOf和fakeObj的原语,然后leak_cage_base的逻辑其实和addressOf是一致的,leak_cage_base主要是这里没有截断高32位,所以可以泄漏出沙箱的基地址通过上方的分析,其实我们可以通过参数不匹配的方式去泄漏wasm stack的值,所以这里可以尝试一下能泄漏出什么东西这里泄漏出了 raw pointer(64-bit C++ 栈地址),通过扫描这个栈区域,可以找到与上方分析的一致,这里需要将i64 → struct → i64,这样就可以实现沙箱逃逸,需要注意的是i64 → struct最好单独拆开,写成一个wasm函数供另外的wasm函数调用,代码如下。接着就可以对于泄漏出的栈地址进行扫描,经过测试,可以发现第一个泄露出来的地址位于jit code所在的段,后续计算也发现与trusted_data中的jump_table偏移固定,因此我们可以得到jump_table的具体地址,并修改为我们的shellcode,出于稳定性的考虑,可以在前面加上一个nop指令即可这里泄漏出来的值与栈偏移处的值并不相等,原因应该是当i64被cast成struct的时候,底层的heaptype等字段被修改,因此实际转换成struct进行取值的时候,会略微有偏差(通过以前阅读src/wasm/*的推测,这次并没有通过源码验证)ai搓一个就行(dcheck_always_on = false
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289115.htm
[原创] RCTF 2025 - no_check_WASM
133 浏览
1 回复
附件太大没办法直接上传,给一个下载链接:e81K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3x3h3I4&6P5i4W2Q4x3V1k6h3z5q4)9J5k6p5g2^5M7r3I4G2K9i4c8Q4x3X3c8o6L8$3I4D9k6h3y4@1K9h3!0F1i4K6u0r3j5X3I4G2j5W2)9J5c8X3#2S2K9h3&6Q4x3V1k6d9b7#2c8r3x3U0l9J5y4g2)9J5k6r3&6G2i4K6g2X3j5$3S2W2j5$3E0Q4y4h3k6%4j5i4y4E0i4K6u0r3L8X3!0Q4y4h3k6U0K9r3g2U0K9#2)9#2k6W2N6m8f1@1#2Q4y4h3k6#2L8Y4A6A6M7q4)9#2k6Y4m8S2M7%4y4%4L8%4u0V1i4K6g2X3K9i4y4Q4y4h3k6d9b7#2c8r3x3U0l9J5y4g2)9J5k6i4A6A6M7l9`.`.