flawopen.com/Incidents/solarwinds-sunburst-build-compromise-december-2020
SUNBURST: когда уязвимостью оказался сам конвейер сборки
SUNSPOT подменил исходный код Orion при сборке, добавив SUNBURST в подписанные обновления. Подпись подтверждала источник, но не целостность кода.
Представьте надёжную слесарную фирму, которая рассылает тысячам зданий опечатанные и проштампованные наборы для обслуживания замков. Кто-то проникает на фабрику, где собирают наборы, и добавляет в каждый маленькую лишнюю деталь до того, как ставят пломбу и штамп. Каждое здание получает набор действительно от этой фирмы и устанавливает его. Пломбу никто не срывал: подделка случилась до опечатывания.
Ключевые понятия и термины
SUNSPOT- Имплант на сервере сборки, проанализированный CrowdStrike. Он отслеживал запуск MSBuild.exe для сборки Orion и на время сборки подменял исходный файл версией с бэкдором.
SUNBURST- Бэкдор, вкомпилированный в SolarWinds.Orion.Core.BusinessLayer.dll. До двух недель он бездействовал, а затем связывался с инфраструктурой злоумышленников по HTTP.
Подпись кода- Криптографическая подпись, показывающая, что двоичный файл получен от владельца ключа. Она ничего не говорит о том, была ли подделана сборка, которая его создала.
Воспроизводимая сборка- Сборка, дающая побитово одинаковый результат из одних и тех же исходников, чтобы независимые сборщики могли проверять результаты друг друга.
CWE-506- Встроенный вредоносный код. Здесь он был внедрён во время сборки у самого поставщика, а не в репозитории исходного кода.
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-506 CWE-829
- D3-OTF Фильтрация исходящего трафика — Описанное в руководстве ограничение исходящего сетевого трафика сокращает список адресов, доступных сервису или хосту.
Хронология инцидента
Злоумышленники получают доступ к среде SolarWinds; 12 сентября они внедряют тестовый код в сборку Orion, чтобы проверить работоспособность метода.
SUNBURST через SUNSPOT вкомпилирован в сборки Orion.
SolarWinds начинает рассылать исправления Orion, сама того не зная содержащие SUNBURST; среди затронутых версий — 2019.4 HF5 и 2020.2.
Злоумышленники удаляют SUNSPOT из среды сборки.
FireEye публикует анализ SUNBURST, а CISA выпускает Emergency Directive 21-01, предписывающую федеральным ведомствам отключить Orion.
Пошаговый сценарий атаки
Сервер сборки скомпрометирован
Злоумышленники получили доступ к среде сборки SolarWinds и установили SUNSPOT на сервер, компилировавший Orion.
Исходный файл подменяется посреди сборки
Увидев, что MSBuild.exe собирает решение Orion, SUNSPOT заменял InventoryManager.cs версией с бэкдором и после компиляции возвращал оригинал.
Настоящий ключ подписывает результат
Скомпилированная SolarWinds.Orion.Core.BusinessLayer.dll проходила обычный этап подписи, поэтому DLL с бэкдором несла действительную подпись SolarWinds.
Клиенты устанавливают доверенное обновление
Затронутые обновления установили менее 18 000 клиентов. Затем злоумышленники выбрали гораздо меньший круг жертв для дальнейших вторжений.
Исходный код: Уязвимый vs Защищённый вариант
Иллюстративный C#, а не конвейер SolarWinds. Уязвимое задание доверяет одному долгоживущему серверу сборки и подписывает всё, что он выдаёт, — именно этим воспользовался SUNSPOT. Защищённый шлюз требует двух сборок одного одобренного коммита на заново развёрнутых сборщиках с раздельным администрированием, сравнивает их дайджесты SHA-256 за постоянное время и отказывается подписывать при любом расхождении. Имплант на одном сборщике тогда даёт расхождение, а не подписанный релиз; защита не сработает, только если злоумышленник контролирует оба сборщика, поэтому у них не должно быть общих учётных данных и образов.
using System;
using System.Diagnostics;
public static class ReleasePipeline
{
// Сборки используют общую доступную для записи рабочую копию на сервере и подписывают
// любой результат. Изменения дерева во время сборки также попадают под подпись.
public static void BuildAndSign(string project, string outputDll)
{
using var build = Process.Start("msbuild.exe", $"\"{project}\" /p:Configuration=Release");
build!.WaitForExit();
if (build.ExitCode != 0)
throw new InvalidOperationException("build failed");
Signer.Sign(outputDll); // HSM-backed signing service client
}
}using System;
using System.IO;
using System.Security.Cryptography;
public static class ReleaseGate
{
// Два изолированных сборщика компилируют один и тот же закреплённый commit из новых копий только для чтения,
// используя /p:Deterministic=true. Этап проверки подписывает только совпадающие результаты.
public static void VerifyAndSign(string builderAOutput, string builderBOutput,
string builtCommit, string approvedCommit)
{
if (!string.Equals(builtCommit, approvedCommit, StringComparison.Ordinal))
throw new InvalidOperationException("build is not from the approved commit");
byte[] a = SHA256.HashData(File.ReadAllBytes(builderAOutput));
byte[] b = SHA256.HashData(File.ReadAllBytes(builderBOutput));
if (!CryptographicOperations.FixedTimeEquals(a, b))
throw new InvalidOperationException("independent builds differ; refusing to sign");
Signer.Sign(builderAOutput, Convert.ToHexString(a)); // digest is logged with the signature
}
}Чек-лист по защите системы для инженеров
- ✓Защищайте CI-раннеры как продуктив: они хранят исходники, секреты и ключи подписи и создают то, что запускают клиенты, поэтому им нужны изоляция, контроль доступа и журналы аудита, как у продуктивной базы данных.
- ✓Собирайте каждый релиз дважды на заново развёрнутых сборщиках с раздельным администрированием и детерминированной компиляцией, и проваливайте выпуск при расхождении дайджестов артефактов.
- ✓Не считайте действительную подпись доказательством безопасности: она подтверждает происхождение, а происхождение надёжно ровно настолько, насколько надёжна среда, где хранился ключ.
- ✓Ограничьте исходящий трафик привилегированных агентов. SUNBURST должен был достучаться до своих серверов управления, поэтому инструменты мониторинга, способные связываться с любым хостом в интернете, должны быть явным и проверенным решением.
- ✓Определяйте привилегии каждого агента поставщика исходя из того, что получит злоумышленник при его полной компрометации, а не из удобства развёртывания.
- ✓Храните телеметрию, которую злоумышленник не может изменить: только журналы вне хоста с режимом «только дописывание» позволяют потом восстановить многомесячное вторжение.
Источники
- Mandiant (FireEye) — крайне скрытный злоумышленник использует цепочку поставок SolarWinds, чтобы с помощью бэкдора SUNBURST скомпрометировать множество жертв по всему миру
- CrowdStrike — SUNSPOT: имплант в процессе сборки
- CISA — Emergency Directive 21-01: устранение последствий компрометации кода SolarWinds Orion
- Бэкдор в XZ Utils: атака на цепочку поставок, растянувшаяся на три года
- Shai-Hulud: npm-червь, публиковавший сам себя