Bollywood HungamaDil Raju calls Ranbir Kapoor ‘Ranveer Singh’ at Ramayana’s grand Hyderabad event; immediately apologizes: “Sorry, Ranbir Kapoor garu!”PunchUK unemployment rate drops unexpectedly to 4.7%The Jerusalem PostAttack on Australian politician follows years of threats to public figuresRTP DesportoSeleção. Cristiano Ronaldo com regresso marcado para novembroInquirerUnderwater search is on for Bukidnon man swept off bamboo raftCNN TürkEuroLeague'de Türk derbisi haftasıDaily MaverickWHAT’S COOKING: Pan-fried duck breasts with blueberry-cherry sauce and a touch of ginger beerZDF heuteEntdecken Sie das ZDF-NachrichtenstudioUOLPapa retoma audiência após cirurgia contra câncer no pulmãoCollider'Clayface' Director Confirms James Gunn Gave Him Complete Freedom To Reinvent GothamSouth China Morning PostEnergy shock could spark Asia’s next debt crisisThe Japan Times‘Two Cigarettes, Three Nights’ explores messy emotions and moral compromises
The Daily Newsstand · Free, Always
Tuesday, October 20, 2026

Как в официальный CLI OVHcloud подложили стилер и почему спас только прописанный хеш

Translate

19 октября в официальном CLI OVHcloud полтора часа раздавался стилер. Первым это заметил клиент OVH, у которого в CI был жёстко прописан SHA-256 одного архива. Сама OVH узнала о подмене из его отчёта: через час после подмены сборка у клиента упала, и он завёл issue #300.

Про этот случай уже написали французские СМИ и OpenSourceMalware. Я прошёл по их следам сам: GitHub API, репозитории взломанного аккаунта, блокчейн Solana. Нашлось кое-что, чего в пересказах нет.

Что произошло

ovhcloud — Go-утилита, которой управляют серверами, VPS, Public Cloud и доменами OVH из терминала. Ключи API она хранит в ~/.ovh.conf или в переменных окружения, то есть на машине разработчика или в CI.

С 15:47 до 16:12 по Москве (12:47–13:12 UTC) через аккаунт HassenBF в пяти уже выпущенных релизах, с v0.11.0 по v0.15.0, заменили бинарники. Новых версий не появилось и тегов не добавилось. GitHub Actions не запускались. Файлы просто перезалили через Releases API поверх старых, последним шёл checksums.txt, чтобы хеши на странице релиза совпадали с подменой.

Подменили не всё. Из десяти файлов релиза заменены сборки для macOS (обе), Linux x86_64 и arm64, Windows x86_64 и файл с хешами. Сборки для i386, Windows arm64 и WASM не тронули — самые редкие платформы. Это видно и сейчас: у v0.11.0–v0.15.0 на странице осталось ровно по четыре файла, остальные шесть OVH удалила.

В 17:21 по Москве (14:21 UTC) подменённые файлы удалили. Вечером вышла v0.16.0, уже с включёнными у GitHub immutable releases и аттестацией релиза. Октав Клаба, основатель OVH, написал в X, что злоумышленник воспользовался GitHub-аккаунтом одного из разработчиков, а бинарник ищет на диске секреты. Качество бинарника он назвал посредственным, но рабочим.

Почему спас только прописанный хеш

Проверка по checksums.txt из того же релиза здесь бесполезна: файл с хешами подменили вместе с архивами. Официальный install.sh не проверяет хеши вообще:

$ grep -ci 'sha256\|shasum\|hash' install.sh
0

Скрипт берёт архив по адресу releases/download/<тег>/<файл> и сразу ставит. В этом окне малварь получили все, кто запускал curl … install.sh | sh, скачивал архив со страницы релиза или тянул его в CI без своего хеша.

С Homebrew вышло иначе. Cask в ovh/homebrew-tap хранит SHA-256 каждого архива, а в окне атаки его никто не правил: последний коммит перед инцидентом — 16 сентября, к выходу v0.15.0. Хеш в нём для Linux_arm64 тот же 5c2beb56…, что был у клиента в CI. Подменённый архив brew должен был отвергнуть по несовпадению хеша.

Не задело и тех, кто собирал из исходников, ставил через go install или брал Docker-образ ovhcom/ovhcloud-cli: его OVH собирает своим конвейером из исходников.

Перезаливка архивов в старом релизе для проекта была штатной операцией. В .goreleaser.yaml так и написано:

release:
  mode: keep-existing
  replace_existing_artifacts: true

Поймал подмену пользователь alink-tothepast. В его CI был вписан хеш ovhcloud-cli_Linux_arm64.tar.gz версии 0.15.0: 5c2beb56…. После подмены архив стал 3833daff…, и сборка упала. Обновлять хеш вслепую он не стал и вытащил из нового бинарника метаданные сборки:

mod   github.com/ovh/ovhcloud-cli  v0.15.1-0.20261013083505-5ead8ef9b43d+dirty
build vcs.revision=5ead8ef9b43d354dfb5caadff803b11afc8c5c58
build vcs.modified=true

Go вшивает это в каждый бинарник. Для сравнения я скачал оригинальный архив v0.15.0 под i386, его не подменяли, и посмотрел то же самое в контейнере с Go (сам бинарник при этом не запускается):

mod   github.com/ovh/ovhcloud-cli  v0.15.0
build -trimpath=true
build vcs.revision=760fd72de93cbea3b507eb36dc0095991e4048e5
build vcs.modified=false

У настоящего релиза версия из тега, коммит 760fd72, на который указывает тег, и чистое дерево. У подмены псевдоверсия от коммита 13 октября, который вышел уже после v0.15.0, и vcs.modified=true: обычный go build в рабочей копии с незакоммиченными правками. Похоже, вредонос дописали локально: в истории репозитория его нет.

Проверить сохранившийся бинарник можно, не запуская его:

go version -m /path/to/ovhcloud

Не запускайте ovhcloud version на подозрительной копии: это и есть запуск стилера. Признак подмены — бинарник, скачанный как официальный релиз (v0.11.0–v0.15.0), в котором стоит псевдоверсия v0.15.1-0.20261013083505-5ead8ef9b43d+dirty. Если вы собирали CLI сами, такая строка ничего не значит.

Аккаунт угнали за семь месяцев до атаки

HassenBF — настоящий контрибьютор OVH: его пулреквесты есть в ovh/ovhcloud-docs и ovh/manager. Публичным членом организации он не значится, коммитов в ovhcloud-cli у него нет. Право на запись в репозиторий у аккаунта тем не менее было: без него Releases API не даёт загружать файлы. Откуда оно взялось, OVH пока не объяснила.

OpenSourceMalware заметили, что 5 марта 2026 года в личных репозиториях этого аккаунта за 42 секунды переписали историю трёх проектов. В два добавили preinstall.js и строчку "preinstall": "node preinstall.js" в package.json, в третьем тот же декодер встроили прямо в src/index.js. Шестого марта так же заразили четвёртый. Почерк GlassWorm: последний коммит подменяют через amend, автора и дату сохраняют и делают force push.

Файл до сих пор лежит в HassenBF/treasure-hunt-game. Я скачал его как текст и ничего не запускал. SHA-256 совпадает с индикатором из разбора OSM (43df42fd…). В редакторе это одна строка на 181 символ: декодер и eval. На самом деле символов в файле 9304. Остальные 9123 — невидимые variation selectors Unicode (U+FE00–U+FE0F и U+E0100–U+E01EF), каждый кодирует один байт. На ревью такой файл выглядит почти пустым.

Байты раскодировались в первый этап: AES-256-CBC, ключ и IV лежат там же открытым текстом. Я расшифровал его через openssl enc -d и получил второй этап, 4407 байт, хеш тоже совпал с разбором. Во втором этапе есть строки ru_RU, ru-RU и Europe/Moscow: на системах с русской локалью и подходящим часовым поясом загрузчик молча выходит. Адрес следующей стадии он берёт из блокчейна.

Тайник в Solana

Загрузчик опрашивает публичные RPC-узлы Solana, берёт транзакции кошелька BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC и читает поле memo у самой свежей. В memo лежит JSON с base64-ссылкой на следующую стадию. Удалить такую запись нельзя, а адрес сервера оператор меняет одной транзакцией.

Историю кошелька может посмотреть любой: вызов getSignaturesForAddress у публичного RPC. Я посмотрел:

  • 71 транзакция, в 70 из них есть memo;

  • первая 27 ноября 2025 года, последняя 29 мая 2026 года;

  • 68 записей со ссылкой на следующую стадию, одна с конфигом (25 февраля, c2server на порту 5000 и адрес для DHT) и одна чужая, о ней ниже;

  • за полгода адреса вели на 12 разных IP;

  • больше всего записей указывают на 45.32.151[.]157 (19) и 45.32.150[.]97 (11), последняя — на 137.184.198[.]91.

Самое забавное нашлось 29 мая. В 19:42 UTC в memo появилась запись {"link":"SSBrbm93IHlvdQ=="}. В base64 это «I know you». Транзакцию оплатил другой кошелёк, не тот, с которого оператор публикует ссылки. Ровно через минуту, в 19:43, оператор записал рабочую ссылку обратно.

Причина в коде загрузчика:

memo = signatures.filter(x => x?.memo)[0].memo

Отправителя он не проверяет и берёт первую попавшуюся memo. Значит, кто угодно может за пару центов подсунуть всем заражённым машинам свою запись. Кто-то так и сделал, похоже исследователь. После 29 мая записей не было: оставшиеся четыре с лишним месяца до атаки на CLI тайник никто не трогал.

Все 12 IP из истории тайника
45.32.151[.]157   19
45.32.150[.]97    11
217.69.2[.]135    10
217.69.11[.]57     9
217.69.11[.]99     6
137.184.198[.]91   5
217.69.0[.]159     3
162.33.177[.]177   2
45.77.60[.]153     1
45.76.44[.]240     1
45.32.147[.]205    1
217.69.11[.]60     1

Делал ли загрузку в CLI тот же оператор, доказать нельзя. Связывает их только общий аккаунт, а публичных копий подменённого бинарника не осталось: OVH удалила файлы, разбора самого стилера пока никто не опубликовал. Известно другое: аккаунт был скомпрометирован ещё в марте, а в октябре у него оставалось право записи в репозиторий популярного CLI.

Если вы ставили CLI 19 октября

Под удар попали машины, где с 15:47 до 17:21 по Москве ставили ovhcloud через install.sh или скачивали архив со страницы релиза: macOS, Linux x86_64/arm64, Windows x86_64. OVH просит сменить все секреты, которые лежат на диске такой машины. Кроме ключей API OVH это SSH-ключи, ~/.kube/config, .npmrc, .netrc, .env, токены других облаков. Менять их стоит с другой машины, а потом уже ставить v0.16.0. У новой версии можно проверить аттестацию:

gh release verify-asset v0.16.0 ovhcloud-cli_Linux_x86_64.tar.gz -R ovh/ovhcloud-cli

Это аттестация релиза: она подтверждает, что файл тот самый, что опубликован в неизменяемом релизе. Как именно его собрали, она не доказывает.

OVH обещает подробный постмортем «в ближайшие дни». Главные вопросы к нему: как атакующий получил доступ к аккаунту HassenBF и что с этим аккаунтом происходило между мартом и октябрём.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.