本文是结合参考资料对CVE-2014-3153的分析,当然各位看官可以看最后的资料,他们写的比我好。
在看CVE-2014-3153之前我们用参考资料4中例子来熟悉下这类漏洞是如何产生的:
/** * An example of bug that can be exploited through stack manipulation * Use -m32 to compile as 32 bit app, so that the int size is the same as pointer size */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct node { const char *value; struct node *next; struct node *prev; }; struct list { struct node *head; struct node *tail; }; void list_add(struct list *lst, struct node *newnode) { if (lst->head==NULL) { lst->head = newnode; lst->tail = newnode; } else { newnode->prev = lst->tail; lst->tail->next = newnode; lst->tail = newnode; } } struct node * list_remove_last(struct list *lst) { struct node *result; result = lst->tail; if (lst->head==lst->tail) { /*zero or 1 element*/ lst->head = lst->tail = NULL; } else { lst->tail = lst->tail->prev; lst->tail->next = NULL; } return result; } void list_print(struct list *lst) { struct node *tmp; tmp = lst->head; while (tmp) { printf("Value = %s ", tmp->value); tmp = tmp->next; } } void list_add_new(struct list *lst, const char *val) { struct node *newnode = (struct node *)malloc(sizeof(struct node)); newnode->next = NULL; newnode->value = strdup(val); list_add(lst, newnode); } void print_with_end_of_list(struct list *lst) { struct node instack; instack.next = 0; instack.value = "--END OF LIST--"; printf("Not a buggy function "); list_add(lst, &instack); list_print(lst); /*we ignore the returned node*/ list_remove_last(lst); } void buggy_print_with_end_of_list(struct list *lst) { int dummy_var1; /*see the article to see why i introduced this*/ int dummy_var2; int dummy_var3; struct node instack; printf("a buggy function, here is the location of value on stack %p ", &instack.value); instack.next = 0; instack.value = "--END OF LIST--"; list_add(lst, &instack); list_print(lst); /*we 'forgot' to remove the list element*/ } void a_function_to_exploit(int element_number, void * value) { int i; int buf[10]; if (element_number==-1) { /*print addressed of buf*/ for (i=0; i < 10; i++) { printf("location of buf[%d] is %p ", i, &buf[i]); } return; } buf[element_number] = (int)value; } int main(int argc, char * argv[]) { struct list mylist; mylist.head = NULL; mylist.tail = NULL; int pos; char *val; /*we have one parameter*/ pos = -1; if (argc==3) { pos = atoi(argv[1]); val = argv[2]; } printf("we will use pos: %d ", pos); list_add_new(&mylist, "Alpha"); list_add_new(&mylist, "Beta"); print_with_end_of_list(&mylist); buggy_print_with_end_of_list(&mylist); a_function_to_exploit(pos, val); list_print(&mylist); /*this is just a demo, i am skipping the cleanup code*/ return 0; }
编译上面的代码(假设编译后的可执行文件名为mylist)并执行
$ ./mylist we will use pos: -1 Not a buggy function Value = Alpha Value = Beta Value = --END OF LIST-- a buggy function, here is the location of value on stack 0xffd724a4 Value = Alpha Value = Beta Value = --END OF LIST-- location of buf[0] is 0xffd72488 location of buf[1] is 0xffd7248c location of buf[2] is 0xffd72490 location of buf[3] is 0xffd72494 location of buf[4] is 0xffd72498 location of buf[5] is 0xffd7249c location of buf[6] is 0xffd724a0 location of buf[7] is 0xffd724a4 location of buf[8] is 0xffd724a8 location of buf[9] is 0xffd724ac Value = Alpha Value = Beta Value = --END OF LIST--
根据上面的执行结果我们知道buggy_print_with_end_of_list函数新增list的value值的栈地址刚好对应a_function_to_exploit函数中buf[7]的栈地址,故有继续执行
$./mylist 7 HACKED we will use pos: 7 Not a buggy function Value = Alpha Value = Beta Value = --END OF LIST-- a buggy function, here is the location of value on stack 0xffd3bd34 Value = Alpha Value = Beta Value = --END OF LIST-- Value = Alpha Value = Beta Value = HACKED
执行结果上面符合,buf[7]存储着“HACKED”字符串的地址,刚好是list.value的地址,所以在最后输出"HACKER“。当然这个是bug,它引用了函数中的局部变量(函数返回后,局部变量的值会被后续的代码覆盖导致,导致重大bug)。这个例子告诉我们可以在类似的bug中我们可以操控list值,当然我们并不会满足于此。
另:我们知道TowelRoot root工具就是利用这个CVE,为了防止他人拷贝和重打包,使用了O-LLVM来混淆ndk代码(当然这是另外的课题了,这里是记录下,你可以看译]使用O-LLVM和NDK对Android应用进行混淆 来熟悉概念)。
参考资料: