使用fgets导致缓冲区溢出 [英] Causing a buffer Overflow with fgets

查看:431
本文介绍了使用fgets导致缓冲区溢出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试缓冲区溢出,并尝试使用某些fgets输入覆盖堆栈的返回地址

I'm experimenting with buffer overflows and try to overwrite the return address of the stack with a certain input of fgets

这是代码:

void foo()
{
    fprintf(stderr, "You did it.\n");
}

void bar()
{
    char buf[20];
    puts("Input:");
    fgets(buf, 24, stdin);
    printf("Your input:.\n", strlen(buf));
}


int main(int argc, char **argv)
{
    bar();
    return 0;
}

在正常执行时,程序仅返回您的输入.我希望它在不修改代码的情况下输出foo().

On a normal execution the program just returns your input. I want it to output foo() without modifying the code.

我的想法是通过输入20个'A'来溢出buf的缓冲区.这有效,并导致分段错误. 我的下一个想法是找出foo()的地址,即\x4006cd,并将其附加到20个'A' s.

My idea was to overflow the buffer of buf by entering 20 'A's. This works and causes a segmentation fault. My next idea was to find out the address of foo() which is \x4006cd and append this to the 20 'A's.

据我了解,这应该覆盖堆栈的返回地址,并使它跳转到foo.但这只会导致段错误.

From my understanding this should overwrite the return address of the stack and make it jump to foo. But it only causes a segfault.

我在做什么错了?

更新:汇编程序转储 主要

Update: Assembler dumps main

    Dump of assembler code for function main:
   0x000000000040073b <+0>: push   %rbp
   0x000000000040073c <+1>: mov    %rsp,%rbp
   0x000000000040073f <+4>: sub    $0x10,%rsp
   0x0000000000400743 <+8>: mov    %edi,-0x4(%rbp)
   0x0000000000400746 <+11>:    mov    %rsi,-0x10(%rbp)
   0x000000000040074a <+15>:    mov    $0x0,%eax
   0x000000000040074f <+20>:    callq  0x4006f1 <bar>
   0x0000000000400754 <+25>:    mov    $0x0,%eax
   0x0000000000400759 <+30>:    leaveq 
   0x000000000040075a <+31>:    retq   
   End of assembler dump.

foo

Dump of assembler code for function foo:
   0x00000000004006cd <+0>: push   %rbp
   0x00000000004006ce <+1>: mov    %rsp,%rbp
   0x00000000004006d1 <+4>: mov    0x200990(%rip),%rax        # 0x601068 <stderr@@GLIBC_2.2.5>
   0x00000000004006d8 <+11>:    mov    %rax,%rcx
   0x00000000004006db <+14>:    mov    $0x15,%edx
   0x00000000004006e0 <+19>:    mov    $0x1,%esi
   0x00000000004006e5 <+24>:    mov    $0x400804,%edi
   0x00000000004006ea <+29>:    callq  0x4005d0 <fwrite@plt>
   0x00000000004006ef <+34>:    pop    %rbp
   0x00000000004006f0 <+35>:    retq   
End of assembler dump.

栏:

Dump of assembler code for function bar:
   0x00000000004006f1 <+0>: push   %rbp
   0x00000000004006f2 <+1>: mov    %rsp,%rbp
   0x00000000004006f5 <+4>: sub    $0x20,%rsp
   0x00000000004006f9 <+8>: mov    $0x40081a,%edi
   0x00000000004006fe <+13>:    callq  0x400570 <puts@plt>
   0x0000000000400703 <+18>:    mov    0x200956(%rip),%rdx        # 0x601060 <stdin@@GLIBC_2.2.5>
   0x000000000040070a <+25>:    lea    -0x20(%rbp),%rax
   0x000000000040070e <+29>:    mov    $0x18,%esi
   0x0000000000400713 <+34>:    mov    %rax,%rdi
   0x0000000000400716 <+37>:    callq  0x4005b0 <fgets@plt>
   0x000000000040071b <+42>:    lea    -0x20(%rbp),%rax
   0x000000000040071f <+46>:    mov    %rax,%rdi
   0x0000000000400722 <+49>:    callq  0x400580 <strlen@plt>
   0x0000000000400727 <+54>:    mov    %rax,%rsi
   0x000000000040072a <+57>:    mov    $0x400821,%edi
   0x000000000040072f <+62>:    mov    $0x0,%eax
   0x0000000000400734 <+67>:    callq  0x400590 <printf@plt>
   0x0000000000400739 <+72>:    leaveq 
   0x000000000040073a <+73>:    retq   
