C/C++典型漏洞产生原理与Demo
来源:互联网 发布:软件测试职位 编辑:程序博客网 时间:2024/06/11 03:51
本篇主要是自己学习笔记,快速读了下泉哥的《漏洞战争》的读书笔记。这里只涉及漏洞产生原理,即漏洞是怎么写出来。至于怎么分析0Day,怎么写代码执行的exp,后续将做深入研究。
C/C++的代码执行漏洞,很多时候是劫持程序的控制流。具体来说:对于C程序,一般是控制函数的返回地址,让程序跳转到我们指定的地方执行。对于C++程序,除了覆盖函数返回地址外,还可以覆盖虚函数表,在调用虚函数的时候,程序将到指定内存处执行。
一、栈溢出漏洞
栈溢出漏洞原理十分简单,只需要了解C语言函数调用时程序的内存结构即可。一句话总结,可控的参数覆盖了函数的返回地址。
#include<stdio.h>#include<string.h>void vulfunc(char* str){ char src[10]; strcpy(src,str);}int main(){ char* str="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; vulfunc(str); return;}
执行程序,程序将crash,并触发Segmentation fault错误。
二、堆溢出漏洞
堆溢出漏洞和栈溢出漏洞原理类似,但是比栈溢出复杂得多,后面单独介绍原理。
#include<stdlib.h>#include<string.h>int main(int argc,char* argv[]){ char* first,second; first = malloc(100); second = malloc(12); if(argc>1){ strcpy(first,argv[1]); } free(fisrt); free(second); return 0;}
同样程序执行时,触发Segmentation fault错误而crash掉。
三、整数溢出
C/C++非内存安全行语言,当输入的整数超出整数的取值范围时,编译器并不会报出错误,但是程序执行时,可能造成严重的安全后果。不过最终导致代码执行,还是归因到栈溢出或者堆溢出。
//栈的整数溢出#include<stdio.h>#include<string.h>int main(int argc,char* argv){ int i; char buf[8]; unsigned short int size; char overflow[65550]; memset(overflow,65,sizeof(overflow)); printf("please input size:\n"); scanf("%d",&i); size =i; printf("size:%d",size); printf("i:%d",i); if(size > 8){ return -1; } //stack overflow memcpy(buf,overflow,i); return 0;}
上面,size类型为unsigned int,最大取值为65535,当超过这个值时,截断导致越过size检查,然后,在memcpy()函数函数中造成栈溢出,程序crash,可能导致代码执行。堆上的整数溢出同理,只是溢出对象是堆数据,导致覆盖的时候后面的堆结构。
四、格式化字符串漏洞
#include<stdio.h>#include<string.h>int main(int argc,char* argv[]){ char buff[1024]; strncpy(buff,argv[1],sizeof(buff)-1); printf(buff); return 0;}
当输入参数为mmm%s或者ttt%x时,程序将产生意向不到的结果。printf()函数的基本形式为:
printf("格式化字符串","参数列表");
这样,当输入ttt%s时,%s不会被当做数据,而是被当成了格式化字符串处理,程序会读取栈上argv[1]后面一个栈上的数据,造成了内存数据的泄露。当输入中包含很多这样的字符时,将可以遍历栈上的数据。
五、UAF漏洞
#include<stdio.h>#define size 32;int main(int argc,char** argv){ char *buf1; char *buf2; buf1=(char*) malloc(size); printf("buf1:0x%p\n",buf1); free(buf1); //buf1=null; buf = (char*)malloc(size); printf("buf2:0x%p\n",buf2); memset(buf2,0,size); printf("buf2:%d\n",*buf2); printf("After free\n"); strncpy(buf1,"hack",5); printf("buf2:%s\n\n",buf2); free(buf2); }
理解这个漏洞的关键是系统对于内存的管理,(后面会深入分析)程序所能拥有的栈内存空间总是有限的,很多需要堆内存,对内存虚拟的内存空间中,堆内存是向上增长的。所以,上面buf1在被free之后,内存管理在再次分配buf2的时候,会认为buf1地址处的内存已经没有用,会分配给buf2,即buf2地址指向了之前buf1地址处。关键是,没有做buf1=NULL的操作,导致buf1成为”野指针”,依然有效。这样,后续如果能够操作到buf1的指针,就可以长生意想不到的结构。如果buf1处为执行指令,则导致了CE。
class CTest{ int m=1;public: virtual void vFunc1(); virtual void vFunc2(); int getM(){ return m; }}void main(){ CTest test; // 实例化;}
在C++代码中,UAF导致CE更加普遍,以为我们常常需要通过new来创建一个对象。如果后面再free()了对应的对象指针后(体现free),没有对指针置NULL。那么攻击者可能通过”占坑式”来让一个指针指向对象的地址,然后利用此指针修改对象的虚函数表。此时,如果对象再次被使用,尤其是虚函数被调用时(体现use after),将导致CE。
六、Double Freee
#include<stdio.h>int main(int argc,char **argv){ void * p1,p2,p3; p1=malloc(100); printf("malloc:%p\n",p1); p2=malloc(100); printf("malloc:%p\n",p2); p3=malloc(100); printf("malloc:%p\n",p3); pritf("free p1\n"); free(p1); pritf("free p3\n"); free(p3); pritf("free p2\n"); free(p2); printf("Double free\n"); free(p2);}
理解这个漏洞并不那么容易,如何导致代码执行也会后面单独来研究,这里只吃别人吃剩的骨头,记录下结论,后面一定要自己研究!!!!!程序释放了p1,p3之后,在释放p2时,会发生堆内存的合并动作,将改变原有的堆头信息及前后向指针。再次释放时,free动作其实应该是引用了之前的地址,所以导致了崩溃。这里,后面研究时,应该要研究系统对堆内存的回收过程。按照泉哥的结论,这根本上是个UAF漏洞,UAF漏洞是比较容易理解的,所以理解内存回收应该是关键。
七、数组越界
数组越界通常包括读越界和写越界,写越界会造成溢出漏洞。
#include<"stdio.h">int main(){ int index; int array[3]={111,222,333}; printf("please input index:\n"); scanf("%d",&index); printf("array[%d]=%d\n",index,array[index]); //写越界,造成溢出; a[index]=233; return 0;}
上面在读取时会造成数组读的越界,赋值时造成(栈)溢出。
以上总结了常见的漏洞类型,其中还有很多知识点需要单独补充:
- 堆溢出原理分析;
- linux对数据分配和回收的管理;
- double free漏洞深入分析;
初次之外,后续要研究的包括:ROP,堆喷,地址随机化绕过,这些属于漏洞利用的知识。
- C/C++典型漏洞产生原理与Demo
- c典型算法 递归
- C典型错误
- c典型算法 递归
- c++/c 产生随机数
- C、C++与Java的产生背景
- C语言的产生与影响
- 随机数的产生原理 - C语言实验篇
- C中strcpy漏洞
- lua 与c#交互原理
- 堆原理与c实现
- C malloc中典型问题
- [C]如何产生随机数~
- C语言产生随机数
- C/C++产生随机数
- C语言产生随机数
- objective-c产生随机数
- C语言产生随机数
- 算法第四版 练习 1.3.34
- AI将带我们去何方?(上-前言篇)
- WekaAPI的学习(加载数据)
- 309. Best Time to Buy and Sell Stock with Cooldown---C语言
- ThinkPHP简介
- C/C++典型漏洞产生原理与Demo
- JAVA购物管理系统
- HDU 6035 Colorful Tree (树形dp)
- 【南阳 oj 】6-- 喷水装置(一)(贪心算法)
- 访问修饰符private
- hdu 2008 数值统计
- opencv写入视频文件
- sloth安装使用
- 四个常用DOM方法(getElementById、getElementByTagName、getAttribute、setAttribute)