前言
偶然逛到的一篇,UAF_overflow_check | Note (gitbook.io)
最近正好也在初学fuzz,学习下对一些漏洞的检测fuzz思路。
刚好这个也指了一条学习方法:看成熟的fuzz工具的源码是如何处理的。
https://github.com/google/sanitizers/tree/master
根据fuzz工具asan源码,对于UAF和堆溢出漏洞,这个工具对malloc与free做了如下HOOK
这里的asan好像指的就是google的AddressSanitizer。
我的理解:hook后可以增加记录信息,同时能够在操作原语的前后进行检测。
UAF
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <execinfo.h>
#include <signal.h>
#define STORESIZE sizeof(size_t)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);
}void main(){signal(SIGSEGV, signal_handler);do();
}
可以看到在malloc
时:
- 在原始存储区前面多分配了一个len长度作为buffer
- 在malloc申请到的地址处写入len长度字段。
在free
时:
- 获取真实存储大小
- 先memset存储的内容空间,再free释放
如果有释放后引用堆块里面的指针行为,程序崩溃Segmentation fault: 的时候打印堆栈。
overflow
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <execinfo.h>
#include <signal.h>
#define STORESIZE sizeof(size_t)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);
}
对于堆溢出的检测,
在malloc
时:
- 在前、后增加了len长度的Buffer
- 构成类似:
[len...][content][len...]
的结构
在free
时:
- 先memset清空存储的内容空间
- 比较首尾两处的
[len...]
结构记录的len字段值是否相等 - 不相等则抛出"堆溢出"错误;相等则free释放。
和canary的保护方法比较类似,在不影响效率的情况下做到了较为准确的检测。