End of assembler dump.

推荐答案

您没有考虑内存需求.我对代码进行了一些改动,以使其更容易找到正确的位置.

You did not count with memory aligment. I changed the code a litte bit to make it easier to find the right spot.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int **x;
int z;

void foo()
{
    fprintf(stderr, "You did it.\n");
}

void bar()
{
    char buf[2];
    //puts("Input:");
    //fgets(buf, 70, stdin);
    x = (int**) buf;
    for(z=0;z<8;z++)
            printf("%d X=%x\n", z, *(x+z));
    *(x+3) = foo;
    printf("Your input: %d %s\n", strlen(buf), buf);
}


int main(int argc, char **argv)
{
        printf("Foo: %x\n", foo);
        printf("Main: %x\n", main);
        bar();
        return 0;
}

在一个较小的缓冲区中(在我的示例中为2),我发现从缓冲区开始起24个字节之外的返回地址(x + 3,用于8个字节的指针; 64位,没有调试,没有优化...).该位置可以根据缓冲区大小,体系结构等进行更改.在此示例中,我设法将bar的返回地址更改为foo.无论如何,在foo return上都会遇到分段错误,因为未正确将其设置为返回main.

With a smaller buffer, 2 in my example, I found the return address 24 bytes away (x+3, for 8 byte pointers; 64 bits, no debug, no optimization...) from the beginning of the buffer. This position can change depending on the buffer size, architecture, etc. In this example, I manage to change the return address of bar to foo. Anyway you will get a segmentation fault at foo return, as it was not properly set to return to main.

我添加了x和z作为全局变量,以不改变bar的堆栈大小.该代码将显示一个类似值的指针数组,从buf [0]开始.以我为例,我在main的3号位置找到了地址.这就是为什么最终代码具有*(x + 3)= foo的原因.如我所说,该位置可以根据编译选项,机器等进行更改.要找到正确的位置,请在地址列表中找到主地址(在调用栏之前打印).

I added x and z as global vars to not change the stack size of bar. The code will display an array of pointer like values, starting at buf[0]. In my case, I found the address in main in the position 3. That's why the final code has *(x+3) = foo. As I said, this position can change depending on compilation options, machine etc. To find the correct position, find the address of main (printed before calling bar) on the address list.

重要的是要注意,我说的是main中的地址,而不是main的地址,因为返回地址被设置为在调用bar之后的行而不是main的开头.因此,就我而言,它是0x4006af而不是0x400668.

It is important to note that I said address in main, not the address of main, bacause the return address was set to the line after the call to bar and not to the beginning of main. So, in my case, it was 0x4006af instead of 0x400668.

在您的示例中,据我所知,它具有20个字节的缓冲区,对齐为32个字节(0x20).

In your example, with 20 bytes buffer, as far as I know, it was aligned to 32 bytes (0x20).

如果要对fgets进行同样的操作,则必须弄清楚如何键入foo的地址,但是如果您正在运行x86/x64机器,请记住将其添加到小端序中.您可以更改代码以显示每个字节的值,因此您可以按正确的顺序获取它们并使用ALT + number键入它们.请记住,按住ALT键时键入的数字是十进制数字.某些终端不会友好地处理0x00.

If you want to do the same with fgets, you have to figure out how to type the address of foo, but if you are running a x86/x64 machine, remember to add it in little enddian. You can change the code to display the values byte per byte, so you can get them in the right order and type them using ALT+number. Remember that the numbers you type while holding ALT are decimal numbers. Some terminals won't be friendly handling 0x00.

我的输出如下:

$ gcc test.c -o test
test.c: In function ‘bar’:
test.c:21: warning: assignment from incompatible pointer type
$ ./test
Foo: 400594
Main: 400668
0 X=9560e9f0
1 X=95821188
2 X=889350f0
3 X=4006af
4 X=889351d8
5 X=0
6 X=0
7 X=95a1ed1d
Your input: 5 ▒▒`▒9
You did it.
Segmentation fault

这篇关于使用fgets导致缓冲区溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