我写了一些C代码,在GDB中将其打开,在exploit = (long long *)&exploit+2;行上放置一个断点,然后运行该程序。

#include<stdio.h>

char Shellcode[] = "\x48\xc7\xc0\x01\x00\x00\x00"
                   "\x48\xc7\xc3\x1a\x00\x00\x00"
                   "\xcd\x80";

int main()
{
        long long *exploit;
        exploit = (long long *)&exploit+2;
        *exploit = (long long)Shellcode;
        return 0;
}


由于在行exploit = (long long *)&exploit+2;上设置了断点,因此GDB在执行该行之前会停止执行程序,这意味着仅执行了long long *exploit;的行exploit

在这一点上,我期望exploit驻留在堆栈的顶部,因为它是唯一的局部变量,并且局部变量在调用函数后仍位于堆栈的顶部(如果我错了,请纠正我)。事实并非如此。

(gdb) print /x &exploit
$2 = 0x7fffffffdfe8
(gdb) x/6xg $rsp
0x7fffffffdff0: 0x0000555555554690      0x00007ffff7a5a2b1
0x7fffffffe000: 0x0000000000040000      0x00007fffffffe0d8
0x7fffffffe010: 0x00000001f7b9b288      0x0000555555554660


我们可以看到,元素的顶部是0x7fffffffdff0,而漏洞利用的地址则是0x7fffffffdfe8处的堆栈指针上方8个字节(上面是?怎么可能?)。有人可以向我解释吗?

编辑:

拆卸主要功能可得到:

0x555555554660 <main>           push   %rbp                                                                                                                         │
   │0x555555554661 <main+1>         mov    %rsp,%rbp                                                                                                                    │
B+>│0x555555554664 <main+4>         lea    -0x8(%rbp),%rax                                                                                                              │
   │0x555555554668 <main+8>         add    $0x10,%rax                                                                                                                   │
   │0x55555555466c <main+12>        mov    %rax,-0x8(%rbp)                                                                                                              │
   │0x555555554670 <main+16>        mov    -0x8(%rbp),%rax                                                                                                              │
   │0x555555554674 <main+20>        lea    0x2009b5(%rip),%rdx        # 0x555555755030 <Shellcode>                                                                      │
   │0x55555555467b <main+27>        mov    %rdx,(%rax)                                                                                                                  │
   │0x55555555467e <main+30>        mov    $0x0,%eax                                                                                                                    │
   │0x555555554683 <main+35>        pop    %rbp                                                                                                                         │
   │0x555555554684 <main+36>        retq


编辑2:此代码做什么?

如果变量exploit位于堆栈的顶部(如我预期的那样),则exploit之后的下8个字节将是RBP,后跟__libc_start_main()函数中指令的返回地址。程序执行的环境,调用main(),然后在执行后清理混乱。

exploit = (long long *)&exploit+2;将移动并利用漏洞指向我提到的返回地址,而*exploit = (long long)Shellcode;将使用Shellcode地址覆盖返回地址。由于Shellcode是预先检查的指令的操作码,并且可以被处理器读取,因此一旦程序完成执行并尝试使用返回地址返回__libc_start_main()(只要已关闭DEP),就可以执行该代码。 。

最佳答案

SYS V ABI引入了许多优化,包括(如Jester pointed outRed zone-堆栈指针下方1个128字节的区域,该堆栈指针未被任何异步处理程序触及。
对于叶函数,编译器可以使用红色区域存储局部变量,而无需移动rsp



1请注意,您似乎在堆栈指针的“上方”和“下方”使用了相反的术语。

10-07 16:24