- 235
- 134
- 30 Май 2016
Добровольный ботнет (слито).
Несколько слов о предмете статьи. В качестве объема работы, который будет распределяться, выступает перебор MD5-хеша (поиск коллизии) по диапазону символов. Задача достаточно актуальна и позволяет наглядно продемонстрировать методы своего распределения. Как результат, получится система распределенных вычислений типа «грид-сеть».
Несколько слов о предмете статьи. В качестве объема работы, который будет распределяться, выступает перебор MD5-хеша (поиск коллизии) по диапазону символов. Задача достаточно актуальна и позволяет наглядно продемонстрировать методы своего распределения. Как результат, получится система распределенных вычислений типа «грид-сеть».
Немного терминологии.
Грид вычисления – форма распределенных вычислений, в которой группа компьютеров, объединенных каналами связи (кластер), выполняет большой объем работ. Впервые эта технология была применена для решения научных, математических задач, требующих для решения значительных вычислительных ресурсов. Сейчас грид вычисления используются также и в коммерческой инфраструктуре для решения таких трудоёмких задач как экономическое прогнозирование, сейсмоанализ, разработка и изучение свойств новых лекарств. Но ничто не мешает нам организовать такую сеть для выполнения полезных для нас действий, требующих огромных вычислительных ресурсов. Одно из таких действий – перебор MD5-хеша.
Почему именно MD5? Ответ: потому что хеши этого алгоритма наиболее распространены в веб-инфраструктуре (уже чувствуются летящие в сторону автора камни). К тому же, ничто не мешает переписать участок кода, отвечающего за генерацию хеша по строке, для нужного вам алгоритма шифрования, благо - этот участок небольшой.
В качестве платформы был выбран Microsoft .NET, т.к. обладает широкими возможностями для проектирования сетевых приложений и позволяет сконцентрироваться на задаче, а не на коде. Наша цель – построение грид-сети, а не бот-сети. Этот факт освобождает от необходимости прятать клиента в системе и позволяет написать свой сервер. Плюс ко всему, автор таким способом решил изучить новые для себя технологии и язык программирования в том числе.
Создание базы будущей системы.
Приложение типа «клиент-сервер» с, так называемым, «толстым клиентом», т.е. при получении задачи клиент сам определяет нужный для себя диапазон строк. Серверу остается только в соответствии с запрашиваемым диапазоном сгенерировать его, передать клиенту и учесть у себя, какие диапазоны перебираются и были перебраны.
Технология .NET Remoting освобождает программиста от возни с сокетами и открывает широкие возможности в распределенной вычислительной среде. Используем ее.
Приступим непосредственно к проектированию системы.
При первом запуске сервера требуется создать и зарегистрировать канал на определенном порту (используем порт с номером 39993), а также зарегистрировать класс для удаленной активизации, т.е. для предоставления этого класса клиентам. В этом, собственно, суть Ремоутинга: клиент создает у себя экземпляр класса, который расположен на удаленном сервере, и работает с этим экземпляром, как со своим. При этом все расчеты, которые используются в классе, выполняются на сервере, а клиенту передаются лишь результаты этих расчетов. Вся эта система работает через прозрачный (не видимый с точки зрения программиста) прокси-сервер. В общем, за деталями технологии к поисковику. Вот код, выполняющий наши требования:
Код:
//создать и зарегестрировать канал на порту 39993
TcpServerChannel channel = new TcpServerChannel(39993);
ChannelServices.RegisterChannel(channel);
//зарегистрировать класс для удаленной активизации
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(Bot),//регистрируемый класс
"Bot",//URI регистрируемого класса
WellKnownObjectMode.SingleCall);//режим активизации для каждого клиентского вызова
URI , он же Uniform Resource Identifier (унифицированный идентификатор ресурса) – параметр, который используется клиентом для активизации объекта, т.е. с помощью URI клиент укажет серверу, что требуется экземпляр именно класса Bot.
Клиент, в свою очередь, должен создать клиентский канал и зарегестрировать удаленный класс в локальном домене:
Код:
//создать и зарегестрировать клиентский канал
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel);
//зарегистрировать удаленный класс в локальном домене
RemotingConfiguration.RegisterWellKnownClientType(
typeof(Bot),//удаленный класс
"tcp://localhost:39993/Bot");//URI удаленного класса
Здесь URI задает местоположение удаленного класса. Протокол (в данном случае tcp) соответствует протоколу каналов, зарегистрированных в доменах приложений. Идентификатор машины (localhost) задает сервер, экспортирующий класс Bot и таким образом указывает компьютер, на котором будет создан объект. Вместо localhost можно использовать IP-адрес или имя компьютера. Далее в строке URI через двоеточие указывается номер порта, соответствующий номеру порта, на котором сервер ожидает вызовы (порт с номером 39993).
Для того, чтобы класс Bot поддерживал удаленное взаимодействие необходимо использовать в качестве базового класса System.MarshalByRefObject:
Код:
public class Bot : MarshalByRefObject
{
…
}
Клиентская часть.
Перейдем к детальному рассмотрению клиентской части системы.
После регистрации канала для соединения с сервером и регистрации класса Bot в своем домене, для последующего использования ресурсов, предоставляемых этим классом, клиент должен создать экземпляр этого класса:
Код:
Bot bot = new Bot();
После этого, клиент может работать с объектом bot, как с локальным, но при этом все расчеты, которые выполняются в классе этого объекта, будут производиться сервером (отдаем дань уважения программистам Microsoft).
Затем клиент должен определить диапазон, который он «предпочитает» перебирать за один шаг. «Предпочтения» клиента, автор решил определять с помощью частоты процессора и количества ядер (процессоров) на компьютере. Решение это не случайно: основная нагрузка при переборе ложится на процессор, поэтому его характеристики будут играть важную роль при составлении диапазона. Итак, вот участок кода, в котором определяются характеристики процессора:
Код:
int Core = (Int32)System.Environment.ProcessorCount;//кол-во ядер
int Takt = (Int32)Registry.GetValue(//тактовая частота (МГц)
@"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0",
"~MHz", 0);
Далее составляем функцию, в результате которой получается число, равное числу строк для нашего клиента:
Код:
int RangeValue = Core * Takt * 9; //функция для расчета диапазона
Третий множитель автор определил из того, чтобы среднее время перебора на одной машине было не более 2-х минут. Приблизительно, на компьютере с характеристиками процессора: Core2Duo 2,4ГГц (соответственно, 2 ядра) перебор 80000 тысяч строк диапазона занимает 00:00:47. Цифры весьма условные (т.к. 32-разрядная ОС, особенности получения слова из строки диапазона и активное программное обеспечение также загружают процессор, что затрудняет расчеты), поэтому автор предлагает не “зацикливаться” на этом коэффициенте (вынесем его в настройки клиента) и перейти к следующему важному участку кода, отвечающему за перебор.
Код:
EnemyHash = EnemyHash.ToUpper(); //перевести все символы в верхний регистр
//перебрать каждую строку
int i = 0;
string CurrentLine = string.Empty;
Range += "\0";
while (Range != '\0')
{
if (Range == '\n')
{
Console.WriteLine(CurrentLine);
string CurrentHash = string.Empty;
//сгенерировать MD5-хеш
foreach (byte b in new MD5CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(CurrentLine)))
{
CurrentHash += b.ToString("X2");
}
//сравнить хеши
if (CurrentHash == EnemyHash)
{
bot.Finish(CurrentLine);
Console.ReadKey();
return;
}
CurrentLine = string.Empty;
}
else CurrentLine = CurrentLine + Range;
i++;
}
Описывать действие строк (и без этого откомментированных) автор не собирается, а отправит любопытного читателя к своей мини-статье, в которой детально рассмотрен данный код и процесс перебора в целом ("Раскалываем MD5").
В случае, если клиент не нашел пароль, он отправит пустую строку серверу, которая будет означать, что в перебранном клиентом диапазоне строк не содержится пароль.
На этом рассмотрение основного функционала нашей системы завершается. Теперь необходимо приступить к описанию удаленного класса, который сервер предоставляет своим клиентам и который, по сути, является поставщиком диапазонов для клиентской части.
Удаленный класс Bot .
Данный класс является ядром системы и именно в его методах вычисляется диапазон строк для каждого клиента и производится учет уже перебранных диапазонов, чтобы не происходило «лишней» работы. Рассмотрим наиболее интересные, по моему мнению, участки кода.
Для начала, необходимо сделать класс удаленно доступным для клиентов, т.е. дать клиентам возможность создавать у себя экземпляры этого класса. Плюс технологии Remoting заключается в том, что все расчеты в методах созданного экземпляра будут производиться на сервере (благодаря прозрачному прокси-серверу).
Код:
public class Bot : MarshalByRefObject
{
…
}
Метод GetJob(int RangeValue)(см. исходные коды bot.cs в прилагающемся проекте) фактически содержит в себе код, отвечающий за перебор, за учет перебранных диапазонов, за выдачу диапазона длинной RangeValue, которую определяет клиент для себя сам. В проекте, который прилагается к статье автор постарался не оставить без внимания каждую деталь, поэтому убедительно просит читать комментарии.
Рассмотрим процесс генерации диапазона:
Код:
for (int PassLength = 1; PassLength <= MaxPassLength; PassLength++)
{
char[] Temp = new char[PassLength];//символы, соответствующие номерам
int[] Number = new int[PassLength];//номера символов
bool p=false;
while ((Counter <= RangeValue + Marker) && (p == false))
{
CurrentString = string.Empty;
if (Counter <= Marker+1)
{
//начиная с младшего символа проверяем, не равен ли он размеру множества (проверка на переход в следующий разряд)
for (int i = 0; i < PassLength; i++)
{
if ((Number == CharSet.Length) && (i != PassLength - 1))
{
Number[i + 1]++; //если это так, то младший разряд равен 0, а следующий +1
Number = 0;
}
//если последний разряд подошел к концу, то выйти из программы
if ((i == PassLength - 1) && (Number == CharSet.Length))
{
p = true;
}
}
Number[0]++; // увеличиваем младший разряд на 1 (переход к следующей комбинации)
Counter++;
}
else
{
//начиная с младшего символа проверяем, не равен ли он размеру множества (проверка на переход в следующий разряд)
for (int i = 0; i < PassLength; i++)
{
if ((Number == CharSet.Length) && (i != PassLength - 1))
{
Number[i + 1]++; //если это так, то младший разряд равен 0, а следующий +1
Number = 0;
}
//если последний разряд подошел к концу, то выйти из программы
if ((i == PassLength - 1) && (Number == CharSet.Length))
{
p = true;
}
}
if (p == true) break;
//составление строки
for (int i = PassLength - 1; i >= 0; i--) //генерация строки (пароль)
{
Temp = CharSet[Number];//конвертировать позицию в соответствующий символ
CurrentString += Temp;
}
range += CurrentString + "\n";
Number[0]++; // увеличиваем младший разряд на 1 (переход к следующей комбинации)
Counter++;
}
}
}
Множество символов CharSet, по которому идет перебор, представляется как биективное (взаимооднозначное) отображание во множество чисел (работа с n-мерной системой счисления, где n = length(CharSet)), т.е. при генерации новой строки происходит инкрементация текущего числа на 1.
Под занавес.
Сети распределенных вычислений впервые нашли свое применение в науке. Моделирование сложных процессов, обработка большого объема данных и тому подобные задачи требуют вычислительных мощностей, которые зачастую не способны предоставить суперкомпьютеры. При этом здесь мы не затрагиваем финансовую составляющую. Как альтернативу огромным вычислительным комплексам ученые решили взять «с миру по нитке», и сейчас мы можем наблюдать продукты их побочной деятельности: начиная от обычных кластеров и заканчивая ботнетами, которые, в подавляющем большинстве случаев, используются в корыстных целях.
В этой статье мы рассмотрели создание программного обеспечения, реализующего распределенные транзакции с использованием технологии .NET Remoting. Каждый уважающий пен-тестер должен иметь в своем инструментарии приложение, реализующее распределенные вычисления, и набор производительных серверов для его работы.
Грид вычисления – форма распределенных вычислений, в которой группа компьютеров, объединенных каналами связи (кластер), выполняет большой объем работ. Впервые эта технология была применена для решения научных, математических задач, требующих для решения значительных вычислительных ресурсов. Сейчас грид вычисления используются также и в коммерческой инфраструктуре для решения таких трудоёмких задач как экономическое прогнозирование, сейсмоанализ, разработка и изучение свойств новых лекарств. Но ничто не мешает нам организовать такую сеть для выполнения полезных для нас действий, требующих огромных вычислительных ресурсов. Одно из таких действий – перебор MD5-хеша.
Почему именно MD5? Ответ: потому что хеши этого алгоритма наиболее распространены в веб-инфраструктуре (уже чувствуются летящие в сторону автора камни). К тому же, ничто не мешает переписать участок кода, отвечающего за генерацию хеша по строке, для нужного вам алгоритма шифрования, благо - этот участок небольшой.
В качестве платформы был выбран Microsoft .NET, т.к. обладает широкими возможностями для проектирования сетевых приложений и позволяет сконцентрироваться на задаче, а не на коде. Наша цель – построение грид-сети, а не бот-сети. Этот факт освобождает от необходимости прятать клиента в системе и позволяет написать свой сервер. Плюс ко всему, автор таким способом решил изучить новые для себя технологии и язык программирования в том числе.
Создание базы будущей системы.
Приложение типа «клиент-сервер» с, так называемым, «толстым клиентом», т.е. при получении задачи клиент сам определяет нужный для себя диапазон строк. Серверу остается только в соответствии с запрашиваемым диапазоном сгенерировать его, передать клиенту и учесть у себя, какие диапазоны перебираются и были перебраны.
Технология .NET Remoting освобождает программиста от возни с сокетами и открывает широкие возможности в распределенной вычислительной среде. Используем ее.
Приступим непосредственно к проектированию системы.
При первом запуске сервера требуется создать и зарегистрировать канал на определенном порту (используем порт с номером 39993), а также зарегистрировать класс для удаленной активизации, т.е. для предоставления этого класса клиентам. В этом, собственно, суть Ремоутинга: клиент создает у себя экземпляр класса, который расположен на удаленном сервере, и работает с этим экземпляром, как со своим. При этом все расчеты, которые используются в классе, выполняются на сервере, а клиенту передаются лишь результаты этих расчетов. Вся эта система работает через прозрачный (не видимый с точки зрения программиста) прокси-сервер. В общем, за деталями технологии к поисковику. Вот код, выполняющий наши требования:
Код:
//создать и зарегестрировать канал на порту 39993
TcpServerChannel channel = new TcpServerChannel(39993);
ChannelServices.RegisterChannel(channel);
//зарегистрировать класс для удаленной активизации
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(Bot),//регистрируемый класс
"Bot",//URI регистрируемого класса
WellKnownObjectMode.SingleCall);//режим активизации для каждого клиентского вызова
URI , он же Uniform Resource Identifier (унифицированный идентификатор ресурса) – параметр, который используется клиентом для активизации объекта, т.е. с помощью URI клиент укажет серверу, что требуется экземпляр именно класса Bot.
Клиент, в свою очередь, должен создать клиентский канал и зарегестрировать удаленный класс в локальном домене:
Код:
//создать и зарегестрировать клиентский канал
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel);
//зарегистрировать удаленный класс в локальном домене
RemotingConfiguration.RegisterWellKnownClientType(
typeof(Bot),//удаленный класс
"tcp://localhost:39993/Bot");//URI удаленного класса
Здесь URI задает местоположение удаленного класса. Протокол (в данном случае tcp) соответствует протоколу каналов, зарегистрированных в доменах приложений. Идентификатор машины (localhost) задает сервер, экспортирующий класс Bot и таким образом указывает компьютер, на котором будет создан объект. Вместо localhost можно использовать IP-адрес или имя компьютера. Далее в строке URI через двоеточие указывается номер порта, соответствующий номеру порта, на котором сервер ожидает вызовы (порт с номером 39993).
Для того, чтобы класс Bot поддерживал удаленное взаимодействие необходимо использовать в качестве базового класса System.MarshalByRefObject:
Код:
public class Bot : MarshalByRefObject
{
…
}
Клиентская часть.
Перейдем к детальному рассмотрению клиентской части системы.
После регистрации канала для соединения с сервером и регистрации класса Bot в своем домене, для последующего использования ресурсов, предоставляемых этим классом, клиент должен создать экземпляр этого класса:
Код:
Bot bot = new Bot();
После этого, клиент может работать с объектом bot, как с локальным, но при этом все расчеты, которые выполняются в классе этого объекта, будут производиться сервером (отдаем дань уважения программистам Microsoft).
Затем клиент должен определить диапазон, который он «предпочитает» перебирать за один шаг. «Предпочтения» клиента, автор решил определять с помощью частоты процессора и количества ядер (процессоров) на компьютере. Решение это не случайно: основная нагрузка при переборе ложится на процессор, поэтому его характеристики будут играть важную роль при составлении диапазона. Итак, вот участок кода, в котором определяются характеристики процессора:
Код:
int Core = (Int32)System.Environment.ProcessorCount;//кол-во ядер
int Takt = (Int32)Registry.GetValue(//тактовая частота (МГц)
@"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0",
"~MHz", 0);
Далее составляем функцию, в результате которой получается число, равное числу строк для нашего клиента:
Код:
int RangeValue = Core * Takt * 9; //функция для расчета диапазона
Третий множитель автор определил из того, чтобы среднее время перебора на одной машине было не более 2-х минут. Приблизительно, на компьютере с характеристиками процессора: Core2Duo 2,4ГГц (соответственно, 2 ядра) перебор 80000 тысяч строк диапазона занимает 00:00:47. Цифры весьма условные (т.к. 32-разрядная ОС, особенности получения слова из строки диапазона и активное программное обеспечение также загружают процессор, что затрудняет расчеты), поэтому автор предлагает не “зацикливаться” на этом коэффициенте (вынесем его в настройки клиента) и перейти к следующему важному участку кода, отвечающему за перебор.
Код:
EnemyHash = EnemyHash.ToUpper(); //перевести все символы в верхний регистр
//перебрать каждую строку
int i = 0;
string CurrentLine = string.Empty;
Range += "\0";
while (Range != '\0')
{
if (Range == '\n')
{
Console.WriteLine(CurrentLine);
string CurrentHash = string.Empty;
//сгенерировать MD5-хеш
foreach (byte b in new MD5CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(CurrentLine)))
{
CurrentHash += b.ToString("X2");
}
//сравнить хеши
if (CurrentHash == EnemyHash)
{
bot.Finish(CurrentLine);
Console.ReadKey();
return;
}
CurrentLine = string.Empty;
}
else CurrentLine = CurrentLine + Range;
i++;
}
Описывать действие строк (и без этого откомментированных) автор не собирается, а отправит любопытного читателя к своей мини-статье, в которой детально рассмотрен данный код и процесс перебора в целом ("Раскалываем MD5").
В случае, если клиент не нашел пароль, он отправит пустую строку серверу, которая будет означать, что в перебранном клиентом диапазоне строк не содержится пароль.
На этом рассмотрение основного функционала нашей системы завершается. Теперь необходимо приступить к описанию удаленного класса, который сервер предоставляет своим клиентам и который, по сути, является поставщиком диапазонов для клиентской части.
Удаленный класс Bot .
Данный класс является ядром системы и именно в его методах вычисляется диапазон строк для каждого клиента и производится учет уже перебранных диапазонов, чтобы не происходило «лишней» работы. Рассмотрим наиболее интересные, по моему мнению, участки кода.
Для начала, необходимо сделать класс удаленно доступным для клиентов, т.е. дать клиентам возможность создавать у себя экземпляры этого класса. Плюс технологии Remoting заключается в том, что все расчеты в методах созданного экземпляра будут производиться на сервере (благодаря прозрачному прокси-серверу).
Код:
public class Bot : MarshalByRefObject
{
…
}
Метод GetJob(int RangeValue)(см. исходные коды bot.cs в прилагающемся проекте) фактически содержит в себе код, отвечающий за перебор, за учет перебранных диапазонов, за выдачу диапазона длинной RangeValue, которую определяет клиент для себя сам. В проекте, который прилагается к статье автор постарался не оставить без внимания каждую деталь, поэтому убедительно просит читать комментарии.
Рассмотрим процесс генерации диапазона:
Код:
for (int PassLength = 1; PassLength <= MaxPassLength; PassLength++)
{
char[] Temp = new char[PassLength];//символы, соответствующие номерам
int[] Number = new int[PassLength];//номера символов
bool p=false;
while ((Counter <= RangeValue + Marker) && (p == false))
{
CurrentString = string.Empty;
if (Counter <= Marker+1)
{
//начиная с младшего символа проверяем, не равен ли он размеру множества (проверка на переход в следующий разряд)
for (int i = 0; i < PassLength; i++)
{
if ((Number == CharSet.Length) && (i != PassLength - 1))
{
Number[i + 1]++; //если это так, то младший разряд равен 0, а следующий +1
Number = 0;
}
//если последний разряд подошел к концу, то выйти из программы
if ((i == PassLength - 1) && (Number == CharSet.Length))
{
p = true;
}
}
Number[0]++; // увеличиваем младший разряд на 1 (переход к следующей комбинации)
Counter++;
}
else
{
//начиная с младшего символа проверяем, не равен ли он размеру множества (проверка на переход в следующий разряд)
for (int i = 0; i < PassLength; i++)
{
if ((Number == CharSet.Length) && (i != PassLength - 1))
{
Number[i + 1]++; //если это так, то младший разряд равен 0, а следующий +1
Number = 0;
}
//если последний разряд подошел к концу, то выйти из программы
if ((i == PassLength - 1) && (Number == CharSet.Length))
{
p = true;
}
}
if (p == true) break;
//составление строки
for (int i = PassLength - 1; i >= 0; i--) //генерация строки (пароль)
{
Temp = CharSet[Number];//конвертировать позицию в соответствующий символ
CurrentString += Temp;
}
range += CurrentString + "\n";
Number[0]++; // увеличиваем младший разряд на 1 (переход к следующей комбинации)
Counter++;
}
}
}
Множество символов CharSet, по которому идет перебор, представляется как биективное (взаимооднозначное) отображание во множество чисел (работа с n-мерной системой счисления, где n = length(CharSet)), т.е. при генерации новой строки происходит инкрементация текущего числа на 1.
Под занавес.
Сети распределенных вычислений впервые нашли свое применение в науке. Моделирование сложных процессов, обработка большого объема данных и тому подобные задачи требуют вычислительных мощностей, которые зачастую не способны предоставить суперкомпьютеры. При этом здесь мы не затрагиваем финансовую составляющую. Как альтернативу огромным вычислительным комплексам ученые решили взять «с миру по нитке», и сейчас мы можем наблюдать продукты их побочной деятельности: начиная от обычных кластеров и заканчивая ботнетами, которые, в подавляющем большинстве случаев, используются в корыстных целях.
В этой статье мы рассмотрели создание программного обеспечения, реализующего распределенные транзакции с использованием технологии .NET Remoting. Каждый уважающий пен-тестер должен иметь в своем инструментарии приложение, реализующее распределенные вычисления, и набор производительных серверов для его работы.