堆栈粉碎代码在 Linux 内核 2.6.38.7 上不起作用...请帮助
Posted
技术标签:
【中文标题】堆栈粉碎代码在 Linux 内核 2.6.38.7 上不起作用...请帮助【英文标题】:Stack smashing code not working on Linux kernel 2.6.38.7... Please help 【发布时间】:2011-10-31 06:46:45 【问题描述】:我一直在阅读“The Shellcoders Handbook”并参考this 链接来练习堆栈溢出。但似乎 Linux 内核开发人员已经使内核非常安全。这是我的问题。
1) 这段代码
void function(int a, int b, int c)
char buffer1[8];
char buffer2[10];
int* ret;
ret = buffer1 + 6;
*ret+=8;
void main()
int x;
x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);
给出输出
$ cc smash.c
smash.c: In function ‘function’:
smash.c:7:8: warning: assignment from incompatible pointer type
$ ./a.out
1
但是用*ret=8
替换行*ret+=8
会得到以下输出
*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x50)[0xa86df0]
/lib/i386-linux-gnu/libc.so.6(+0xe5d9a)[0xa86d9a]
./a.out[0x8048448]
./a.out[0x8048477]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x9b7e37]
./a.out[0x8048381]
======= Memory map: ========
003df000-003e0000 r-xp 00000000 00:00 0 [vdso]
009a1000-00afb000 r-xp 00000000 08:01 3277633 /lib/i386-linux-gnu/libc-2.13.so
00afb000-00afc000 ---p 0015a000 08:01 3277633 /lib/i386-linux-gnu/libc-2.13.so
00afc000-00afe000 r--p 0015a000 08:01 3277633 /lib/i386-linux-gnu/libc-2.13.so
...
...
如果我将ret = buffer1 + 6
替换为ret = buffer1 + 7
,结果与上面相同。
如果我将ret = buffer1 +
6 替换为ret=buffer1+8
(或任何更大的值),则上述两种情况的堆栈都会被破坏(即我是否将值*ret
增加8 或将其更改为8)。
请告诉我这是怎么发生的。有用的链接也将不胜感激。 最重要的是,我怎样才能禁用 Linux 内核的这个安全功能,以便我可以使用这本书?
平台:i386 内核:2.6.38
【问题讨论】:
【参考方案1】:要禁用堆栈粉碎检测,请在编译时使用-fno-stack-protector。在阅读“The Shellcoders Handbook”时,您可能还想使用 -ggdb 和 -mpreferred-stack-boundary=4 来启用 GDB 符号并标准化堆栈。
编辑:
当我编译您提供的代码 (gcc -fno-stack-protector -ggdb -mpreferred-stack-boundary=4 -o sc in.c
) 时,编译器重新排列了 function
中局部变量的顺序。我通过使用 GDB 发现了这一点:
willi@ubuntu:~/testing$ gdb sc
(gdb) set disassembly-flavor intel
(gdb) disassemble function
Dump of assembler code for function function:
0x080483c4 <+0>: push ebp
0x080483c5 <+1>: mov ebp,esp
0x080483c7 <+3>: sub esp,0x20
0x080483ca <+6>: lea eax,[ebp-0xc]
0x080483cd <+9>: add eax,0x6
0x080483d0 <+12>: mov DWORD PTR [ebp-0x4],eax
0x080483d3 <+15>: mov eax,DWORD PTR [ebp-0x4]
0x080483d6 <+18>: mov eax,DWORD PTR [eax]
0x080483d8 <+20>: lea edx,[eax+0x8]
0x080483db <+23>: mov eax,DWORD PTR [ebp-0x4]
0x080483de <+26>: mov DWORD PTR [eax],edx
0x080483e0 <+28>: leave
0x080483e1 <+29>: ret
End of assembler dump.
0x080483ca 告诉我 ebp - 0xC
是 buffer1,而 0x080483d0 告诉我 ebp - 0x4
是 ret。因此,变量不存在于堆栈中,因为它们存在于我们的 C 代码中。鉴于ret
是我们最顶层的局部变量,我们可以直接使用它。不过,让我们使用您的代码。
要修改返回指针,我们需要更改保存的 ebp 正下方存储的地址,即ebp + 0x4
。因此,要从我们的变量 buffer1 中获取返回指针,我们必须添加 0xC(以获取 ebp
),然后添加 0x4(返回指针是 ebp
下的 0x4)。现在我们可以进行修改了。
我从您的 C 代码中获取您希望跳过分配 x = 1
并直接返回到 printf
的内容。我反汇编了main
,找到了对返回指针的适当修改:
(gdb) disassemble main
Dump of assembler code for function main:
0x080483e2 <+0>: push ebp
0x080483e3 <+1>: mov ebp,esp
0x080483e5 <+3>: and esp,0xfffffff0
0x080483e8 <+6>: sub esp,0x20
0x080483eb <+9>: mov DWORD PTR [esp+0x1c],0x0
0x080483f3 <+17>: mov DWORD PTR [esp+0x8],0x3
0x080483fb <+25>: mov DWORD PTR [esp+0x4],0x2
0x08048403 <+33>: mov DWORD PTR [esp],0x1
0x0804840a <+40>: call 0x80483c4 <function>
0x0804840f <+45>: mov DWORD PTR [esp+0x1c],0x1
0x08048417 <+53>: mov eax,DWORD PTR [esp+0x1c]
0x0804841b <+57>: mov DWORD PTR [esp+0x4],eax
0x0804841f <+61>: mov DWORD PTR [esp],0x80484f0
0x08048426 <+68>: call 0x80482f4 <printf@plt>
0x0804842b <+73>: leave
0x0804842c <+74>: ret
End of assembler dump.
不修改返回指针,在0x0804840a处对function
的调用返回到0x0804840f。但是我们想跳过这个并返回下一条指令。下一条指令从 0x08048417 开始,也就是 0x8 字节。所以我们对返回指针的修改必须将它的值增加0x8。
考虑到这些因素,我使用以下代码打印“0”而不是“1”:
void function(int a, int b, int c)
char buffer1[8];
char buffer2[10];
int* ret;
ret = buffer1 + 0x10;
*ret+=8;
void main()
int x;
x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);
【讨论】:
好答案,但我不知道t understand one thing. Why for getting return address from
function`你加0x2
和0x2
和0xc
(关于0xc
我明白,但不是0x2
)?跨度>
ebp
存放保存的栈指针,返回地址直接存放在其下。所以我们需要在保存的栈指针地址上加上sizeof(void *)
,得到返回地址的地址。我更新了帖子以使用0x4
而不是0x2
来反映sizeof(void *)
(不知道为什么我有0x2
)。【参考方案2】:
可以像这样禁用堆栈粉碎保护:
$ gcc -ggdb -m32 -o buffer1 -fno-stack-protector -mpreferred-stack-boundary=4 buffer1.c
This link 提供有关 Linux 安全功能的更多信息
【讨论】:
以上是关于堆栈粉碎代码在 Linux 内核 2.6.38.7 上不起作用...请帮助的主要内容,如果未能解决你的问题,请参考以下文章