古代猴子:击败 17 岁版本的 SpiderMonkey

  • 发现漏洞及背景:去年@swapgs和作者在流行的企业 VPN 解决方案Zscaler中发现一个有趣的漏洞。VPN 客户端使用pacparser库根据预配置的Proxy Auto-Configuration (PAC)文件决定哪些 HTTP 请求应被代理,该漏洞允许从字符串中逃逸并在 PAC 文件的上下文中执行任意 JavaScript。当时发现漏洞时未开发完整的利用程序,只是报告了该漏洞。
  • SpiderMonkey 漏洞

    • Bug 描述:在 Mozilla 错误跟踪器中找到适合的 SpiderMonkey 漏洞,如 398085 号 Bug,函数中大型 switch 语句存在问题,会导致字节码生成错误,使攻击者可让引擎执行任意字节码,存在安全隐患。当函数总字节码过长时,跳转会出错,可利用此 misaligned jump 执行任意字节码,但限于 3 字节,可通过巧妙选择IFEQIFNE来跳过不必要的字节码。
    • 内存损坏:任意字节码执行虽酷,但要做有意义的事需损坏内存,POP/POP2指令可用于此目的,它们会递减 VM 的堆栈指针且不检查是否下溢堆栈,通过链式POP2可使堆栈指针指向&fp->argv,然后可使用GETARGSETARG指令读取和写入fp->argv,但会导致堆栈帧损坏使 VM 崩溃,作者改为调用回调函数。
    • 构建addrof原语:在该 SpiderMonkey 版本中,JavaScript 值有多种类型且有类型特定掩码,可通过将指针写入未移除标签的双指针来实现addrof原语,在 JavaScript 世界中读取双精度数并手动转换为字节表示可获取原始指针。
    • 泄露有趣信息:通过读取函数指针可泄露二进制在内存中的基地址,利用addrof原语可读取全局偏移表 (GOT) 条目获取libc基地址,进而获取system()函数地址。
    • 获取 Shell:可通过覆盖和调用函数指针来劫持控制流,JS对象的ops指针是好的候选,但要注意调用参数,幸运的是二进制运行时的上下文对象存储在.bss部分,可通过泄露对象地址并写入控制ops函数的第一个参数来获取 Shell,例如将getProperty()函数指针覆盖为system()并写入"sh\x00"
  • 最终利用程序:提供了exploit.pyexploit.js文件,exploit.py用于设置相关地址和读取漏洞利用脚本exploit.jsexploit.js中定义了一系列用于处理 IEEE-754 浮点数和字节操作的函数,通过一系列函数调用和字节码操作来实现泄露地址、获取libc地址和获取 Shell 的功能。整个利用过程花费约一周时间,作者认为如果重新创建挑战应提供漏洞票作为提示,使挑战更易接近。
阅读 10
0 条评论