使用缓冲区溢出漏洞修改C代码以跳过代码

时间:2015-04-16 00:13:51

标签: c buffer-overflow

我试图找到一种方法来利用以下源代码中的缓冲区溢出漏洞,以便跳过printf("x is 1")行:

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

void func(char *str) {
     char buffer[24];
     int *ret;
     strcpy(buffer,str);
}

int main(int argc, char **argv) {
    int x;
    x = 0;
    func(argv[1]);
    x = 1;
    printf("x is 1");
    printf("x is 0");
    getchar();
}

为了做到这一点,我想修改&#34; func&#34;功能。我知道我需要使用ret变量才能将返回地址修改为刚过我要跳过的行,但我不确定如何实际执行此操作。有没有人有建议?

编辑:

通过使用gdb,我能够在main函数中找到以下调用:

Temporary breakpoint 1, 0x00000000004005ec in main ()
(gdb) x/20i $pc
=> 0x4005ec <main+4>:   sub    $0x20,%rsp
   0x4005f0 <main+8>:   mov    %edi,-0x14(%rbp)
   0x4005f3 <main+11>:  mov    %rsi,-0x20(%rbp)
   0x4005f7 <main+15>:  movl   $0x0,-0x4(%rbp)
   0x4005fe <main+22>:  mov    -0x20(%rbp),%rax
   0x400602 <main+26>:  add    $0x8,%rax
   0x400606 <main+30>:  mov    (%rax),%rax
   0x400609 <main+33>:  mov    %rax,%rdi
   0x40060c <main+36>:  callq  0x4005ac <func>
   0x400611 <main+41>:  movl   $0x1,-0x4(%rbp)
   0x400618 <main+48>:  mov    $0x4006ec,%edi
   0x40061d <main+53>:  mov    $0x0,%eax
   0x400622 <main+58>:  callq  0x400470 <printf@plt>
   0x400627 <main+63>:  mov    $0x4006f3,%edi
   0x40062c <main+68>:  mov    $0x0,%eax
   0x400631 <main+73>:  callq  0x400470 <printf@plt>
   0x400636 <main+78>:  callq  0x400490 <getchar@plt>
   0x40063b <main+83>:  leaveq
   0x40063c <main+84>:  retq
   0x40063d:    nop

虽然,我很困惑从哪里开始。我知道该函数将返回到0x400611的行,并且我需要使它跳转到0x400631,但我不确定如何确定要跳转的位数或我应该如何修改ret变量。

1 个答案:

答案 0 :(得分:1)

想法是找到主函数的返回地址在堆栈上的位置,然后将该偏移添加到您想要得到的命令的偏移量。 要做到这一点:

  1. 使用反汇编查找原始退货地址与新退货地址之间的差异:

    enter image description here

  2. 使用局部变量(例如函数参数)在堆栈上查找func帧地址:

    enter image description here

  3. 最后找到堆栈上返回地址的相对位置,比较局部变量的地址:

    enter image description here

  4. 使用上面的代码看起来像:

    void func(char *str) {
        // 1. Get the address of an object on the stack
        long *ret = (long*)(&str);      
    
        // 2. Move ret to point to the location of the return address from this function. 
        //    Per the example above on my system (Windows 64bit + VS) it was just -1
        ret -= NUMBER_OF_ITEMS_IN_THE_STACK_BEFORE_RETURN_ADDR;
    
        // 3. Modify the return address by adding it the offset to command to go to (in my 
        //   (case 33).
        *ret = *ret + OFFSET_TO_COMMAND;
    
        // The rest of your code
        char buffer[24];
        strcpy(buffer, str);
    }
    

    如上所述,确切的数字取决于系统(即OS,编译器等)。但是,使用上述技术,您应该能够找到要设置的正确数字。

    作为最后一点,现代编译器(例如VS)可能具有保护堆栈损坏的安全保护。如果您的程序因此而崩溃,请检查编译器选项如何禁用此选项。