Способ 1) Для этого нужно использовать русско английскую клавиатуру, на ней каждой русской букве соответствует английская практически, есть буквы у которых английской буквы нет потому что русских букв 33 а английских 26.
Так вот придумываем или используется самое привычное для вас слово, своё имя, отчество, фамилию свою или девичью матери или девичью бабушки то есть то что вы хрен уже забудете находясь в добром здравии и доброй памяти.
Например имени Александр будут соответствовать следующие английские буквы русско английской клавиатуры FKTRCFYLH.
Владимир будет русским буквам на клавиатуре соответствовать следующие ангельские DKFLBVBH и так далее
Способ 2) Потребуется десять символов первый вариант это строка из английского алфавита ABCDEFGHIJKL его многие знают наизусть.
Вторая строка это снова клавиатура, первый ряд символов русско английских их ровно десять сколько нам и надо QWERTYUIOP
Теперь любое число мы можем привести в набор символов двумя способами. За нулевой символ разумно использовать последний десятый, иначе если первый то будет менее удобно, всё окажется сдвинутым на единицу, 1 будет соответствовать второй символ и так далее что менее удобно чем если 1 соответствует первый символ буква.
Например
Дата рождения человека предположим 22.11.1987 переводим её в символы по строке алфавита английского BBAAAKJI
по строке клавиатуры первой, которая содержит 10 русско английских букв и находится сразу под цифрами WWQQQOIU
также можно перевести номер своего телефона или телефонов которые вы хорошо знаете.
Способ 3) Каждому символу, букве соответствует номер в алфавите, то есть переводим буквы в их порядковые номера в алфавите, числа, и записываем последовательность это и будет паролем. Алфавиты большинство хорошо помнят, но если даже и подзабыли подучить и вспомнить их совершенно не помешает, или можно иметь картинку с алфавитами английским и русскими по рукой, знать стоит наизусть как английский алфавит так и русский.
Например имя Катя 12(К) 1(А) 20(Т) 33(Я). И можно совместить Катя1212033
и пусть подбирают хакеры эту последовательность.
Способ 4) Написание хорошо известного, любимого вами слова, имени, фамилии, задом наперёд. Например Иванов будет Вонави, Петров будет Вортеп, Сидоров будет Вородис. К получившимся словам неочевидным но легко восстанавливаемым, можно добавить какое нибудь любимое вами число например год вашего рождения и тоже написанное задом наперёд.
Способ 5) Комбинация и букв и чисел. Например придумали вышеприведенным способом себе пароль из букв и добавляем к нему еще и циферки например год своего рождения написанный к примеру тремя способами, обычным 1987 или задом наперед 7891 или перенос пары последних цифр в перёд или двух первых назад даст тот же результат 8719 то есть зная что вы так оперируете своим цифрами года рождения у вас всего три варианта их написания, можно сделать больше при желании. И добавляем к паролю из букв год своего или даты рождения записанного обычно или необычно по приведенным выше или вашим собственным правилам.
Мне кажется такие пароли получаются непростыми для подбора при переборе наиболее распространенных слов например, но в тоже время простыми для восстановления и запоминания. Конечно никакие пароли не защитят от серьезных хакеров поэтому компрометирующую вас информацию лучше не хранить на устройствах подключенных к сети интернет, спиздят и ни здрасть ни до свидания не скажут, в легкую.
ЗЫ Более устойчивы пароли если вы используете больше вариантов символов в пароле, например если мы используем только цифры то каждый символ имеет 10 вариантов, если буквы английские и числа то уже 10+26 = 36 вариантов может иметь каждый символ, если буквы большие, мелкие и цифры то вариантов символа в пароле уже будет 10+26+26 = 62. Поэтому многие сайты просят нас использовать и маленькие буквы и большие и числа и даже специальные знаки чтобы пароль был максимально сложным для подбора. Чем большее число символов используется при составлении (цифры, буквы заглавные и мелкие, спецсимволы) пароля тем сложнее его будет взломать хакерам говнякерам методом перебора.
ЗЫ2 Чтобы проще переводить цифры в буквы и буквы в цифры разумно иметь под рукой, на компьютере алфавиты русский и английский с приписанными каждой букве её порядковым номером, картинкой с клавиатурой русско английской если например её не окажется под рукой, иметь возможность глянуть как шифровать слова и цифры. Можно и написать последовательности две из десяти символов из QWERTYUIOP и ABCDEFGHIJKL с подписанными порядковыми номерами для того чтобы не считать, какой букве соответствует десятизначное число, а глянул и сразу узнал какой букве какой номер соответствует, это упростит шифрацию и дешифрацию букв и цифр.
В этой статье мы создадим инструмент, проверяющий схему базы данных (например, имена столбцов) в поиске ценной информации. Допустим, нам нужно найти пароли, хеши, номера социального страхования и кредитных карт. Вместо написания единой утилиты, добывающей информацию из различных БД, мы создадим раздельные программы — по одной для каждой БД — и задействуем конкретный интерфейс, обеспечивая согласованность между их реализациями. Такая гибкость может оказаться излишней для данного примера, но она дает возможность создать переносимый код, который можно использовать повторно.
Интерфейс должен быть минимальным, то есть состоять из нескольких базовых типов и функций, требуя реализации всего одного метода для извлечения схемы базы данных. В коде ниже определяется именно такой интерфейс майнера с названием 𝗱𝗯𝗺𝗶𝗻𝗲𝗿.𝗴𝗼.
Реализация майнера данных /db/dbminer/dbminer.go
Код начинается с определения интерфейса DatabaseMiner. Для реализующих этот интерфейс типов будет требоваться один-единственный метод — GetSchema(). Поскольку каждая серверная база данных может иметь собственную логику для извлечения данной схемы, подразумевается, что каждая конкретная утилита сможет реализовать эту логику уникальным для используемых БД и драйвера способом.
Далее мы определяем тип 𝗦𝗰𝗵𝗲𝗺𝗮, состоящий из нескольких подтипов, которые определены здесь же. Тип 𝗦𝗰𝗵𝗲𝗺𝗮 задействуется для логического представления схемы БД, то есть баз данных, таблиц и столбцов. Вы могли обратить внимание на то, что функция 𝗚𝗲𝘁𝗦𝗰𝗵𝗲𝗺𝗮() в определении интерфейса ожидает, что реализации вернут *𝗦𝗰𝗵𝗲𝗺𝗮.
Далее идет определение одной функции 𝗦𝗲𝗮𝗿𝗰𝗵() с объемной логикой. Эта функция ожидает передачи экземпляра 𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲𝗠𝗶𝗻𝗲𝗿 и сохраняет значение майнера в переменной 𝗺. Начинается она с вызова 𝗺.𝗚𝗲𝘁𝗦𝗰𝗵𝗲𝗺𝗮() для извлечения схемы. Затем функция перебирает всю эту схему в поиске списка соответствующих значений регулярному выражению (𝗿𝗲𝗴𝗲𝘅). При нахождении соответствий схема базы данных и совпадающие поля выводятся на экран.
В завершение мы определяем функцию 𝗴𝗲𝘁𝗥𝗲𝗴𝗲𝘅(). Она компилирует строки регулярных выражений с помощью пакета 𝗚𝗼 𝗿𝗲𝗴𝗲𝘅𝗽 и возвращает срез их значений. Список 𝗿𝗲𝗴𝗲𝘅 состоит из нечувствительных к регистру строк, которые сопоставляются со стандартными или интересующими нас именами полей, например 𝗰𝗰𝗻𝘂𝗺, 𝘀𝘀𝗻 и 𝗽𝗮𝘀𝘀𝘄𝗼𝗿𝗱.
Теперь, имея в распоряжении интерфейс добытчика, можно создать особые реализации утилит. Начнем с добытчика данных из 𝗠𝗼𝗻𝗴𝗼𝗗𝗕.
Реализация майнера данных из MongoDB:
Утилита для работы с MongoDB, показанная в коде ниже, реализует интерфейс из кода Реализации майнера данных, а также интегрирует код подключения к базе данных, который я написал в предыдущем посте (Подключение к базе данных MongoDB).
Создание майнера для MongoDB /db/mongo/main.go
Вначале мы импортируем пакет 𝗱𝗯𝗺𝗶𝗻𝗲𝗿, определяющий интерфейс 𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲𝗠𝗶𝗻𝗲𝗿. Затем прописываем тип 𝗠𝗼𝗻𝗴𝗼𝗠𝗶𝗻𝗲𝗿, который будет использоваться для реализации этого интерфейса. Для удобства также реализуется функция 𝗡𝗲𝘄(), создающая новый экземпляр типа 𝗠𝗼𝗻𝗴𝗼𝗠𝗶𝗻𝗲𝗿, вызывая метод 𝗰𝗼𝗻𝗻𝗲𝗰𝘁(), который устанавливает подключение к базе данных. В совокупности эта логика производит начальную загрузку кода, выполняя подключение к базе данных аналогичным рассмотренному в листинге 𝟳.𝟲 способом.
Самая интересная часть кода содержится в реализации метода интерфейса 𝗚𝗲𝘁𝗦𝗰𝗵𝗲𝗺𝗮(). В отличие от примера кода 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 из кода (Предыдущий Пост) Подключение к базе данных MongoDB и запрос данных , теперь мы проверяем метаданные 𝗠𝗼𝗻𝗴𝗼𝗗𝗕, сначала извлекая имена баз данных, а затем перебирая эти базы данных для получения имен коллекции каждой. В завершение эта функция получает сырой документ, который, в отличие от типичного запроса 𝗠𝗼𝗻𝗴𝗼𝗗𝗕, использует отложенный демаршалинг. Это позволяет явно демаршалировать запись в общую структуру и проверить имена полей. Если бы не возможность такого отложенного демаршалинга, пришлось бы определять явный тип, скорее всего, использующий атрибуты тега 𝗯𝘀𝗼𝗻, инструктируя программу о порядке демаршалинга данных в определенную нами структуру. В этом случае мы не знаем о типах полей или структуре (или нам все равно), нам просто нужны имена полей (не данные) — именно так можно демаршалировать структурированные данные, не зная структуры заранее.
Функция 𝗺𝗮𝗶𝗻() ожидает 𝗜𝗣-адрес экземпляра 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 в качестве единственного аргумента, вызывает функцию 𝗡𝗲𝘄() для начальной загрузки всего, после чего вызывает 𝗱𝗯𝗺𝗶𝗻𝗲𝗿.𝗦𝗲𝗮𝗿𝗰𝗵(), передавая ему экземпляр 𝗠𝗼𝗻𝗴𝗼𝗠𝗶𝗻𝗲𝗿. Напомним, что 𝗱𝗯𝗺𝗶𝗻𝗲𝗿.𝗦𝗲𝗮𝗿𝗰𝗵() вызывает 𝗚𝗲𝘁𝗦𝗰𝗵𝗲𝗺𝗮() в полученном экземпляре 𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲𝗠𝗶𝗻𝗲𝗿. Таким образом происходит вызов реализации функции 𝗠𝗼𝗻𝗴𝗼𝗠𝗶𝗻𝗲𝗿, что приводит к созданию 𝗱𝗯𝗺𝗶𝗻𝗲𝗿.𝗦𝗰𝗵𝗲𝗺𝗮, которая затем просматривается на соответствие списку 𝗿𝗲𝗴𝗲𝘅 из кода Реализация майнера данных.
Совпадение найдено! Выглядит она не очень аккуратно, но работу выполняет исправно — успешно обнаруживает коллекцию базы данных, содержащую поле ccnum.
Разобравшись с реализацией для MongoDB, в следующем разделе сделаем то же самое для серверной базы данных MySQL.
Реализация майнера для MySQL
Чтобы реализация 𝗠𝘆𝗦𝗤𝗟 заработала, мы будем проверять таблицу 𝗶𝗻𝗳𝗼𝗿𝗺𝗮𝘁𝗶𝗼𝗻_𝘀𝗰𝗵𝗲𝗺𝗮.𝗰𝗼𝗹𝘂𝗺𝗻𝘀. Она содержит метаданные обо всех базах данных и их структурах, включая таблицы и имена столбцов. Чтобы максимально упростить потребление данных, используйте приведенный далее 𝗦𝗤𝗟-запрос. Он удалит информацию о некоторых из встроенных БД 𝗠𝘆𝗦𝗤𝗟, не имеющих для нас значения:
В результате данного запроса вы получите примерно такие результаты:
Несмотря на то что использовать этот запрос для извлечения информации схемы довольно просто, сложность кода обусловливается стремлением логически дифференцировать и категоризировать каждую строку при определении функции GetSchema(). Например, последовательные строки вывода могут принадлежать или не принадлежать одной базе данных/таблице, поэтому ассоциирование строк с правильными экземплярами dbminer.Database и dbminer.Table становится несколько запутанным.
В коде снизу показана реализация:
Создание майнера для MySQL /db/mysql/main.go/
Бегло просмотрев код, вы можете заметить, что большая его часть очень похожа на пример для MongoDB из предыдущего раздела. В частности, идентична функция main().
Функции начальной загрузки также очень похожи — изменяется лишь логика на взаимодействие с MySQL, а не MongoDB. Обратите внимание на то, что эта логика подключается к базе данных information.schema, позволяя проинспектировать схему базы данных.
Основная сложность этого кода заключена в реализации 𝗚𝗲𝘁𝗦𝗰𝗵𝗲𝗺𝗮(). Несмотря на то что мы можем извлечь информацию схемы, используя один запрос к БД, после приходится перебирать результаты, просматривая каждую строку с целью определения присутствующих баз данных, их таблиц и строк этих таблиц. В отличие от реализации для 𝗠𝗼𝗻𝗴𝗼𝗗𝗕, у нас нет преимущества 𝗝𝗦𝗢𝗡/𝗕𝗦𝗢𝗡 с тегами атрибутов для маршалинга и демаршалинга данных в сложные структуры. Мы используем переменные для отслеживания информации в текущей строке и сравниваем ее с данными из предыдущей строки, чтобы понять, когда встретим новую базу данных или таблицу. Не самое изящное решение, но с задачей справляется.
Далее идет проверка соответствия имен баз данных текущей и предыдущей строк. Если они совпадают, создается новый экземпляр 𝗺𝗶𝗻𝗲𝗿.𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲. Если это не первая итерация цикла, таблица и база данных добавляются в экземпляр 𝗺𝗶𝗻𝗲𝗿.𝗦𝗰𝗵𝗲𝗺𝗮. С помощью аналогичной логики мы отслеживаем и добавляем экземпляры 𝗺𝗶𝗻𝗲𝗿.𝗧𝗮𝗯𝗹𝗲 в текущую 𝗺𝗶𝗻𝗲𝗿𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲. В завершение каждый столбец добавляется в 𝗺𝗶𝗻𝗲𝗿.𝗧𝗮𝗯𝗹𝗲.
Теперь запустите готовую программу в отношении экземпляра 𝗗𝗼𝗰𝗸𝗲𝗿 𝗠𝘆𝗦𝗤𝗟, чтобы убедиться в корректности ее работы:
Вывод должен получиться практически идентичным выводу для 𝗠𝗼𝗻𝗴𝗼𝗗𝗕. Причина в том, что 𝗱𝗯𝗺𝗶𝗻𝗲𝗿.𝗦𝗰𝗵𝗲𝗺𝗮 не производит никакого вывода — это делает функция 𝗱𝗯𝗺𝗶𝗻𝗲𝗿.𝗦𝗲𝗮𝗿𝗰𝗵(). В этом заключается сила интерфейсов. Можно использовать конкретные реализации ключевых возможностей, задействуя при этом одну стандартную функцию для обработки данных прогнозируемым эффективным способом. В следующем разделе мы отойдем от БД и рассмотрим кражу данных из файловых систем.
Получение данных из файловых систем:
В этом разделе мы создадим утилиту, рекурсивно обходящую предоставленный пользователем путь файловой системы, сопоставляя ее содержимое со списком имен файлов, интересующих нас в процессе постэксплуатации. Эти файлы могут содержать помимо прочего личную информацию, имена пользователей, пароли и логины системы.
Данная утилита просматривает именно имена файлов, а не их содержимое. При этом скрипт существенно упрощается тем, что пакет Go path/filepath предоставляет стандартную функциональность, с помощью которой можно эффективно обходить структуру каталогов. Сама утилита приведена в коде ниже.
Обход файловой системы /filesystem/main.go
В отличие от реализации майнеров данных из БД, настройка и логика инструмента для кражи информации из файловой системы могут показаться слишком простыми. Аналогично тому, как мы создавали реализации для баз данных, вы определяете список для определения интересующих имен файлов. Чтобы максимально сократить код, мы ограничили этот список всего несколькими элементами, но его вполне можно расширить, чтобы он стал более практичным.
Далее идет определение функции walkFn(), которая принимает путь файла и ряд дополнительных параметров. Эта функция перебирает список регулярных выражений в поиске совпадений, которые выводит в stdout. Функция walkFn() используется в функции main() и передается в качестве параметра в filepath.Walk(). Walk() ожидает два параметра — корневой путь и функцию (в данном случае walkFn()) — и рекурсивно обходит структуру каталогов, начиная с переданного корневого пути и попутно вызывая walkFn() для каждого встречающегося каталога и файла.
Написав утилиту, перейдите на рабочий стол и создайте следующую структуру каталогов:
Выполнение утилиты в отношении той же папки targetpath производит следующий вывод, подтверждая, что код работает исправно:
Вот и все, что касается данной темы. Вы можете улучшить этот образец кода, включив в него дополнительные регулярные выражения. Я также посоветую вам доработать его, применив проверку regex только для имен файлов, но не каталогов. Помимо этого, рекомендую найти и отметить конкретные файлы с недавним временем доступа или внесения изменений. Эти метаданные могут привести к более важному содержимому, включая файлы, используемые в значимых бизнес-процессах.
Несмотря на наличие прекрасного стандартного 𝗦𝗤𝗟-пакета, 𝗚𝗼 не поддерживает аналогичный пакет для работы с базами данных 𝗡𝗼𝗦𝗤𝗟. Для этого вам придется использовать сторонние инструменты. Вместо изучения реализации каждого такого стороннего пакета мы сосредоточимся исключительно на 𝗠𝗼𝗻𝗴𝗼𝗗𝗕. Для этого будем применять драйвер 𝗺𝗴𝗼 (произносится «манго»). Начните с установки 𝗺𝗴𝗼:
Теперь можно установить подключение и запросить коллекцию 𝘀𝘁𝗼𝗿𝗲 (эквивалент таблицы), для чего потребуется еще меньше кода, чем в примере с 𝗦𝗤𝗟, который мы создадим чуть позже.
Подключение к базе данных MongoDB и запрос данных
Сначала идет определение типа 𝗧𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻, который будет представлять один документ из коллекции 𝘀𝘁𝗼𝗿𝗲. Внутренний механизм представления данных в 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 — это двоичный 𝗝𝗦𝗢𝗡. По этой причине для определения любых директив маршалинга используются теги. В этом случае с их помощью мы явно определяем имена элементов для применения в двоичных данных 𝗝𝗦𝗢𝗡.
В функции 𝗺𝗮𝗶𝗻() вызов 𝗺𝗴𝗼.𝗗𝗶𝗮𝗹() создает сессию, устанавливая подключение к базе данных, выполняя тестирование на наличие ошибок и реализуя отложенный вызов для закрытия сессии. После этого с помощью переменной 𝘀𝗲𝘀𝘀𝗶𝗼𝗻 запрашивается база данных 𝘀𝘁𝗼𝗿𝗲, откуда извлекаются все записи коллекции 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀. Результаты мы сохраняем в срезе 𝗧𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻 под названием 𝗿𝗲𝘀𝘂𝗹𝘁𝘀. Теги структуры используются для демаршалинга двоичного 𝗝𝗦𝗢𝗡 в определенный нами тип. В завершение выполняется перебор результатов и их вывод на экран. И в этом случае, и в примере с 𝗦𝗤𝗟 из следующего раздела вывод должен выглядеть так:
Обращение к базам данных SQL:
𝗚𝗼 содержит стандартный пакет 𝗱𝗮𝘁𝗮𝗯𝗮𝘀𝗲/𝘀𝗾𝗹, который определяет интерфейс для взаимодействия с базами данных 𝗦𝗤𝗟 и их аналогами. Базовая реализация автоматически включает такую функциональность, как пул подключений и поддержка транзакций. Драйверы базы данных, соответствующие этому интерфейсу, автоматически наследуют эти возможности и, по сути, являются взаимозаменяемыми, поскольку 𝗔𝗣𝗜 между ними остается согласованным. Вызовы функций и реализация в коде идентичны независимо от того, используете вы 𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝘀, 𝗠𝗦𝗦𝗤𝗟, 𝗠𝘆𝗦𝗤𝗟 или другой драйвер. В результате этого удобно менять серверные базы данных при минимальном изменении кода клиента. Конечно же, эти драйверы могут реализовывать специфичные для БД возможности и задействовать различный 𝗦𝗤𝗟-синтаксис, но вызовы функций при этом практически одинаковы. Поэтому мы покажем, как подключать всего одну базу данных 𝗦𝗤𝗟 — 𝗠𝘆𝗦𝗤𝗟, а остальные БД 𝗦𝗤𝗟 оставим в качестве самостоятельного упражнения. Начнем с установки драйвера:
Далее создадим простой клиент, который подключается к этой базе данных и извлекает информацию из таблицы transactions, как показано в коде ниже.
Код начинается с импорта пакета 𝗚𝗼 𝗱𝗮𝘁𝗮𝗯𝗮𝘀𝗲/𝘀𝗾𝗹. Это позволяет реализовать взаимодействие с базой данных через удобный интерфейс стандартной библиотеки 𝗦𝗤𝗟. Кроме того, мы импортируем драйвер базы данных. Начальное подчеркивание указывает на то, что она импортируется анонимно, то есть ее экспортируемые типы не включаются, но драйвер регистрируется пакетом 𝘀𝗾𝗹, и в результате драйвер 𝗠𝘆𝗦𝗤𝗟 сам обрабатывает вызовы функций.
Далее идет вызов 𝘀𝗾𝗹.𝗢𝗽𝗲𝗻() для установки подключения к базе данных. Первый параметр указывает, какой драйвер использовать — в данном случае это 𝗺𝘆𝘀𝗾𝗹, а второй определяет строку подключения. Затем мы обращаемся к базе данных, передавая инструкцию 𝗦𝗤𝗟 для выбора всех строк из таблицы 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀, после чего перебираем эти строки, последовательно считывая данные в переменные и выводя значения.
Это все, что необходимо для запроса данных из 𝗠𝘆𝗦𝗤𝗟. Для использования другой серверной БД потребуется внести в код лишь минимальные изменения:
импортировать подходящий драйвер базы данных;
изменить передаваемые в sql.Open() параметры;
скорректировать SQL-синтаксис в соответствии с требованиями серверной базы данных.
Среди нескольких доступных драйверов баз данных часть написаны на чистом 𝗚𝗼. А некоторые другие используют 𝗰𝗴𝗼 для ряда внутренних взаимодействий. Полный список доступных драйверов можно найти здесь: 𝗵𝘁𝘁𝗽𝘀://𝗴𝗶𝘁𝗵𝘂𝗯.𝗰𝗼𝗺/𝗴𝗼𝗹𝗮𝗻𝗴/𝗴𝗼/𝘄𝗶𝗸𝗶/𝗦𝗤𝗟𝗗𝗿𝗶𝘃𝗲𝗿𝘀/.
Мы составляем подборку интересных игровых каналов, шоу и даже просто рубрик про игры, которые можно найти на просторах RUTUBE. Пожалуйста, поделитесь ссылками на то, что смотрите сами, и расскажите, почему вам нравится этот контент.
В конце декабря в этом профиле выйдет подборка. Если ваши предложения окажутся в ней — придет уведомление к «колокольчик»!
Привет, друзья Pikabu! Сегодня мы поговорим о том, как можно использовать Python для создания чего-то полезного и интересного. Мы напишем простой генератор паролей, который поможет вам создавать безопасные пароли для ваших аккаунтов.
Шаг 1: Импорт необходимых библиотек Для начала нам понадобятся две библиотеки: string и random. Библиотека string содержит полезные константы, такие как буквы и цифры, а random поможет нам выбирать символы случайным образом.
Шаг 2: Создание функции для генерации пароля Теперь давайте создадим функцию, которая будет генерировать пароль. Эта функция будет принимать один параметр: длину пароля.
Шаг 3: Использование функции Теперь мы можем использовать эту функцию для генерации пароля. Давайте создадим пароль длиной в 12 символов.
И вот мы создали простой, но эффективный генератор паролей на Python! Этот скрипт можно доработать, добавив в него дополнительные функции, например, проверку сложности пароля. Надеюсь, вам понравился этот мини-проект. Делитесь в комментариях, какие еще интересные вещи вы создавали с помощью Python!
Предыстория, один клиент в компании попросил проверить пк сотрудника после упадка продаж, он реально думал что сливали заказы копированием или как то доступом через crm в общем упадок был, а понять как и отследить было сложно. Так для тех кто в теме, скрипт я переделал под exe прятался он под pdf прайсом. а в диспетчере скрыт. И пост не для программистов.
Попросили меня проверить, результат порадовал, но причастность доказать нереально кто из менеджеров запустил данный софт. Схема проста, покупается зарубежный виртуальный номер на который регистрируется аккаунт телеграмм и через которого создаётся бот.
Рекомендую всем проверять отправки на порты телеги возможно вы тот самый за кем шпионит жена, муж, начальник или конкурент.
Находку я немного переписал, потому что она была зашита под файлом но выполняла почто такой же функционал как на видео.
Кто такие “White hats - Белы шляпы” ?
“White hats - Белы шляпы” - это термин, используемый для обозначения этичных хакеров, которые используют свои навыки для улучшения кибербезопасности.
Они работают на благо общества, помогая организациям обнаруживать и устранять уязвимости в их системах безопасности.
Белые шляпы проводят тестирование на проникновение и другие проверки безопасности, чтобы обнаружить потенциальные угрозы.
В отличие от “Black hats”, белые шляпы действуют законно и с разрешения владельцев систем.
Работа белых шляп важна для поддержания безопасности в интернете и защиты данных пользователей от злоумышленников. Всё тестировалось в среде на виртуальных машинах и ведео не в коем образом не пропагандирует взлом или как то его рекламирует. Видео несёт информационный характер в сфере Pentest. Tg@Windall
В этой статье мы установим различные системы баз данных, а затем заполним их информацией, которую сами же и будем красть в последующих примерах. Везде, где возможно, используем 𝗗𝗼𝗰𝗸𝗲𝗿 из-под виртуальной машины 𝗨𝗯𝘂𝗻𝘁𝘂 𝟭𝟴.𝟬𝟰. 𝗗𝗼𝗰𝗸𝗲𝗿 — это платформа создания контейнеров ПО, упрощающая развертывание приложений и управление ими. Она дает возможность связывать программы упрощающим развертывание способом. При этом контейнер остается отделенным от операционной системы, что предотвращает «загрязнение» хостовой машины. Это очень классная штука.
Для данной главы мы задействуем несколько предварительно настроенных образов 𝗗𝗼𝗰𝗸𝗲𝗿 для баз данных, с которыми будем работать. Если 𝗗𝗼𝗰𝗸𝗲𝗿 у вас еще не установлен, то инструкции по его установке в 𝗨𝗯𝘂𝗻𝘁𝘂 вы найдете здесь: 𝗵𝘁𝘁𝗽𝘀://𝗱𝗼𝗰𝘀.𝗱𝗼𝗰𝗸𝗲𝗿.𝗰𝗼𝗺/𝗶𝗻𝘀𝘁𝗮𝗹𝗹/𝗹𝗶𝗻𝘂𝘅/𝗱𝗼𝗰𝗸𝗲𝗿-𝗰𝗲/𝘂𝗯𝘂𝗻𝘁𝘂/
Мы намеренно опустили детали настройки экземпляра Oracle. Несмотря на то что Oracle предоставляет образы виртуальных машин, которые можно скачать и использовать для создания тестовой БД, мы посчитали, что знакомить вас со всеми этими действиями необязательно, поскольку они аналогичны приводимым далее примерам с MySQL. Поэтому реализация версий программы с применением Oracle остается для вас домашним заданием.
Установка и заполнение MongoDB:
𝗠𝗼𝗻𝗴𝗼𝗗𝗕 — это единственная база данных 𝗡𝗼𝗦𝗤𝗟, с которой мы будем работать в этой главе. В отличие от традиционных реляционных БД, она не взаимодействует посредством 𝗦𝗤𝗟. Вместо этого 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 для извлечения данных и управления ими использует понятный синтаксис 𝗝𝗦𝗢𝗡. Этому виду баз данных посвящены целые книги, и ее подробное рассмотрение выходит за рамки изучения нашего материала. На данном этапе мы с вами установим образ 𝗗𝗼𝗰𝗸𝗲𝗿 и заполним его фиктивными данными.
В отличие от стандартных баз данных 𝗦𝗤𝗟, 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 не имеет схемы, то есть не придерживается предопределенной жесткой системы организации табличных данных. Это объясняет, почему в коде Внедрение транзакций в коллекцию MongoDB вы видите только команды 𝗶𝗻𝘀𝗲𝗿𝘁 без каких-либо определений схем. Начнем с установки образа 𝗗𝗼𝗰𝗸𝗲𝗿 𝗠𝗼𝗻𝗴𝗼𝗗𝗕:
Эта команда скачает образ 𝗺𝗼𝗻𝗴𝗼 из репозитория 𝗗𝗼𝗰𝗸𝗲𝗿, запустит новый экземпляр 𝘀𝗼𝗺𝗲-𝗺𝗼𝗻𝗴𝗼 (имя можете дать любое) и сопоставит локальный порт 𝟮𝟳𝟬𝟭𝟳 с портом контейнера 𝟮𝟳𝟬𝟭𝟳. Сопоставление портов необходимо, поскольку так мы получаем возможность обращаться к экземпляру базы данных непосредственно из операционной системы. Иначе он был бы недоступен. Проверьте, запустился ли контейнер автоматически, сделав вывод всех выполняющихся контейнеров:
Если автоматически он не запускается, выполните:
Команда 𝘀𝘁𝗮𝗿𝘁 должна запустить контейнер.
После этого подключитесь к экземпляру 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 с помощью команды 𝗿𝘂𝗻, передав ему клиент 𝗠𝗼𝗻𝗴𝗼𝗗𝗕. Таким образом вы можете взаимодействовать с БД для заполнения ее данными:
Эта волшебная команда запускает второй, теперь уже одноразовый, контейнер 𝗗𝗼𝗰𝗸𝗲𝗿, в котором установлен исполняемый файл клиента 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 (то есть устанавливать его в систему хоста уже не нужно), и задействует этот контейнер для подключения к экземпляру 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 𝗗𝗼𝗰𝗸𝗲𝗿 контейнера 𝘀𝗼𝗺𝗲-𝗺𝗼𝗻𝗴𝗼. В этом примере выполняется подключение к БД 𝘀𝘁𝗼𝗿𝗲.
В коде ниже мы вставляем массив документов в коллекцию 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀. (Все листинги кода находятся в корне /𝗲𝘅𝗶𝘀𝘁 репозитория 𝗵𝘁𝘁𝗽𝘀://𝗴𝗶𝘁𝗵𝘂𝗯.𝗰𝗼𝗺/𝗯𝗹𝗮𝗰𝗸𝗵𝗮𝘁-𝗴𝗼/𝗯𝗵𝗴/.)
Вот и все! Таким образом вы создали экземпляр базы данных 𝗠𝗼𝗻𝗴𝗼𝗗𝗕 и заполнили его коллекцией 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀, которая содержит три фиктивных документа для запросов, чем мы вскоре и займемся. Но сначала вам нужно узнать, как устанавливать и заполнять традиционные базы данных 𝗦𝗤𝗟.
Установка и заполнение баз данных PostgreSQL и MySQL:
𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝗦𝗤𝗟 (также называемая 𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝘀) и 𝗠𝘆𝗦𝗤𝗟 — вероятно, наиболее распространенные и хорошо известные корпоративные реляционные системы баз данных с открытым исходным кодом. При этом официальные образы 𝗗𝗼𝗰𝗸𝗲𝗿 существуют для обеих. Из-за их сходства и в основном одинакового процесса установки мы объединили здесь соответствующие инструкции.
Во-первых, как и в примере с 𝗠𝗼𝗻𝗴𝗼𝗗𝗕, сначала нужно скачать и установить подходящий образ 𝗗𝗼𝗰𝗸𝗲𝗿:
После сборки контейнеров убедитесь, что они работают. Если же нет, их можно запустить с помощью команды 𝗱𝗼𝗰𝗸𝗲𝗿 𝘀𝘁𝗮𝗿𝘁 𝗻𝗮𝗺𝗲. Далее можно подключиться к этим контейнерам из подходящего клиента, опять же используя образ 𝗗𝗼𝗰𝗸𝗲𝗿, чтобы избежать установки дополнительных файлов на хосте, и продолжить создавать, а затем заполнять базу данных. В коде ниже прописана логика 𝗠𝘆𝗦𝗤𝗟.
Создание и инициализация базы данных MySQL
Этот листинг, как и последующий, начинается с одноразовой оболочки 𝗗𝗼𝗰𝗸𝗲𝗿, выполняющей соответствующий двоичный файл клиента. Она генерирует базу данных 𝘀𝘁𝗼𝗿𝗲 и подключается к ней, после чего создает таблицу 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀. Эти два листинга идентичны, за исключением того, что связаны с разными системами БД.
В коде ниже прописана логика 𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝘀, которая немного отличается синтаксисом от 𝗠𝘆𝗦𝗤𝗟.
Создание и инициализация базы данных Postgres
В 𝗠𝘆𝗦𝗤𝗟 и 𝗣𝗼𝘀𝘁𝗴𝗿𝗲𝘀 синтаксис для внедрения транзакций идентичен. Например, в коде ниже указано, как вставить три документа в коллекцию 𝘁𝗿𝗮𝗻𝘀𝗮𝗰𝘁𝗶𝗼𝗻𝘀 𝗠𝘆𝗦𝗤𝗟.
Вставка транзакций в базы данных MySQL
Попробуйте вставить те же три документа в свою БД Postgres.
Перед тем как ознакомиться с данным материалом настоятельно рекомендую ознакомиться с предыдущей статьей.
Один из столпов социального инжиниринга — это атака по сбору учетных данных. В ходе нее перехват учетной информации пользователя происходит за счет подмены оригинального сайта клонированной версией, где пользователь и вводит свои данные. Эта техника эффективна против организаций, которые предоставляют в интернете доступ к интерфейсу однофакторной аутентификации. Как только вы получили учетные данные пользователя, можете применять их для получения доступа к аккаунту на оригинальном сайте. Это зачастую приводит к прорыву сетевого периметра организации.
Go обеспечивает отличную платформу для выполнения подобных атак, потому что он быстро устанавливает новые серверы, позволяя также легко настраивать маршрутизацию и парсинг вводимой пользователем информации. В сборщик учетных данных можно добавлять множество настроек и возможностей, но в нашем примере будем придерживаться основ.
Для начала нужно сделать клон сайта, имеющего форму авторизации. Здесь можно рассмотреть множество вариантов. На практике вы будете делать копию сайта, используемого вашей мишенью. В своем примере мы будем клонировать ресурс Roundcube. Roundcube — это открытый клиент электронной почты, который применяется не так часто, как коммерческие решения наподобие Microsoft Exchange, но вполне годится для демонстрации принципа. Для запуска Roundcube мы задействуем Docker, так как он существенно упрощает процесс.
Вы можете запустить собственный сервер Roundcube, выполнив приведенный далее код. Делать это не обязательно, так как исходный код примера содержит клон данного сайта. Тем не менее для полноты информации мы включаем и этот вариант:
Эта команда запускает экземпляр Roundcube Docker. Перейдя по адресу http://127.0.0.1:80, вы увидите форму авторизации. Обычно для клонирования сайта и всех необходимых ему файлов используется wget, но задействованный в реализации Roundcube JavaScript лишает нас этой возможности. Вместо этого применим для сохранения Google Chrome. Структура каталога примера приведена в коде ниже.
Структура каталогов
Файлы в каталоге public представляют неизмененный сайт. Вам потребуется изменить исходную форму авторизации, чтобы перенаправлять вводимые данные, отправляя их своему серверу вместо действительного. Для начала откройте public/index.html и найдите элемент формы, используемый для POST-запроса авторизации. Он должен выглядеть так:
В этом теге нужно отредактировать атрибут action, направив его на свой сервер. Для этого измените action на /login и сохраните. Теперь эта строка должна выглядеть так:
Для корректного отображения формы авторизации и перехвата имени пользователя с паролем сначала потребуется разместить эти файлы в каталог public. Затем нужно будет написать для /login функцию HandleFunc, которая и будет выполнять перехват. Вам также потребуется сохранить полученные учетные данные в файле с помощью логирования.
Все это можно обработать буквально в нескольких строках кода, и в коде ниже вы увидите итоговую программу целиком.
Сервер сбора учетных данных
Первое, на что следует обратить внимание, — это импорт github.com/Sirupsen/logrus. Это структурированный пакет для логирования, который мы предпочитаем задействовать вместо стандартного пакета Go log. Он предоставляет более богатые возможности настройки логирования для лучшей обработки ошибок. Чтобы использовать этот пакет, нужно, как обычно, вначале выполнить go get.
Затем мы определяем функцию-обработчик login(). Надеемся, что данный паттерн вам знаком. Внутри этой функции запись перехваченных данных реализуется с помощью log.WithFields(). При этом отображаются текущее время, пользовательский агент и IP-адрес источника запроса. Помимо этого, выполняется вызов FormValue(string) для перехвата переданных значений имени пользователя (_user) и пароля (_pass). Эти значения мы получаем из index.html, также определив расположение элементов ввода формы для каждого имени пользователя и пароля. Ваш сервер должен явно соответствовать именам полей в том виде, в каком они присутствуют в форме авторизации.
Приведенный далее фрагмент, извлеченный из index.html, показывает соответствующие вводные элементы, чьи имена для наглядности выделены жирным:
В функции main() мы начинаем с открытия файла, в котором будут храниться перехваченные данные. Затем используем log.SetOutput(io.Writer), передавая ей только что созданный дескриптор файла для настройки пакета логирования, чтобы он производил запись в этот файл. Далее создаем новый маршрутизатор и добавляем функцию-обработчик login().
Перед запуском сервера нужно выполнить еще одно действие: сообщить маршрутизатору о необходимости предоставлять статические файлы из каталога. Таким образом, ваш сервер Go явно знает, где находятся все статические файлы — изображения, JavaScript, HTML. Go упрощает этот процесс и обеспечивает защиту против атак по обходу каталогов. Начиная изнутри, мы используем http.Dir(string) для определения каталога, из которого нужно предоставлять файлы. Результат передается в качестве ввода в http.FileServer(FileSystem), которая создает для данного каталога http.Handler. Все это прикрепляется к маршрутизатору с помощью PathPrefix(string). Использование / в качестве префикса пути будет соответствовать всем запросам, которые еще не нашли соответствия. Обратите внимание на то, что по умолчанию возвращаемый из FileServer обработчик поддерживает индексацию каталогов, что может спровоцировать утечку информации. Это можно отключить, но здесь мы данный вопрос рассматривать не будем.
В завершение, как и прежде, мы запускаем сервер. Собрав и выполнив код Сервера сбора учетных данных, откройте браузер и перейдите на http://localhost:8080. Попробуйте отправить через форму имя пользователя и пароль. Затем выйдите из программы и откройте credentials.txt:
Только взгляните на эти логи! Здесь видно, что были отправлены имя Oleg и пароль p@ssw0rd1!. Наш вредоносный сервер успешно обработал POST-запрос формы, перехватив введенные учетные данные и сохранив их в файл для просмотра офлайн. Будучи атакующим, вы могли бы затем использовать эти данные против целевой организации и продолжить внедрение в ее систему.
Далее мы проработаем вариацию этой техники по сбору учетных данных. Вместо ожидания отправки формы создадим кейлогер для перехвата нажатий клавиш в реальном времени.
Кейлогинг с помощью WebSocket API
WebSocket API (WebSockets) — это полнодуплексный протокол, чья популярность на протяжении последних лет возросла, поскольку теперь он поддерживается во многих браузерах. Этот протокол предоставляет веб-серверам и их клиентам способ эффективно взаимодействовать друг с другом. Что еще более важно, он позволяет серверу отправлять сообщения клиенту, не требуя опроса.
WebSockets применяются для создания приложений реального времени, таких как чаты и онлайн-игры. Но их можно задействовать и для вредоносных действий, например для внедрения кейлогера в приложение с целью перехвата всех нажимаемых пользователем клавиш. Для начала представьте, что нашли приложение, уязвимое для межсайтового выполнения сценариев (брешь, через которую сторонний агент может выполнять произвольный JS-код в браузере жертвы), или взломали сервер, получив возможность изменять исходный код этого приложения. При любом из этих вариантов вы сможете внедрить удаленный JS-файл. Мы с вами создадим инфраструктуру сервера для обработки WebSocket-соединения со стороны клиента и регистрации входящих нажатий клавиш.
В целях демонстрации для тестирования полезной нагрузки мы используем JS Bin(http://jsbin.com). JS Bin — это онлайн-песочница, где разработчики могут тестировать свой HTML- или JS-код. Перейдите на этот ресурс в браузере и вставьте следующий HTML в столбец слева, полностью заменив исходный код:
В правой части экрана отобразится форма. Вы могли заметить, что включили тег script с атрибутом src, установленным как http://localhost:8080/k.js. Это будет JS-код, реализующий создание WebSocket-соединения и отправку пользовательского ввода на сервер.
Нашему серверу потребуется выполнить два действия: обработать WebSocket и предоставить JS-файл. Давайте в первую очередь покончим с JavaScript, ведь книга, в конце концов, посвящена Go. (Инструкции по написанию JS-кода с помощью Go имеются в репозитории https://github.com/gopherjs/gopherjs/.)
Вот JS-код:
Он обрабатывает события нажатия клавиш. Каждое такое нажатие этот код отправляет через WebSocket на ресурс по адресу ws://{{.}}/ws. Напомним, что значение {{.}} является полем ввода шаблона Go, отражающего текущий контекст. Этот ресурс представляет WebSocket URL, который будет вносить информацию о местоположении сервера на основе переданной в шаблон строки. Мы вернемся к этому через минуту. Для этого примера сохраним JS в файл logger.js.
Вас может смутить то, что мы вроде собирались предоставлять его как k.js. HTML-код, который мы показали ранее, тоже явно использует k.js. Что это значит? Это значит, что на деле logger.js является не JS-файлом, а шаблоном Go. Мы будем применять k.js в маршрутизаторе в качестве паттерна для сопоставления. При его совпадении сервер будет отображать шаблон из файла logger.js, заполненный контекстными данными, представляющими хост, к которому подключается WebSocket. Код сервера, реализующий этот процесс, показан в коде ниже.
Сервер кейлогинга
Рассмотрим приведенный код подробнее. Прежде всего, обратите внимание на то, что мы используем еще одну стороннюю библиотеку, gorilla/websocket, с помощью которой обрабатываем коммуникации WebSocket. Это полноценный мощный пакет, упрощающий процесс разработки, наподобие уже знакомого вам gorilla/mux. Не забудьте сначала выполнить из терминала go get github.com/gorilla/websocket.
Затем переходим к определению нескольких переменных. Мы создаем экземпляр websocket.Upgrader, который будет добавлять в белый список каждый источник. Допуск всех источников обычно считается плохой практикой в плане безопасности, но здесь мы не придаем этому значения, поскольку работаем с тестовым экземпляром, который будем запускать на локальных рабочих станциях. Для использования в реальных вредоносных действиях источник нужно будет ограничить конкретным значением.
В функции init(), выполняющейся автоматически перед main(), мы определяем аргументы командной строки и пытаемся спарсить шаблон Go, расположенный в файле logger.js. Обратите внимание на то, что мы вызываем template.ParseFiles("logger.js"). Проверяем ответ, чтобы убедиться в успешном парсинге файла. Если все правильно, то спарсенный шаблон будет сохранен в переменной jsTemplate.
На данный момент мы еще не предоставляли контекстуальных данных шаблону и не выполняли его. Это произойдет чуть позже. Сначала идет определение функции serveWS(), которая будет использоваться для обработки WebSocket-коммуникаций. С помощью вызова upgrader.Upgrade(http.ResponseWriter, *http.Request, http.Header) мы создаем экземпляр websocket.Conn. Метод Upgrade() расширяет HTTP-соединение для использования протокола WebSocket. Это означает, что любой обрабатываемый данной функцией запрос будет расширен для использования WebSocket. Мы взаимодействуем с этим соединением внутри бесконечного цикла for, вызывая для чтения входящих сообщений conn.ReadMessage(). Если JS-код будет работать должным образом, то сообщения должны состоять из перехваченных символов нажатых клавиш. Эти сообщения и удаленный IP-адрес клиента записываются в stdout.
Мы разобрали самую сложную часть пазла создания обработчика WebSocket. Далее идет создание еще одной функции-обработчика serveFile(). Она будет извлекать и возвращать содержимое JS-шаблона, заполненного включенными контекстными данными. Для этого мы установим заголовок Content-Type как application/javascript. Это сообщит подключающимся браузерам, что содержимое тела HTTP-ответа должно рассматриваться как JavaScript. Во второй и последней строке обработчика выполняется вызов jsTemplate.Execute(w, wsAddr). Помните, как мы парсили logger.js в функции init() во время бутстрэппинга сервера? Результат был сохранен в переменной jsTemplate. Данная строка кода обрабатывает тот самый шаблон. Мы передаем ей io.Writer (в нашем случае используется w, http.ResponseWriter) и контекстные данные типа interface{}. Тип interface{} означает, что можно передать любой тип переменной, будь то строка, структура или что-то другое. В данном случае мы передаем строковую переменную wsAddr. Если вернуться назад к функции init(), то можно заметить, что эта переменная содержит адрес WebSocket-сервера и устанавливается через аргумент командной строки. Говоря кратко, она заполняет шаблон данными и записывает его как HTTP-ответ. Довольно хитро!
Мы реализовали функции-обработчики serveFile() и serveWS(). Теперь нужно только настроить маршрутизатор для сопоставления шаблонов, чтобы передавать выполнение правильному обработчику. Как и ранее, это делается в функции main(). Первый обработчик сопоставляется с URL-шаблоном /ws, выполняя функцию
serveWS для апгрейда и обработки WebSocket-соединений. Второй маршрут сопоставляется с шаблоном /k.js, выполняя функцию serveFile(). Таким образом сервер передает отрисованный JS-шаблон клиенту.
Теперь давайте этот сервер запустим. Если открыть HTML-файл, то мы увидим сообщение connection established. Оно регистрируется, так как JS-файл был успешно отрисован в браузере и запросил WebSocket-соединение. Если ввести учетные данные в элементы формы, то они будут выведены в stdout на сервере:
У нас все получилось! На выводе мы видим список всех нажатых при заполнении формы клавиш. В данном случае это набор пользовательских учетных данных. Если у вас возникли сложности, убедитесь, что передаете в качестве аргументов командной строки точные адреса. Кроме того, сам HTML-файл может нуждаться в доработке, если вы вызываете k.js с сервера, чей адрес отличен от localhost:8080.
Приведенный код можно улучшить несколькими способами. В одном из них можно логировать вывод не в терминал, а в файл или другое постоянное хранилище. Это снизит вероятность потери данных по причине закрытия окна терминала или перезапуска сервера. К тому же если ваш кейлогер регистрирует нажатия клавиш одновременно на нескольких клиентах, данные в выводе могут смешиваться, усложняя сбор и анализ учетных данных разных пользователей. Этого можно избежать, определив более эффективный формат представления, который, например, группирует нажатые клавиши по уникальному клиенту/порту.
На этом знакомство с техниками сбора учетных данных закончено. Последним мы рассмотрим мультиплексирование HTTP‑соединений C2.
Мультиплексирование C2-соединений:
В последнем разделе главы мы покажем, как мультиплексировать HTTP-соединения Meterpreter к различным бэкенд-серверам управления. Meterpreter — это популярный гибкий инструмент исполнения команд (C2), являющийся частью фреймворка Metasploit. Здесь мы не будем излишне углубляться в подробности Metasploit или Meterpreter. Если вы с ними прежде не сталкивались, рекомендуем ознакомиться с одним из множества руководств или сайтов документации.
В этом же разделе поговорим о создании обратного HTTP-прокси в Go, который позволит динамически перенаправлять входящие сессии Meterpreter на основе HTTP-заголовка Host. Именно так и работает виртуальный хостинг сайтов. Тем не менее вместо предоставления различных локальных файлов и каталогов мы будем проксировать соединение на разных слушателей Meterpreter. Это будет интересным случаем применения по нескольким причинам.
Во-первых, прокси-сервер выступает в роли переадресатора, позволяя раскрывать только имя домена и IP-адрес, но не слушателей Meterpreter. Если переадресатор вдруг попадет в черный список, можно будет легко переместить его, не перемещая C2-сервер. Во-вторых, вы можете расширить приведенные здесь концепции для выполнения доменного фронтирования, техники задействования доверенных сторонних доменов (зачастую от облачных провайдеров) для обхода ограничивающего контроля исходящего трафика. Мы не будем разбирать здесь пример детально, но вам рекомендуем изучить эту тему подробнее, поскольку это очень мощная техника. И наконец, приведенный пример показывает, как можно совместно использовать одну комбинацию «хост/порт» в команде союзников, потенциально атакуя разные целевые организации. Поскольку порты 80 и 443 — это наиболее вероятные допустимые точки выхода, можно применять прокси-сервер для их прослушивания и перенаправления соединений на правильного слушателя.
Вот наш план. Мы настроим два отдельных обратных HTTP-слушателя Meterpreter. В этом примере они будут размещаться на виртуальной машине с IP-адресом 10.0.1.20, также вполне допускается их размещение на разных хостах. Мы привяжем этих слушателей к портам 10080 и 20080 соответственно. В реальном сценарии они могут выполняться где угодно, при условии что прокси-сервер сможет связаться с их портами. Убедитесь, что у вас установлен Metasploit (в Kali Linux он установлен по умолчанию), затем запустите слушателей:
При запуске слушателя мы передаем прокси-данные как значения LHOST и LPORT. Тем не менее устанавливаем продвинутые опции ReverseListener, BindAddress и ReverseListenerBindPort на действительный IP-адрес и порт, где должен запускаться слушатель. Это дает некоторую гибкость при использовании портов, в то же время позволяя явно идентифицировать прокси-сервер, которым в случае, например, настройки фронтирования домена может быть имя хоста.
Во втором экземпляре Metasploit мы делаем то же самое для запуска дополнительного слушателя на порте 20080. Единственное отличие здесь в привязке к другому порту:
Теперь создадим обратный прокси, исчерпывающий код которого приведен в коде ниже.
Мультиплексирование Meterpreter
В первую очередь выполняется импорт пакета net/http/httputil, который содержит вспомогательную функциональность для создания обратного прокси. Это избавит вас от необходимости делать все с нуля.
После импорта пакетов определяются две переменные, которые являются картами. Первая, hostProxy, будет служить для сопоставления имен хостов с URL-адресом слушателя Metasploit, на который их нужно направлять. Вспомните, что переадресацию мы делаем на основе заголовка Host, который ваш прокси-сервер получает в HTTP-запросе. Поддержание этого сопоставления — простой способ определения мест назначения.
Вторая переменная, proxies, также будет использовать в качестве значения ключей имена хостов. Тем не менее соответствующие им значения в карте являются экземплярами *httputil.ReverseProxy. То есть эти значения будут не строковыми представлениями места назначения, а фактическими экземплярами прокси-сервера, на которые можно делать перенаправление.
Обратите внимание: данную информацию мы кодируем жестко, и это не самый удачный способ управления конфигурацией и проксирования данных. В более оптимальной реализации информация сохранялась бы во внешнем файле конфигурации, но это упражнение мы оставим вам для самостоятельной проработки.
С помощью функции init() мы определяем сопоставления между именами доменов и целевыми экземплярами Metasploit. В этом случае будем перенаправлять все запросы со значением заголовка Host, равным attacker1.com, на http://10.0.1.20:10080, а со значением attacker2.com — на http://10.0.1.20:20080. Конечно же, пока мы не делаем реальное перенаправление, а просто создаем зачаточную конфигурацию. Обратите внимание на то, что адреса назначения соответствуют значениям ReverseListenerBindAddress и ReverseListenerBindPort, которые мы использовали для слушателей Meterpreter ранее.
Далее все в той же функции init() мы перебираем карту hostProxy, делая парсинг целевых адресов для создания экземпляров net.URL. Полученный результат задействуется в качестве ввода в вызове функции httputil.NewSingleHostReverseProxy (net.URL), которая является вспомогательной функцией, создающей обратный прокси из URL. Более того, тип httputil.ReverseProxy удовлетворяет требованиям интерфейса http.Handler, то есть создаваемые экземпляры прокси можно использовать как обработчики для маршрутизатора. Делается это с помощью функции main(). Сначала создается маршрутизатор, после чего осуществляется перебор всех экземпляров прокси. Напомним, что ключ — это имя хоста, а значение имеет тип httputil.ReverseProxy. Для каждой пары «ключ/значение» карты мы добавляем в маршрутизатор функцию сопоставления. Тип Route из набора Gorilla MUX содержит такую функцию под названием Host, которая получает имя хоста для сопоставления со значениями заголовка Host входящих запросов. Для каждого имени хоста, которое нужно проверить, мы указываем маршрутизатору использовать соответствующий прокси. Это на удивление простое решение того, что в противном случае оказалось бы сложной задачей.
В завершение происходит запуск сервера и его привязка к порту 80. Сохранитесь и запустите программу. Это нужно будет сделать от имени привилегированного пользователя, поскольку привязка выполняется к привилегированному порту.
На данный момент у нас запущены два обратных HTTP-слушателя Meterpreter, а также должен работать обратный прокси-сервер. Последний шаг — генерирование тестовой полезной нагрузки для проверки его итоговой работоспособности. Для этого мы задействуем msfvenom — инструмент генерирования полезной нагрузки, который также поставляется вместе с Metasploit. С его помощью создадим два исполняемых файла Windows:
Эти команды создадут два файла с названиями payload1.exe и payload2.exe. Обратите внимание на то, что единственное различие между ними помимо самого имени заключается в значениях HttpHostHeader. Это гарантирует, что итоговая полезная нагрузка отправляет свои HTTP-запросы с конкретным значением заголовка Host. Также стоит заметить, что значения LHOST и LPORT соответствуют информации нашего обратного прокси-сервера, а не слушателей Meterpreter. Отправьте эти исполняемые файлы в систему Windows или на виртуальную машину. При их выполнении должны устанавливаться две сессии: одна в слушателе, привязанном к порту 10080, вторая в слушателе, привязанном к порту 20080. Выглядеть они должны так:
Если с помощью tcpdump или Wireshark вы проверите трафик, предназначенный для порта 10080 или 20080, то должны увидеть, что обратный прокси-сервер является единственным хостом, коммуницирующим со слушателем Metasploit. Вы также можете убедиться, что заголовок Host соответствующим образом устанавливается на attacker1.com для слушателя на порте 10080 и на attacker2.com для слушателя на порте 20080.
Вот и все. Вы справились! Теперь пора поднять планку. Я советую вам в качестве дополнительного упражнения доработать код для использования поэтапной полезной нагрузки. Это будет сопряжено с дополнительными трудностями, так как потребуется добиться того, чтобы обе стадии правильно перенаправлялись через прокси. Затем попробуйте реализовать это с помощью HTTPS вместо небезопасного HTTP. Так вы сможете глубже разобраться в проксировании трафика для вредоносных целей и повысить его эффективность.
Два человека из трех мечтают получить в подарок на Новый год технику — так показывают опросы общественного мнения. Но ведь техника бывает такой разной! Расскажите, о чем мечтаете именно вы. Представьте: разворачиваете подарок, а там…