格式字符串利用:Linux 实战探索

概括

这篇博文介绍了夺旗挑战赛,该挑战赛是 2024 年 picoCTF 活动的一部分,该活动持续到 2024 年 3 月 26 日星期二。我们与 NVISO 的团队一起决定参加并应对尽可能多的挑战,最终在全球记分牌上获得了第 130 名的好成绩。我决定尝试专注于二进制利用挑战。虽然我学习了Corelan 的Windows 课程中的 Stack & Heap 利用,但 Linux 二进制利用对我来说相当新,这在试图填补知识空白的同时提供了一个很好的挑战。

挑战涉及格式字符串漏洞。这是一种漏洞,其中输入字符串的提交数据被评估为printf()应用程序不安全使用(例如函数)的参数,从而导致能够读取和/或写入内存。format string 3挑战提供了 4 个文件:

  • 存在漏洞的二进制文件format-string-3(下载链接)

  • 存在漏洞的二进制源代码format-string-3.c(下载链接)

  • AC标准库libc.so.6(下载链接)

  • 动态链接器作为解释器ld-linux-x86-64.so.2(下载链接)

提供这些文件是为了在本地分析漏洞,但目的是编写漏洞来攻击运行易受攻击的二进制文件的远程目标。

最终漏洞利用步骤如下:

  1. setvbuf获取函数的地址libc。这实际上是由易受攻击的二进制文件本身通过一个puts()函数提供的,用于模拟打印到 stdout 的信息泄露,

  2. 动态计算库的基地址libc

  3. 利用格式字符串漏洞,用函数地址覆盖puts全局偏移表(GOT)中的函数地址。system

对于步骤 2,动态计算地址(相对于静态/硬编码)很重要,因为我们可以验证远程目标每次运行时是否在不同地址加载模块。我们可以通过多次运行二进制文件来验证这一点,每次运行时都会提供不同的内存地址。这是由于地址空间布局随机化 (ASLR) 和位置独立可执行文件 (PIE) 编译器标志的组合。后者可以通过readelf在我们的二进制文件上使用来验证,因为二进制文件是作为挑战的一部分提供的。

了解这些缓解措施之间的区别的有趣资源:ASLR/PIE – Nightmare (guyinatuxedo.github.io)

然后,通过生成一个shell,我们可以读取并提交标志文件内容来解决挑战。

漏洞详细信息

字符串格式化的背景

这项挑战涉及一个格式字符串漏洞,正如其名称和描述所示。当用户输入直接传递并用作 C 库printf()及其变体等函数的参数时,就会出现此漏洞:

int printf(const char *format, ...)
int fprintf(FILE *stream, const char *format, ...)
int sprintf(char *str, const char *format, ...)
int vprintf(const char *format, va_list arg)
int vsprintf(char *str, const char *format, va_list arg)

即使进行了输入验证,也printf(input)应避免将输入直接传递给这些函数之一(例如:)。建议改用占位符和字符串格式printf("%s", input)

格式字符串漏洞的影响可以分为几类:

  • 能够读取堆栈上的值

  • 任意内存读取

  • 任意内存写入

在可以进行任意内存写入的情况下,攻击者可以完全控制程序的执行流程,甚至可能实现远程代码执行。

全球抵消表的背景

过程链接表 (PLT) 和全局偏移表 (GOT) 在程序的执行中都起着至关重要的作用,特别是使用共享库编译的程序——几乎任何在现代系统上运行的二进制文件。

GOT 是存储全局变量和函数地址的中央存储库。在当前 CTF 挑战中,格式字符串漏洞尤为突出,因此了解 GOT 至关重要。利用此漏洞需要操纵存储在 GOT 中的地址来重定向程序流。

当一个可执行文件用 C 编写成要调用的函数function并被编译为 ELF 可执行文件时,该函数将被编译为function@plt。执行该程序时,它将跳转到和的 PLT 条目function

  • 如果有 GOT 条目function,它会跳转到存储在那里的地址;

  • 如果没有 GOT 条目,它将解析地址并跳转到那里。

第一个选项的示例,其中有一个GOT 条目function,如下图所示:

你可能感兴趣的:(单片机,嵌入式硬件)