【问题标题】:How to deal with a bad char in a shellcode buffer overflow?如何处理 shellcode 缓冲区溢出中的坏字符?
【发布时间】:2020-12-08 05:42:41
【问题描述】:

所以我最近对缓冲区溢出感兴趣,许多在线教程和资源都有这种类似 CTF 的攻击,您需要读取标志文件的内容(例如使用 cat)。

所以我开始在网上寻找有关如何执行此操作的组装示例,然后我访问了诸如 this 或 shell-storm 之类的网站,其中有很多关于如何执行此操作的示例。

所以我生成了我的漏洞利用并得到了这个机器代码(它基本上执行了一个执行 cat 标志的 shell):

shellcode = b'\x31\xc0\x50\x68\x2f\x63\x61\x74\x68\x2f\x62\x69\x6e\x89\xe3\x50\x68\x66\x6c\x61\x67\x89\xe1\x50\x51\x53\x89\xe1\x31\xc0\x83\xc0\x0b\xcd\x80'

问题在于,由于使用 GDB 调试问题,我注意到我的缓冲区没有被复制到 shell 代码末尾以 \x0b 开始。我知道问题就在那里,因为如果我将其更改为 \x3b 则它可以工作(我的其余漏洞未在此处复制)即使它明显在它达到错误值时崩溃但在至少整个缓冲区被复制。现在做一些研究,似乎 \x0b 是一个“坏字符”,可能会导致问题,应该避免。话虽如此,我不明白如何:

  • 所有在线甚至大学教程都使用该 shell 代码 为这个确切的任务。

  • 如何解决这个问题。有没有可能完全不 改汇编代码?

我会补充一点,我在 Ubuntu 上并尝试在 64 位上进行这项工作。

【问题讨论】:

  • 据我所知,0xb 不是有问题的字符,但它取决于哪些函数进行复制。您可以使用编码中没有 0xb 的指令来解决它(例如,让 0xb 使用 0xa 和 inc 或其他类似的算术/逻辑技巧)。
  • 这个 shellcode 用于什么 ISA? AArch64? RISC-V64? x86-64?避免机器代码中某些字节的技术显然在很大程度上取决于 ISA。您应该将 [security] 标签替换为 x86-64 或任何合适的标签。
  • 正如 Margaret 所说,查看将您的漏洞利用数据复制到太小的缓冲区中的易受攻击的代码。它的停止条件是什么?如果它类似于strcpy,那么除\0 之外的任何字符都可以,这可能是您的消息来源想要利用的那种漏洞。如果是scanf("%s",...) 之类的,那么遇到空格就会停止,\x0b 是 ASCII 中的空格字符(垂直制表符)。因此,如果这就是您要利用的内容,那么是的,您需要重写代码以避免任何作为空白字符的字节。
  • 有时这可以通过细微的调整来完成,有时它可能需要像你说的那样“完全改变”。真的不一样。
  • 如果您将尝试利用的代码添加到您的问题中,您可能会得到更具体的答案。

标签: security assembly buffer-overflow exploit shellcode


【解决方案1】:

字节 0x0b 的一个特别之处在于它是 ASCII 垂直制表符,它被认为是一个空白字符。

所以我要大胆猜测你正在利用的代码看起来像

// Dangerous code, DO NOT USE
char buf[TOO_SMALL];
scanf("%s", buf);

因为scanf("%s") 是一种常用(错误)使用的输入机制,在遇到空格时会停止。如果是这样,那么如果您的 shellcode 包含 0x0b 或任何其他空白字符,它将被截断。

对于你的第一个问题,关于“为什么其他教程使用这样的 shellcode”,他们可能在思考而不是像利用这样的代码

// Dangerous code, DO NOT USE
char buf[TOO_SMALL];
gets(buf);

其中gets() 不会在0x0b 处停止阅读,而只会在换行符0x0a 处停止阅读。或者他们可能正在考虑由strcpy() 填充的缓冲区,它只会在0x00 处停止,或者可能是由read() 填充的缓冲区,其大小由用户控制,无论它是什么字节,它都会读取全部数据量包含。因此,哪些字符是“坏”的问题取决于易受攻击的代码实际上做了什么。

至于如何处理它,你需要修改你的 shellcode 以只使用不包含任何空白字节的指令。这种事情与其说是科学,不如说是一门艺术;你必须非常了解你的指令集,并创造性地考虑替代指令序列以达到预期的结果。有时您可以通过细微的调整来做到这一点;其他时候可能需要大规模重写。真的不一样。

在这种情况下,幸运的是 0x0b 是整个代码中唯一的空白字符,它出现在指令中

83C00B  add eax, 0x0b

由于eax 之前已清零,因此目标是使用值0xb 加载它,这是execve 的系统调用号。当“坏字节”作为即时数据的一部分出现时,通常不难找到另一种方法将该数据带到它需要去的地方。 (当坏字节是操作码本身的一部分时,生活会更艰难。)在这种情况下,一个简单的解决方案是利用二进制补码,并改为编写

83E8F5  sub eax, -0x0b

单个字节 -0x0b = 0xf5 符号扩展为 32 位并用作要减去的值,从而根据需要将 0x0b 留在 eax 中。当然还有很多其他方式,其中一些可能代码量较小;我会留给你的聪明才智。

【讨论】:

    【解决方案2】:

    找出shellcode的“坏字符”是利用溢出漏洞的重要一步。

    首先,您必须弄清楚目标可以溢出多少位(该字段也用于 shellcode)。如果这个区域足够大,并且您可以使用所有“char”(从 \x01 到 \xff 的 google bad char。\x00 是 bad char)作为 shellcode 发送到目标。

    然后您可以找到寄存器以查看剩余的字符。(如果区域不足以容纳所有字符,您可以一次发送一些字符并重复)

    你可以关注这个https://netsec.ws/?p=180

    【讨论】:

      猜你喜欢
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      相关资源
      最近更新 更多