探索栈溢出远程利用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40337012/article/details/79181564

实验名称:探索栈溢出远程利用


实验环境:

System

IP

Windows7

192.168.127.133

Kali

192.168.127.159


实验工具:

1、  vc++6.0

2、  vim

3、  windbg


实验原理:

l  栈溢出在缓存空间填入shellcode

l  通过jmp esp找到shellcode地址

l  通过pe文件结构特点寻找kernel,进而找到GetProcAddress()就可以获取各种api地址

l  通过异或加密shellcode避免出现0x00字符造成截断

实验过程:

1)     服务器代码解析:

#include<stdio.h>
#include<string.h>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
void printf_data(char *data)
{
	char message[20];
	strcpy(message,data);
	printf("receive data: %s\n",message);
	return 0;
}
/*struct sockaddr
{
	unsigned short sa_family;
	char sa_data[14];
};
struct sockaddr_in
{
	short int sin_family;
	unsigned short int sin_port;
	struct in_addr sin_addr;
	unsigned char sin_zero[8];
};
struct in_addr
{
	unsigned long s_addr;
};*/
int main(void)
{
	struct sockaddr_in sin;
	struct sockaddr_in remote_addr;
	int len=sizeof(remote_addr);
	int ret;

	char rev_data[2000];
	char *send_data="receive the messge!\n";

	SOCKET s_socket;
	SOCKET s_new_socket;

	WORD sockVersion=MAKEWORD(2,2);
	WSADATA wsaData;
	if(WSAStartup(sockVersion,&wsaData)!=0)
	{
		return -1;
	}
	s_socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(s_socket==-1)
	{
		printf("fail");
		return 0;
	}
	sin.sin_family=AF_INET;
	sin.sin_port=htons(55555);
	sin.sin_addr.S_un.S_addr=INADDR_ANY;
	if(bind(s_socket,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
		printf("bind error !");
	if(listen(s_socket,5)==SOCKET_ERROR)
	{
		printf("listen error!\n");
		return 0;
	}
	while(1)
	{
		printf("wait for connecting...\n");
		s_new_socket=accept(s_socket,(SOCKADDR*)&remote_addr,&len);
		if(s_new_socket==INVALID_SOCKET)
		{
			printf("accept error !\n");
			continue;
		}
		printf("success connect with : %s \r\n",inet_ntoa(remote_addr.sin_addr));
		while(1)
		{
			ret =recv(s_new_socket,rev_data,2000,0);
			if(ret>0)
			{
				rev_data[ret]=0x00;
				printf_data(rev_data);
				send(s_new_socket,send_data,strlen(send_data),0);
			}
			else
			{
				closesocket(s_new_socket);
				break;
			}
		}
	}
	closesocket(s_socket);
	WSACleanup();
	return 0;
}

Printf_data处存在栈溢出漏洞:

void printf_data(char *data)
{
	char message[20];
	strcpy(message,data);
	printf("receive data: %s\n",message);
	return 0;
}


2)     通用shellcode原理&编写

通过pe文件结构特点寻找kernel,进而找到GetProcAddress()

·寻找kernel.dll流程:


1、fs寄存器指向TEB结构


2、Teb偏移0x030处指向peb



3、  Peb偏移0x00c处指向peb_ldr_data




4、PEB_LDR_DATA偏移0x014处指向InMemoryOrdermoduleList



5、List_entry结构体



6、查看ldr_data_table_entry结构




总流程:


·寻找具体函数流程:

1、Dos头偏移0x03c找到nt头(image_nt_header)



2、进入optionalheader




3、查看DataDirectory


流程:


在导出表中得到函数:



·汇编解析:





·Vc++6.0反汇编后,利用python脚本提取机器码:





3)     测试shellcode



·shellcode存在的问题


·strcpy以0x00字符结尾

·shellcode存在0x00截断字符

4)     解决办法:

用python脚本异或加密shellcode消除0x00字符


加密后:



5)     解密shellcode的汇编&机器码


机器码:


6)     测试新的shellcode


7) 最终shellcode填入情况


buff

Jmp esp的地址

用于解码的shellcode

经加密的shellcode

8)     发送构造好的shellcode进行攻击



成功!


猜你喜欢

转载自blog.csdn.net/qq_40337012/article/details/79181564