c - 缓冲区溢出示例不适用于 Debian 2.6

标签 c security buffer-overflow stack-smash

我正在尝试使缓冲区利用示例(来自 http://insecure.org/stf/smashstack.html 的 example3.c)在 Debian Lenny 2.6 版本上运行。我知道 gcc 版本和操作系统版本与 Aleph One 使用的版本不同。我已经使用 -fno-stack-protector 和 sysctl -w kernel.randomize_va_space=0 参数禁用了任何堆栈保护机制。为了解释我的设置和 Aleph One 的差异,我引入了两个参数:offset1 -> 从 buffer1 变量到返回地址的偏移量和 offset2 -> 要跳过多少字节以跳过语句。我试图通过分析汇编代码来找出这些参数,但没有成功。因此,我编写了一个 shell 脚本,基本上运行缓冲区溢出程序,同时使用 (1-60) 的 offset1 和 offset2 值。但令我惊讶的是,我仍然无法破解这个程序。如果有人可以指导我,那就太好了。我已附上代码和程序集输出以供考虑。很抱歉发了这么长的帖子:)

谢谢。


// Modified example3.c from Aleph One paper - Smashing the stack
void function(int a, int b, int c, int offset1, int offset2) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   ret = (int *)buffer1 + offset1;// how far is return address from buffer ?
   (*ret) += offset2; // modify the value of return address
}

int main(int argc, char* argv[]) {
  int x;
  x = 0;
  int offset1 = atoi(argv[1]);
  int offset2 = atoi(argv[2]);
  function(1,2,3, offset1, offset2);
  x = 1; // Goal is to skip this statement using buffer overflow
  printf("X : %d\n",x);
  return 0;
}

-----------------
// Execute the buffer overflow program with varying offsets
#!/bin/bash
for ((i=1; i<=60; i++))
do
   for ((j=1; j<=60; j++))
   do
    echo "`./test $i $j`"
   done
done

-- Assembler output
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c2 <main+0>:    lea    0x4(%esp),%ecx
0x080483c6 <main+4>:    and    $0xfffffff0,%esp
0x080483c9 <main+7>:    pushl  -0x4(%ecx)
0x080483cc <main+10>:   push   %ebp
0x080483cd <main+11>:   mov    %esp,%ebp
0x080483cf <main+13>:   push   %ecx
0x080483d0 <main+14>:   sub    $0x24,%esp
0x080483d3 <main+17>:   movl   $0x0,-0x8(%ebp)
0x080483da <main+24>:   movl   $0x3,0x8(%esp)
0x080483e2 <main+32>:   movl   $0x2,0x4(%esp)
0x080483ea <main+40>:   movl   $0x1,(%esp)
0x080483f1 <main+47>:   call   0x80483a4 <function>
0x080483f6 <main+52>:   movl   $0x1,-0x8(%ebp)
0x080483fd <main+59>:   mov    -0x8(%ebp),%eax
0x08048400 <main+62>:   mov    %eax,0x4(%esp)
0x08048404 <main+66>:   movl   $0x80484e0,(%esp)
0x0804840b <main+73>:   call   0x80482d8 <printf@plt>
0x08048410 <main+78>:   mov    $0x0,%eax
0x08048415 <main+83>:   add    $0x24,%esp
0x08048418 <main+86>:   pop    %ecx
0x08048419 <main+87>:   pop    %ebp
0x0804841a <main+88>:   lea    -0x4(%ecx),%esp
0x0804841d <main+91>:   ret    
End of assembler dump.

(gdb) disassemble function
Dump of assembler code for function function:
0x080483a4 <function+0>:    push   %ebp
0x080483a5 <function+1>:    mov    %esp,%ebp
0x080483a7 <function+3>:    sub    $0x20,%esp
0x080483aa <function+6>:    lea    -0x9(%ebp),%eax
0x080483ad <function+9>:    add    $0x30,%eax
0x080483b0 <function+12>:   mov    %eax,-0x4(%ebp)
0x080483b3 <function+15>:   mov    -0x4(%ebp),%eax
0x080483b6 <function+18>:   mov    (%eax),%eax
0x080483b8 <function+20>:   lea    0x7(%eax),%edx
0x080483bb <function+23>:   mov    -0x4(%ebp),%eax
0x080483be <function+26>:   mov    %edx,(%eax)
0x080483c0 <function+28>:   leave  
0x080483c1 <function+29>:   ret    
End of assembler dump.

最佳答案

function 的反汇编您提供的似乎使用了 offset1 的硬编码值和 offset2 ,与您的 C 代码相反。

ret 的地址应使用字节/字符偏移量计算:ret = (int *)(buffer1 + offset1) ,否则你会被 pointer math 击中(特别是在这种情况下,当您的 buffer1 与返回地址的偏移量不在一个很好的对齐位置时)。

offset1应该等于 0x9 + 0x4 (lea 中使用的偏移量 + push %ebp 的 4 个字节)。但是,每次编译时这可能会发生不可预测的变化 - 堆栈布局可能不同,编译器可能会创建一些额外的堆栈对齐等。

offset2应该等于 7 (您要跳过的指令的长度)。


请注意,您在这里有点幸运 - function使用 cdecl调用约定,这意味着调用者负责从函数返回后从堆栈中删除参数,通常看起来像这样:

push arg3
push arg2
push arg1
call func
add esp, 0Ch ; remove as many bytes as were used by the pushed arguments

您的编译器选择将此更正与 printf 之后的更正结合起来,但它也可以决定在您的函数调用后执行此操作。在这种情况下 add esp, <number>指令将出现在您的返回地址和您要跳过的指令之间 - 您可能会想象这不会很好地结束。

关于c - 缓冲区溢出示例不适用于 Debian 2.6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12550123/

相关文章:

java - 如果我在客户端或网页上上传 .jar 文件,如何确保其安全?

java - 如何在 Java 中序列化和反序列化 RSA KeyPair

java - 初创公司应采取的最低安全预防措施是什么?

linux - 动态查找shellcode的地址,放置在堆栈上

你能解释一下在寻找缓冲区溢出可能性时找到缓冲区偏移量的方法吗

c - 缓冲区溢出返回地址有 00

c - 使用 fread 在 C 中读取 ASCII 文件

c - 在 C 中实现具有邻接表的图

c - 从函数中读取数组的索引

c - 为什么这个 C 程序会出现段错误?