离职三个月在家闭门造车学习漏洞挖掘,开始的时候是使用各种开源的fuzz框架对github一顿挖,看各种fuzzer和asan实现的原理。直到挖到第一个UAF类型的漏洞,我终于感觉我可能已经入门了。于是便有了此文,分享一下我研究出来的android全局的UAF和heap over-flow检测的简单思路,供大家一同进步。
https://github.com/mpv-player/mpv/issues/6808 这是我用honggfuzz发现mpv的一个UAF漏洞。调试完后我有了自己对UAF的理解。
在我看来就是系统free的时候没有将数据清除导致之前存储的内容依然存在,使得该程序依然能够正常运行。但凡free后被其他申请的内存覆盖则程序才有可能报错。
自己写了一个demo 来测试UAF
#include <stdio.h> #include <memory.h> #include <stdlib.h> struct sample_1{ char* name; }; struct sample_2{ char* name; struct sample_1* v0; }; int main(int argc,char** argv){ struct sample_1* smp1=(struct sample_1*)malloc(sizeof(struct sample_1)); smp1->name="smp1"; struct sample_2* smp2=(struct sample_2*)malloc(sizeof(struct sample_2)); smp2->name="smp2"; smp2->v0=smp1; free(smp2); printf("%s\n",smp2->name); printf("%s\n",smp2->v0->name); return 0; }
我们看到在free(smp2)以后程序依然正常运行。
看过asan的源码,他采取的是替换free和malloc函数,所以我这里也替换free和malloc,在malloc的时候多分配一个size_t大小用于存储malloc的buffer大小,并放置在buffer前。
在free的时候获取存储的buffer大小进行memset,后在释放。
为测试代码添加了signal处理函数(如果不添加处理函数会显示Segmentation fault: 11),当程序崩溃的时候打印堆栈。
#include <stdio.h> #include <memory.h> #include <stdlib.h> #include <execinfo.h> #include <signal.h> #define STORESIZE sizeof(size_t) struct sample_1{ char* name; }; struct sample_2{ char* name; struct sample_1* v0; }; void show_stack() { int i; void *buffer[1024]; int n = backtrace(buffer, 1024); char **symbols = backtrace_symbols(buffer, n); for (i = 0; i < n; i++) { printf("%s\n", symbols[i]); } } void signal_handler(int sig) { if(SIGSEGV==sig) { show_stack(); exit(-1); } else{ printf("signal with %d\n",sig); } } void my_free(void* addr){ printf("free addr:%p size:%d append_size:%d\n",addr,*(size_t*)((size_t)addr-STORESIZE),STORESIZE); memset(addr,0xFF,*(size_t*)((size_t)addr-STORESIZE)); free((void*)((size_t)addr-STORESIZE)); } void* my_malloc(size_t len){ void* addr=malloc(len+STORESIZE); printf("malloc addr:%p size:%d app_size:%d\n",(void*)((size_t)addr+STORESIZE),len,STORESIZE); *(size_t*)addr=len; return (void*)((size_t)addr+STORESIZE); } int main(int argc,char** argv){ signal(SIGSEGV, signal_handler); struct sample_1* smp1=(struct sample_1*)my_malloc(sizeof(struct sample_1)); smp1->name="smp1"; struct sample_2* smp2=(struct sample_2*)my_malloc(sizeof(struct sample_2)); smp2->name="smp2"; smp2->v0=smp1; my_free(smp2); printf("%s\n",smp2->name); printf("%s\n",smp2->v0->name); return 0; }
编译后运行结果如下:
此时我们已经可以检测到UAF,并且捕获了异常
溢出的检测是在malloc的buffer前后分别添加一个buffer的size 类似[len][buffer][len],在free的时候检测头尾的len是否相等。如不相等则溢出。
void my_free(void* addr){ printf("free addr:%p size:%d append_size:%d\n",addr,*(size_t*)((size_t)addr-STORESIZE),2*STORESIZE); memset(addr,0xFF,*(size_t*)((size_t)addr-STORESIZE)); if(*(size_t*)((size_t)addr-STORESIZE)!=((size_t)addr+*(size_t*)((size_t)addr-STORESIZE))) { printf("heap over_flow!\n"); show_stack(); exit(-1); } free((void*)((size_t)addr-STORESIZE)); } void* my_malloc(size_t len){ void* addr=malloc(len+2*STORESIZE); printf("malloc addr:%p size:%d app_size:%d\n",(void*)((size_t)addr+STORESIZE),len,2*STORESIZE); *(size_t*)addr=len; *(size_t*)((size_t)addr+len+STORESIZE)=len; return (void*)((size_t)addr+STORESIZE); } int main(int argc,char** argv){ char src[120]=""; void* dst=my_malloc(100); memcpy(dst,src,120); my_free(dst); return 0; }
运行结果如下:
这里只说一下思路
1、全局hook 具体方法可以在论坛找(比如注入app_process)
2、hook malloc 和 free函数将其替换
3、在注入的so中添加signal处理函数,将崩溃或heap overflow的信息记录到文件。
4、运行app (此时已经可以检测该app的so是否存在uaf或heap over-flow漏洞)
以上只是个人的想法与观点,如有不当之处,望各位大佬指出。共同学习进步。
[公告]LV6级以上的看雪会员可以免费获得《2019安全开发者峰会》门票一张!!
最后于 38分钟前 被scxc编辑 ,原因: