GHOST系统之家 - Windows系统光盘下载网站!
当前位置:GHOST系统之家>电脑问题 > 深入考察解释型语言背后隐藏的攻击面,Part 2(四)

深入考察解释型语言背后隐藏的攻击面,Part 2(四)

来源:Ghost系统之家浏览:时间:2023-02-19 20:29:51

在本文中,我们将深入地探讨,在通过外部函数接口(ForeignFunctionInterface,FFI)将基于C/C++的库“粘合”到解释语言的过程中,安全漏洞是如何产生的。

接上文:

  • 《深入考察解释型语言背后隐藏的攻击面,Part 1(上)》
  • 《深入考察解释型语言背后隐藏的攻击面,Part 1(下)》
  • 《深入考察解释型语言背后隐藏的攻击面,Part 2(一)》
  • 《深入考察解释型语言背后隐藏的攻击面,Part 2(二)》
  • 《深入考察解释型语言背后隐藏的攻击面,Part 2(三)》

战略规划

我们知道,虽然已经可以完全控制linkmap,但我们仍无法控制通过硬编码PLT参数传递给解析器代码的reloc_arg参数,在我们的示例中,png_error的参数为0x11d(285)。这个值的作用,是用作png-img模块的重定位段(.rela.plt)的索引。

除此之外,我们也不知道被破坏的linkmap在内存中的位置。同时,由于堆的基地址是随机的,所以,我们唯一已知的数据都是拜测试平台上node二进制文件的非PIE特性所赐。因此,我们仍然无法在内存中的已知位置处伪造相应的段,以便与我们精心制作的linkmap一起使用。

尽管如此,我们现在已经到了有趣的部分:制定战略,考虑如何将我们的堆内存控制与我们对解析器和目标二进制的了解结合起来,重定向执行流程。

我们的既定目标是通过加载带有png-img的恶意PNG来执行任意命令。

针对任意命令执行的头脑风暴

我们回忆一下,png_ptr分块与linkmap分块是相邻的。并且,linkmap的第一个字段是l_addr字段,这个字段应该就是库的基地址,各种重定位和函数偏移都是以它为基础的。

我们可以覆盖堆数据,粒度为rowbytes,简单来说就是我们PNG图片的宽度。libpng接受的最小的rowbytes值与用于溢出的高度值结合起来就是3,也就是说,我们可以采取的最小的堆覆盖步骤是每行迭代3个字节。在littleendian平台上,我们可以覆盖linkmap的l_addr字段中最低有效字节,以使png_error解析在其预期的函数起始地址之外,而不会破坏linkmap中的任何其他指针。然而,这使得我们无法在调用错误对齐的png_error时控制png_ptr参数,因为控制这些数据需要覆盖一个完整的linkmap。事实证明,在png_error附近没有足够多的有用指令来控制进程。由于ASLR的原因,我们无法对l_addr进行更激进的局部覆盖,因为我们很快就会碰到库基地址的熵区域,而且我们只有一次尝试机会。

所以,我们需要重新规划一下。

理想情况下,我们设计一个场景,其中我们可以为png_error重定位索引285提供任意重定位记录。这样的话,我们就能够完全控制(伪造的)符号表的索引。

我们可以将node的GOT段(其中包含许多已经解析好的libc指针)用作一个伪造的符号表,这样我们精心制作的重定位记录就能以获取一个现有libc地址作为符号的sym->st_value的方式来索引nodeGOT。然后,我们可以借助对l->l_addr的控制能力,从这个现有的libc地址进行偏移,并将执行重定向到我们希望的任何其他libc的.text段地址。

由于我们可以在解析png_error时控制加载到rdi寄存器中的png_ptr数据(即,根据Linux 64bit intel平台上使用的SystemVAMD64 ABI的第一个参数),我们可以设法解析为system(3),并从我们控制之下的png_ptr数据中提供一个任意的命令来执行。

由于最终修复的重定位偏移量也处于我们精心制作的重定位记录的控制之下,所以,我们可以简单地将l->l_addr值加到它上面,并将其指向某个安全的内存位置,以便在控制进程之前,在重定位修复中幸存下来。

这将是一个理想的方案。不过,当前面临的挑战是:在已知位置没有受控数据,也无法控制reloc_arg的情况下,我们如何提供任意的重定位记录?

曙光乍现

面对上面所说的挑战,一个重要的线索是,l_info[DT_JMPREL]是通过对指向.dynamic段的指针以解除引用的方式获得的。前面说过,解析器并不直接引用它需要访问的各个段,而是获取指向所需节的.dynamic条目的指针,然后查询其d_ptr字段以获得指向相关段的实际指针。

更直白地说,解析器将使用我们的受控指针来获取l_info[DT_JMPREL],并在该指针的偏移量8处,获取另一个指针值,这个指针值应该就是实际的段地址。

这对我们有什么帮助呢?

好吧,我们说过:我们可以把data_分块放到堆上的任意位置,但我们无法可靠地把它挤在linkmap和png_ptr分块之间。但是,如果我们把它放在linkmap分块前面的某个地方会怎样呢?这将导致覆盖大量的堆空间,从而控制这些堆空间中的内容。

在利用漏洞的时候,我们与堆的交互是非常有限的,因为没有很多的分配或释放操作发生。实际上,我们只是在一个循环中,简单地将我们控制的数据行写入堆中,直到用完行数据,这时,png_error的解析逻辑就启动了。

所以,至少在我们的PoC场景中,我们可以有效地覆盖相当一部分堆内存,直到达到我们需要控制的数量为止,这不会带来太多的稳定性问题。

我们还知道,我们处理的是一个非PIE二进制文件。所以,我们知道它的.data段的具体地址。在node的.data段中,会含有大量的结构体,这些结构体在运行时可能含有指向堆内存的指针。如果我们覆盖了堆中足够多的内存空间,其中一些指针就可能指向我们控制的数据,准确来说,这些指针将位于.data段的静态位置。

那么,如果我们重新调整其中一个.data位置的用途,将其用于我们的l_info[DT_JMPREL]的.dynamic条目指针,结果会如何呢?我们也许可以用它来为_dl_fixup提供一个完全受控的重定位记录。由于在我们的目标平台上,重定位记录的大小是24(3x8字节),而png_errorreloc_arg的大小是285,只要我们可以将正确对齐的重定位记录放置在距获取堆指针的node.data的285x24偏移处,我们就应该能够破坏解析器的逻辑。

随后,我们可以使用类似的方法找到一个静态位置,在+8处包含一个指向node二进制代码GOT的指针,并将其用作l_info[DT_SYMTAB].dynamic条目指针。在与制作好的重定位记录一致的情况下,我们可以索引到节点GOT中,从而获得一个现有的libc指针值,并使用我们制作好的linkmap的l_addr字段作为到一个所需的libc函数的增量,在我们的例子中,这个函数就是system(3)。

深入考察解释型语言背后隐藏的攻击面,Part2(四)

综合起来

现在,我们已经有了一个初步的漏洞利用策略,我们就必须收集所有的要素,来将我们的攻击计划付诸实施。

从漏洞利用的可靠性的角度来看,我们当前策略的缺点是它高度依赖二进制代码,并且对堆布局高度敏感。因此,我们认为这充其量只能算是一个PoC。因为它高度依赖于越来越少见的非PIEnode的二进制代码,以及从data_chunks到linkmap和png_ptr chunks的可预测堆偏移。

话虽如此,我们拿它在启用了各种防御功能的系统上来练练手,还是非常不错的。

为了把我们的策略付诸实施,我们需要:

  • 能把溢出分块放到linkmap分块的前面data_分块的合适大小。
  • data_ 分块和linkmap分块之间的偏移量。
  • 从node二进制代码GOT到偏移量的合适的libc指针。
  • 一个已知的node指针,指向一个指向node GOT基址的指针。
  • 一个已知的node指针,指向一个指向受控堆内存的指针。
  • 从源libc指针到目标libc函数指针的偏移量。
  • 一个用于接收最终的_dl_fixup重定位写入的安全的内存区域。

首先,让我们找到一个合适的空闲块,以便在调用PngImg::PngImg构造函数时,可以将data_分块保存到这个空闲块中。我们可以使用gef的heapbins命令来显示哪些bins有可用的空闲分块,以及它们在内存中的位置。

我们要寻找的是一个与linkmap分块的位置离得较远的分块,这样我们就有很好的机会通过node的.data的堆指针从堆中提供可控的重定位记录。但是,我们也不想因为担心不稳定而破坏整个堆的内容。

我们可以在unsorted的bin中找到一个看似合适的大小为0x2010的空闲块:

通过将data_size设置为0x2010,我们可以将这个空闲块塞进这个位于偏移量0x3950处的分块中,这个分块最终将成为我们的linkmap分块。当然,这个假设在任何现实情形下都是非常不稳定的,但在我们的练习中,不妨假设它是成立的。

同时,我们让rowbytes(宽度)取值为16,以便为堆溢出提供一个已经对齐的、细粒度的写入原语。

我们注意到,由于符号表项长24个字节,而St_value字段在Symbol结构体中的偏移量为8,所以,我们从node二进制GOT中选择的libc指针(用作St_value),必须位于距24字节对齐索引的偏移量8处。例如,一个指定Symtab索引为1的重定位记录,将意味着在nodeGOT的偏移量32处取值,并将其作为Symbol的st_value。

我们还注意到,伪造的符号条目的st_other字段决定了我们是否在_dl_fixup中根据符号的可见性来进入更复杂的符号查找路径。因为我们喜欢尽可能地保持简单,所以,对于在我们的st_value字段之前的GOT条目,应该设法不让它通过_dl_fixup中的if(__builtin_expect(ELFW(ST_VISIBILITY) (sym->st_other), 0)==0)的检查。这实际上只是意味着伪造的符号表条目中st_other字段(字节6)的低2位不应该是0。当然,这需要一定的运气,但大多数GOT段中都存在符合这一要求的指针。另外,可见性检查是使用以下宏完成的:

在我们的测试平台上,getockopt的node二进制GOT条目很符合我们的要求:它的前面有一个指针值,这个指针值会通过ST_VISIBILITY检查,这样我们就不必在linkmap中使用更复杂的解析器逻辑。所以,我们将使用getockopt来偏移到所需的系统libc目标。这两个libc偏移量之间的差值将是我们在linkmapsl_addr字段中设置的delta值。

接下来,让我们首先从node二进制代码中收集我们需要的所有地址信息。

接下来,我们必须在node的.data段中寻找这样一个堆指针,它指向位于我们控制的偏移量285x24处的数据。通过一个小型的GDB脚本,我们就可以很快找到符合要求的候选者。我们的脚本将搜索node的.data段,以寻找位于我们控制的数据区域内或其附近的堆指针。

注意:在启用ASLR后,这些堆地址将在每次运行时发生变化,所以这个脚本示例只与我们的调试会话快照相关。然而,当实际运行漏洞利用代码时,考虑到面对的是非PIE型的node二进制代码,所以,我们可以预期得到一个一致的.data指针位置,并期望该位置将包含用于实际运行上下文的可用堆指针。

所以我们找到了一个潜在可用的.data位置(0x265b9e0),该位置将包含一个位于偏移量285x24处的堆指针,该指针将指向受控数据。

最后,我们必须在node二进制代码中找到这样一个位置:它在+8处包含一个指向node的.got段的指针。这并非难事,因为node二进制代码肯定会引用各个二进制段。

现在,我们已经收集好了所有的素材,这样就可以编写PoC代码了。总结一下,我们将构建一个伪造的linkmap,它符合以下约束条件:

  • l_addr字段将是libc的getockopt偏移量和libc的系统偏移量之间的增量。
  • l_info[DT_STRTAB]条目将是一些有效的指针值,因为我们的目的是跳过基于字符串的符号查找,它只需要能够安全地解除引用即可。
  • l_info[DT_SYMTAB]条目将是一个指向某个位置的指针,该位置在+8处有一个指向node的.got段起始地址的指针。
  • l_info[DT_JMPREL]条目将是指向某个位置的指针,该位置在+8处包含一个堆指针,该指针基于png_error解析的reloc_arg值指向偏移量285x 24处的受控伪造重定位记录。

伪造的重定位记录将为伪造的符号表(node的二进制代码的.got段)提供一个索引,这样符号的st_value字段就是之前解析的指向getockopt的libc指针。它还将提供一个重定位偏移量(它是相对于safe-to-write内存区域的),这样我们的成果就可以在_dl_fixup中的最后一次重定位写入操作后幸存下来。

解析器将把我们在linkmap的l_addr字段中设置的libc增量与伪造的符号的st_value字段相加,其中st_value字段存放的是解析的getsockoptlibc函数指针值。相加之后,得到的就是system(3)函数的libc地址。

由于我们还破坏了png_error的png_ptr参数,因此,当我们最终从为png_error劫持的_dl_resolve跳转到system(3)时,我们能够提供并执行任意命令。对于我们的PoC来说,我们将执行“touch/tmp/itworked”命令。

用我们的PoC脚本准备好触发漏洞的PNG文件后,就可以将其移动到我们的调试环境中了:

我们先在调试器里面运行易受攻击的node程序,并将断点设置在system(3)上:

太棒了!看起来代码在调试阶段一切正常。现在,让我们在没有附加调试器的情况下运行一下。

尽管node进程确实因为堆损坏而发生了崩溃,但是,这一切都发生在实现任意命令执行之后。

无论如何,我们的任务已经完成了。

我们的PoC开发任务现在已经大功告成:我们已经为利用png-imgFFI漏洞成功打通了所有环节。虽然从攻击者的角度来看,可靠性仍然是现实利用过程中的一个令人担忧的问题,但这足以让我们证明该漏洞的潜在影响。

读者可以在附录A中找到完整的exploit代码。

小结

在本系列文章中,我们以Node.jsFFI漏洞的利用过程为例,为读者深入介绍了隐藏在解释型语言底层攻击面。当然,我们的最终目标是为大家演示内存安全漏洞是如何通过基于FFI的攻击面潜入解释型语言应用程序的。同时,我们为读者介绍了exploit的开发之旅,并演示了攻击者是如何评估代码中的bug的潜在利用价值的。

附录A: png-img PoC exploit

本文翻译自:https://securitylab.github.com/research/now-you-c-me-part-two

鸿蒙官方战略合作共建——HarmonyOS技术社区

推荐系统

  • 微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载

    微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载

    语言:中文版系统大小:5.13GB系统类型:Win11

    微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Win11 64位 Office办公版(免费)优化  1、保留 Edge浏览器。  2、隐藏“操作中心”托盘图标。  3、保留常用组件(微软商店,计算器,图片查看器等)。  5、关闭天气资讯。 

  • Win11 21H2 官方正式版下载_Win11 21H2最新系统免激活下载

    Win11 21H2 官方正式版下载_Win11 21H2最新系统免激活下载

    语言:中文版系统大小:4.75GB系统类型:Win11

    Ghost Win11 21H2是微软在系统方面技术积累雄厚深耕多年,Ghost Win11 21H2系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Ghost Win11 21H2是微软最新发布的KB5019961补丁升级而来的最新版的21H2系统,以Windows 11 21H2 22000 1219 专业版为基础进行优化,保持原汁原味,系统流畅稳定,保留常用组件

  • windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载

    windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载

    语言:中文版系统大小:5.31GB系统类型:Win11

    windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载,微软win11发布快大半年了,其中做了很多次补丁和修复一些BUG,比之前的版本有一些功能上的调整,目前已经升级到最新版本的镜像系统,并且优化了自动激活,永久使用。windows11中文版镜像国内镜像下载地址微软windows11正式版镜像 介绍:1、对函数算法进行了一定程度的简化和优化

  • 微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载

    微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载

    语言:中文版系统大小:5.31GB系统类型:Win11

    微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载,微软2022年正式推出了win11系统,很多人迫不及待的要体验,本站提供了最新版的微软Windows11正式版系统下载,微软windows11正式版镜像 是一款功能超级强大的装机系统,是微软方面全新推出的装机系统,这款系统可以通过pe直接的完成安装,对此系统感兴趣,想要使用的用户们就快来下载

  • 微软windows11系统下载 微软原版 Ghost win11 X64 正式版ISO镜像文件

    微软windows11系统下载 微软原版 Ghost win11 X64 正式版ISO镜像文件

    语言:中文版系统大小:0MB系统类型:Win11

    微软Ghost win11 正式版镜像文件是一款由微软方面推出的优秀全新装机系统,这款系统的新功能非常多,用户们能够在这里体验到最富有人性化的设计等,且全新的柔软界面,看起来非常的舒服~微软Ghost win11 正式版镜像文件介绍:1、与各种硬件设备兼容。 更好地完成用户安装并有效地使用。2、稳定使用蓝屏,系统不再兼容,更能享受无缝的系统服务。3、为

  • 雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载

    雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载

    语言:中文版系统大小:4.75GB系统类型:

    雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载在系统方面技术积累雄厚深耕多年,打造了国内重装系统行业的雨林木风品牌,其系统口碑得到许多人认可,积累了广大的用户群体,雨林木风是一款稳定流畅的系统,一直以来都以用户为中心,是由雨林木风团队推出的Windows11国内镜像版,基于国内用户的习惯,做了系统性能的优化,采用了新的系统

  • 雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO

    雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO

    语言:中文版系统大小:5.91GB系统类型:Win7

    雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO在系统方面技术积累雄厚深耕多年,加固了系统安全策略,雨林木风win7旗舰版系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。win7 32位旗舰装机版 v2019 05能够帮助用户们进行系统的一键安装、快速装机等,系统中的内容全面,能够为广大用户

  • 番茄花园Ghost Win7 x64 SP1稳定装机版2022年7月(64位) 高速下载

    番茄花园Ghost Win7 x64 SP1稳定装机版2022年7月(64位) 高速下载

    语言:中文版系统大小:3.91GB系统类型:Win7

    欢迎使用 番茄花园 Ghost Win7 x64 SP1 2022.07 极速装机版 专业装机版具有更安全、更稳定、更人性化等特点。集成最常用的装机软件,集成最全面的硬件驱动,精心挑选的系统维护工具,加上独有人性化的设计。是电脑城、个人、公司快速装机之首选!拥有此系统