LIMB
Вход Регистрация

тема

Приватная live-ОС: от обзора существующих дистрибутивов до создания собственного

hipeople · · 12 ответов · 1.1к просмотров

Рад всех приветствовать! Перед началом статьи задам один вопрос: ты используешь live-системы в духе Tails OS, Whonix Live или подобных? 
Если да, то наверняка сталкивался с проблемами. Вроде того что образ загружается мучительно долго пять, семь, внутри гора ненужного софта, который никогда не запустишь, зато поверхность атаки растёт

При этом для более-менее серьёзной работы система всё равно часто остаётся неудобной: пакеты часто устаревшие, кастомизация реализована через одно место, а некоторые важные вещи тот же I2P из коробки вообще отсутствуют.

Но что тогда делать? Какую live-систему выбрать? Чтобы она реально стартовала, ничего не писала на диск и содержала только самый минимум необходимого софта чтобы не плодить лишнюю поверхность атак.

В этой статье я покажу, на мой взгляд, один из самых адекватных выходов из этой ситуации. Сначала я быстро пробегусь по самым популярным приватным дистрибутивам, расскажу их сильные и слабые стороны, чтобы ты сам мог сделать вывод стоит ли использовать тот или иной live дистрибутив.
А в конце я подробно разберу, как собрать собственную минималистичную live-систему. Она будет жить исключительно в RAM и на флешке, подключаться к сети только через Tor, иметь встроенный I2P, kill-switch и ещё несколько полезных функций, о которых расскажу по ходу статьи. Что ж, не буду больше тянуть, поехали!



Популярные приватные live дистрибутивы
Сначала давай разберёмся, что такое live-системы и почему некоторые из них считаються приватными.

Концепция live-систем появилась из простой мысли: иногда нужно быстро и разово выполнить задачу на компьютере. Например, проверить наличие ошибок в основной системе или просто воспользоваться Linux без долгой установки.  Но думаю, ты прекрасно понимаешь, что периодически людям нужно не только единоразово, безобидно попользоваться Linux =). 

Бывает нужно, например, безопасно провести крипто-транзакцию, зайти на закрытый форум или просто не светить свою основную систему, занимаясь чем-то секретным.  И именно из этой идеи развились приватные live-дистрибутивы.


Как работают live системы?
Live-система это система, которая полностью загружается с флешки и работает напрямую в оперативной памяти. Всё, что происходит во время работы, хранится в tmpfs. Такой файловой системе, расположенной прямо в RAM. Благодаря этому live-режим по умолчанию не оставляет очень мало следов на вашем основном накопителе.

Из за этого например, вирусы которые мог обосноваться в твой основной системе, в большинстве случаев просто не могут проникнуть в live и наоброт. Конечно, если на аппаратном уровне уже установлен серьёзный руткит, live-система не станет волшебной защитой. Но такие угрозы на практике встречаются крайне редко, и от них почти ничего не спасает.

Но что же отличает обычную live от приватной? 
В обычной live-системе далеко не всё находится в оперативной памяти. Например, многие временные файлы, логи и даже часть системных данных могут записываться на внутренний жёсткий диск  если он доступен для записи. Кроме того, в обычной системе нет жёсткого контроля над монтированием дисков, и памяти и надёжного стирания данных при выключении.

В приватной live-системе всё должно быть устроено максималь продуманно. Такая система обязательно должна гарантировать защиту от утечек данных даже после извлечения флешки. Для этого хорошие такие дистрибутивы отключают все механизмы записи на диск (включая swap и файлы гибернации), а иногда добавляют шифрование оперативной памяти на случай cold-boot-атаки или если пользователь не сразу отключит устройство.

Главный принцип хорошей привтной live-системы это минимализм. Чем меньше софта внутри, тем меньше поверхность атаки и тем проще контролировать, что происходит. Поэтому в идеале там должен быть только тот набор инструментов, который нужен именно для твоей текущей задачи, без лишнего балласта. К примеру, один надёжный браузер с защитой от фингерпринтинга, хорошим анти-детектом и минимумом расширений почти всегда лучше, чем десяток "защищённых" браузеров на выбор. Каждый дополнительный вариант несёт свой код, свои потенциальные уязвимости и увеличивает шанс, что тебя можно будет отличить от других пользователей.

Помимо базового, многие популярные live-системы вроде Tails (о нём подробнее чуть позже) предлагают из коробки солидный арсенал против слежки: Tor как единственный шлюз в интернет, автоматическая подмена MAC-адрес при каждом старте, полное отключение swap и подкачки, блокировку утечек через DNS, , а также фичи как запрет на работу всех внешних устройств (мышь, usb, колонки и тд.), кроме тех, что были подключены до загрузки системы.


Обзор Tails OS
Первый дистрибутив о котором я расскажу это Tails OS. 

Принцип амнезии в Tails

Tails построена на принципе полной "амнезии". Это когда система специально спроектирована так, чтобы после завершения работы от неё не оставалось абсолютно никаких следов. Это работает, потому что вся ОС работает исключительно в RAM и ничего не записывает на постоянные носители. Но так ли это надёжно, как заявлено?

Мой ответ - нет, или, точнее, не совсем. Дело в том, что данные в RAM не исчезают мгновенно, а рассеиваются постепенно, что открывает дверь для cold boot-атак. Это когда злоумышленник быстро охлаждает модули памяти (например, с помощью жидкого азота) и пытается восстановить информацию из них.

Делает ли Tails что-то с этим? Да, хотя и не до конца. Чтобы максимально снизить риск, ОС использует специальный процесс стирания памяти (вроде того, как когда нужно правильно стереть данные с жёсткого диска, чтобы их нельзя было восстановить)

На сколько мне известно, раньше этот механизм был не самым надёжным: применялась утилита sdmem, которая просто несколько раз перезаписывала всю оперативную память случайными данными. Из-за этого процесс занимал много времени особенно на системах с большим объёмом RAM.

Но сейчас Tails исправил это, перейдя на более современный механизм под названием freed memory poisoning.
Механизм работает так: при нормальном выключении система активирует отравление через параметр ядра init_on_free=1, который заставляет освобождаемую RAM заполняться специальными паттернами (например, повторяющимися последовательностями вроде 0xaa55aa55). А из-за того то, что весь процесс происходит на уровне ядра, всё срабатывает гораздо быстрее, чем раньше.
В дополнение к этому, Tails добавил отравление освобождённой памяти ядра во время работы самой системы. То есть такое заполнение случайными последовательностями происходит в реальном времени для страниц, освобождаемых от данных.

Проблемы амнезии
Тем не менее, 
у Tails есть одна известная проблема: он не умеет полностью стирать видеопамять. Это давний открытый баг (тикет до сих пор не закрыт с 2013 года). При перезагрузке компьютера иногда можно заметить остатки предыдущего экрана из Tails, которые мелькают в другой ОС.
 
Такой баг возникает из-за технических ограничений: видеопамять управляется GPU отдельно от основной RAM, и для её стирания нужны специфические драйверы, которые в live-системе трудно реализовать надёжно, без риска для совместимости с разным железом. Кроме того, BIOS или UEFI продолжают активно работать с видеопамять вплоть до самого выключения или перезагрузки. Из-за этого полная перезапись изнутри ОС практически невозможна, система просто не может стереть память после того, как сама уже остановилась. При стандартном выключение видеопамять обычно со временем очищается сама, но это не всегда гарантировано и сильно зависит от аппаратной части.

Именно поэтому я сказал, что Tails не совсем справляется со стиранием памяти: такие нестёртые фрагменты видеопамяти подрывают саму идею "амнезии". Ведь если злоумышленник получит физический доступ к машине сразу после выключения, он теоретически может попытаться восстановить данные из видеопамяти. В зависимости от железа и времени, прошедшего после выключения, это может дать ему фрагменты экрана от отдельных открытых окон браузера, до почти полных скриншотов сессии. В худшем случае видны даже части веб-страниц, имена файлов, кошельки или сообщения в чатах - всё, что было на экране в момент выключения.

Но не стоит унывать: на современной памяти типа DDR3 и DDR4 данные исчезают очень быстро от нескольких миллисекунд до пары секунд без искусственного охлаждения. Поэтому разработчиками Tails рекомендуется использовать относительно новое желез.

Ещё одна проблема заключается в том, что в экстренных ситуациях пользователи часто прибегают к резкому выдергиванию флешки. 
Для удобства даже существуют (или, точнее, предлагались в концепциях) специальные аксессуары вроде "Pull The Plug Bracelet" -  это идея USB-накопителя на браслете, который легко выдернуть одной рукой.
Но это далеко не самый надёжный метод: процесс полного стирания памяти может просто не успеть запуститься или завершиться, поскольку он в основном активируется только при нормальном выключении через меню Tails (хотя и занимает всего секунды, как я упоминал выше).

Поэтому прибегать к такому нужно исключительно на свой страх и риск - в так как сработает только базовое отравление освобождённой памяти без дополнительной защиты, которое не гарантирует полное затирание всего. К примеру, оно не сотрёт свежие данные в RAM или видеопамяти, особенно если прошло мало времени после отключения.


Persistent и его недостатки
Есть ещё один важный нюанс, который думаю стоит упомянуть: 
пользователь может сам выбрать-хранить данные только в RAM или нет. И Tails это позволяет.

Да, да, ты всё верно прочитал: в Tails есть постоянное хранилище. И эта фича вроде как рушит концепцию ОС... Кхм, точнее, позволяет сохранять файлы, настройки и данные между сессиями.
Но на самом деле всё не так плохо, как могло бы быть. Постоянное хранилище создаётся как отдельный зашифрованный раздел прямо на флешке, где установлен Tails.

И как же работает это хранилище?
Для начала эту фичу нужно вообще запустить. Если пользователю не настолько важна его безупречная безопасность (но вопрос тогда зачем он тогда вообще взял live-ОС?), он должен зайти в меню и выбрать пункт Persistent Storage/
Не удалось прогрузить медиа

После выбора этого пункта Tails берёт оставшееся свободное пространство на флешке и форматирует его в зашифрованный раздел.


Дальше ты вводишь секретную фразу, которая она станет основой для мастер-ключа, и запускается процесс инициализации:
Не удалось прогрузить медиа


На этом этапе создаётся LUKS-устройство (это стандартный инструмент для дискового шифрования в Linux) и файловая система, обычно ext4:
Не удалось прогрузить медиа

Для самого шифрования используется связка LUKS с DM-Crypt это блочное шифрование прямо на уровне ядра. Кстати, если хочешь дополнительные тома, можно вручную настроить VeraCrypt, но основное хранилище всегда остаётся на LUKS. По умолчанию LUKS применяет параметры, которые считаются высоко надёжными: AES с 256-битными ключами в режиме XTS или CBC, плюс PBKDF2 для вывода ключей из твоей фразы. Точнее, в Tails 6.x и новее добавили поддержку Argon2 как альтернативы чистому PBKDF2, так что при настройке можно выбрать, что больше подходит под твою паранойю. Вкратце отличие в том, что: в Argon2 более современная KDF, которая не только жрёт CPU-время, как PBKDF2, но и требует кучи оперативки, потому она более устойчива к атакам на GPU или ASIC

При создании раздела генерируется мастер-ключ, который выводится из твоей фразы. Данные потом пишутся и читаются на лету: при записи шифруются, а при чтении дешифруются автоматически. Самое слабое звено здесь именно фраза, которую придумывает пользователь. Если она предсказуемая или слабая (типа "password123" или комбо из имён семьи), то вся цепочка рушится.

После установки ты можешь по желанию настроить, какие именно типы данных туда сохранять: например, личные файлы, GnuPG-ключи, Wi-Fi-сети, принтеры и тд.

Вот как это выглядит:
Не удалось прогрузить медиа

Ещё хранилище можно "заморозить" на определённые опции, чтобы даже при разблокировке не все данные были доступны.

Когда всё готово, при каждой загрузке Tails на экране приветствия система предложит разблокировать постоянное хранилище достаточно ввести твою секретную фразу. Если всё сойдётся, автоматически монтируется папка /live/persistence/TailsData_unlocked, где и лежат твои данные доступны как обычные файлы. Если разблокировка не прошла, ничего не происходит: Нет фич вроде "пароля под принуждением"(после ввода специальной «аварийной» фразы хранилище самоуничтожается, чтобы спасти данные от вынужденного раскрытия). А жаль, ведь такая опция идеально вписалась бы в философию Tails для допбезопасности.

Теперь моё мнение по этому поводу. Как по мне, такая фича это чистый излишество для системы, которая позиционирует себя как live-ОС с полной амнезией. Имхо, если пользователю нужно сохранять файлы между сессиями, он просто выберет другую ОС, а такие добавки просто рушат изначальную концепцию. Да, файлы там зашифрованы фразой, но как говорится, паяльник отличное средство для обхода любого шифрования =). Так что за эту фичу Tails однозначно минус. Спасибо хоть, что хранилище хотя бы обернули в шифрование, а не оставили голым.


Утилиты и приложения
Дальше расскажу, какие приложения и утилиты стоят в Tails по умолчанию и поверь, их количество и разнообразие - это отдельная большая проблема с точки зрения приватности и безопасности.

Вот что есть в Applications overview:
Не удалось прогрузить медиа

Как видно на скриншоте тут сразу куча иконок, и первое, что бросается в глаза и вызывает больше всего вопросов полный офисный пакет LibreOffice. А именно Writer, Calc, Impress, Draw, Base, Math это 5-6 отдельных ярлыков. Это огромный офисный пакет, который  имеет очень долгую историю уязвимостей. Особенно опасны макросы(VBA и LibreOffice Basic), сложный парсинг форматов MS Office вроде RTF, DOCX, XLSX, или фильтры импорта/экспорта. Там регулярно находят CVE, с открытием специально подготовленного документа которое даёт RCE или другие серьёзные дыры.

Например, возьмём CVE-2025-1080 это относительно свежая проблема от марта 2025 года. Она возникла из-за поддержки Office URI Schemes(это когда LibreOffice интегрируется с браузером для работы с SharePoint). Разработчики добавили собственную схему "vnd.libreoffice.command", чтобы поддерживать такие сценарии. Из-за ошибки в реализации злоумышленник мог создать ссылку, которая выглядела совершенно обычно, но при клике передавалась в LibreOffice, который запускал макросы с произвольными аргументами. То есть можно было выполнить любой код, который захочет атакующий.

Ещё из недавних это CVE-2025-2866. Она касается именно подделки PDF-подписей в LibreOffice. В уязвимых версиях код проверки подписей в PDF был кривой, особенно для легаси-формата с adbe.pkcs7.sha1 это старый тип подписи на базе PKCS#7 с SHA-1 хешем). Из-за ошибки в логике верификации система могла принять неверную подпись как валидную. То есть злоумышленник мог создать фейковый "подписанный" документ, который LibreOffice показывает, как легитимный.

Или CVE-2024-3044, дело в том, что, в старых версиях скрипты(макросы) считались "доверенными", потому что они встроены в сам офис и не приходят из внешнего источника. Позже их переоценили как "не очень доверенные", но код не обновили полностью. В результате, если в документе была фигура с привязанным макросом на событие "клик", скрипт срабатывал, без сообщения "Разрешить макросы?" .

В общем, думаю, моё мнение по этому поводу уже понятно. Как по мне, такой гигантский офисный пакет как LibreOffice это чистое излишество для live-системы вроде Tails. Вряд ли человеку, который запускает Tails с флешки, срочно понадобится полноценно работать с документами: создавать сложные таблицы, презентации или базы данных. А для простых действий, вроде просмотра, или лёгкого редактирования, есть гораздо более лёгкие и безопасные варианты.
Например, AbiWord - это очень текстовый редактор, который весит очень мало, парсит только самое необходимое и вообще не поддерживает макросы, сложные фильтры импорта или другие "фичи".  Или к Okular и Evince, которые отлично справляются с просмотром файлов PDF, ODT и другими, а главное не запускают ничего лишнего.
В крайнем случае, если уж очень хочется десктопный редактор с нормальной совместимостью с MS Office, то OnlyOffice Desktop выглядит заметно безопаснее LibreOffice. Там макросы отключены по умолчанию, кодовая база чище, меньше легаси, а парсинг форматов сделан аккуратнее и с меньшим количеством потенциальных дыр. Но даже его лучше не тащить в базовую live-систему, пусть будет опционально, или вообще пользователь сам его ставит на свой страх и риск.

По мимо откровенно опасного  LibreOffice есть, ещё нескольно просто бесполезных приложений, а имнно GIMP и Inkscape. Это буквально программы для рисования и редактирования графики. Зачем они на ктоят в системе, которая позиционирует себя как приватная live-ОС? Я не знаю, видимо кто то из разаработчиков любит рисовать.
А если говорить серьёзно, мне интересно, даже гипотетически что пользователь будет рисовать в Tails? Логотип для анонимного форума? Мемы для даркнета? В 99% сценариев использования Tails такие графические редакторы просто не нужны, а их наличие только раздувает поверхность атаки.
Особенно если учитывать, что кодовая база у этих программ огромная: куча плагинов, скриптов, поддержка десятков форматов изображений и векторной графики. Если открыть вредоносный файл .xcf (нативный формат GIMP), .xcf.bz2, .svg (Inkscape) можно легко словить RCE. Такие эксплойты находили не раз, особенно через уязвимые зависимости вроде libpng, libtiff, libxml или парсеры специфических форматов.

Например, в GIMP недавно было несколько серьёзных дыр. Возьмём CVE-2025-14424 в парсере XCF-файлов. Код не проверяел, существует ли объект, прежде чем выполнять над ним операции. В результате указатель остаётся "висячим" и указывает на уже освобождённую память. А злоумышленник в свою очередь мог использовать эту области памяти для атаки, например сделать .xcf-файл и после открытия его, жертва получала RCE.
Ещё была CVE-2025-5473 в парсере ICO-файлов, которая тоже приводила к RCE при открытии файла. Программа недостаточно хорошо проверяла пользовательские данные и атакующий мог подсунуть ICO с огромными значениями. Из-за этого при расчётах размеров буфера происходило переполнение, и в итоге запись выходила за пределы выделенной памяти.

С Inkscape ситуация похожая, хотя свежие полноценные RCE реже попадают в заголовки (отчасти потому, что программа менее популярна среди обычных пользователей, чем GIMP).
Но совсем недавно была CVE-2025-15523, это не прямой RCE, но серьёзное повышение привилегий на macOS. Inkscape поставляется с встроенным интерпретатором Python, который наследует TCC-права, данные приложению пользователем. В итоге злоумышленник мог запускать любые Python-скрипты от имени Inkscape. Плюс старые есть более сатрые CVE в libxml2 или librsvg (которые Inkscape использует для SVG) часто приводят к переполнению кучи или use-after-free при открытии специально сформированного векторного файла.

На скриншоте также было несколько медиаплееров и связанных с ними программ. Возникает вопрос: зачем вообще большая часть из них присутствует в Tails? Мультимедиа это явно не самая важная функциональность для такой системы.

Например, Audacity это полноценный редактор для аудио. Он умеет работать с многодорожечными проектами, применять эффекты, а ещё поддерживает разные VST-плагины и форматы. Если переводить на человеческий: у него куча фич, которые в Tails вообще никому не нужны, зато повышают поверхность атаки.

Ещё есть Sound Juicer это риппер аудио-CD из GNOME. Если кто вдруг забыл (а в наше время это уже неудивительно), рипперы это программы, которые берут звук с диска и сохраняют его в нужный формат (OGG, MP3, тд). Как нетрудно догадаться, в 2026 году это выглядит дико бесполезно. Кто сейчас вообще вставляет CD в ноут или даже имеет привод? Да, даже есть у кого-то завалялся привод, зачем использовать это в Tails? Для меня это до сих про какая-то загадка Джокера.

Дальше идёт Totem тоже дефолтный видеоплеер GNOME. Сам по себе он довольно лёгкий, но завязан на целую экосистему GStreamer. А в GStreamer, к сожалению, периодически вылазят серьёзные уязвимости. Например, CVE-2025-6663, это, по сути, RCE: тебе могут подсунуть специально сделанный файл, ты его просто откроешь и произвольный код выполняется в контексте плеера.

И напоследок нечто, что выбивается из общей бесполезной картины, это Sound Recorder, простой диктофон. С ним в принципе ещё можно смириться: кодовая база крошечная, и иногда реально может пригодиться.

Дальше идёт ещё несколько программ, на которые я бы хотел заострить внимание, хотя они чуть менее бесполезны. Например, BookletImposer для создания PDF-брошюр. Зачем, лол, если в Tails уже стоит LibreOffice, который и так умеет делать манипуляции с PDF. Хотя может это для тех, кто не хочет подставлять себя под риски из-за его использования?

Или Pidgin мессенджер, который сильно устарел, хотя в целом ещё довольно прилично работает для XMPP/OTR. Но его безопасность оставляет желать лучшего: утечки метаданных, древний код libpurple, проблемы с протоколами. Tails уже давно думает его убрать (в документации об этом пишут годами), но до сих пор не убрали видимо, ждут, пока совсем не устареет.

Но особенно хочется заострить внимание на Electrum. Это довольно плохой Bitcoin-кошелёк, хоть и с открытыми исходниками - за это ему плюс, конечно.
Так почему он плохой? Во-первых, seed-фраза не шифруются по умолчанию. Если юзер сам не поставит пароль на wallet-файл, то всё лежит в открытом виде. Но даже если шифрование включено, используется AES-256-CBC. Это сам по себе нормальный шифр, но ключ в нем выводится из пароля через двойной SHA-256 без серьёзных итераций или соли в старых версиях, а в новых PBKDF2 с относительно низким числом итераций.

Из-за этого, если у злоумышленника окажется зашифрованный wallet-файл, то брутфорс атака на слабый/средний пароль проходит довольно быстро, особенно по сравнению с современными кошельками. К примеру в нормальных альтернативах (Wasabi, Sparrow, и тд) seed шифруется по умолчанию, с хорошо серытым ключем(Argon2id, scrypt, PBKDF2 с высоким числом итераций), и вообще подход к защите seed куда серьёзнее.

Для наибольшей полноты картины кроме просмотра приложений на поверхности я вывел лог apt list --installed:
Не удалось прогрузить медиа

И увы, там тоже нашлось на что посмотреть.

Первое, что сразу бросается в глаза полная система печати CUPS со всеми либами: printer-driver-*, hplip, cups-filters, cups-daemon, cups-client. Это прямой билет в проблемы вроде PrintNightmare и его наследников. Вспомним свежую цепочку из четырёх уязвимостей 2024 года: CVE-2024-47176, CVE-2024-47076, CVE-2024-47175 и CVE-2024-47177. По сути, в ней атакующий слал специальный пакет на UDP-порт 631, а система подключается к подконтрольному принтеру. После чего когда юзер (или система) пытались что-то напечатать происходил RCE.

Ещё меня смутил hunspell с 20+ языковыми словарями. Полезно? Для кого-то да, но зачем в Tails тащить гигабайты словарей на всех языках мира, если 99% юзеров пишут максимум на 1-2?

В остальном ничего сверхкритического (по крайней мере сверх того, что я уже перечислил), я не нашёл. Но и этого, честно говоря, уже более чем достаточно.

В общем, не кажется ли тебе, что наполнение Tails будто переместилось прямиком из 2016 года в лучшем случае? Программы сплошь устаревшие, с кучей легаси-кода, который давно пора было выпилить. А минимализма, фокуса на приватности и реальных нуждах пользователя явно не хватает. Думаю, если бы разработчики всерьёз хотели сделать полезную ОС, они могли бы гораздо лучше позаботиться о составе пакетов. Потому что после всего просмотра и разбора у меня сложилось стойкое ощущение, что набор софта слепили ещё на заре проекта и с тех пор толком не трогали, просто добавляли патчи безопасности, когда уж совсем прижмёт, а старьё так и висит мёртвым грузом. Единсвенный плюс чами пакеты Tor и Tor Browser обновляются из репозиториев Debian с акцентом на самые свежие патчи безопасности. Разработчики Tails поверх этого добавляют свои доработки именно под анонимность: отключение ненужных фич, усиление изоляции и тд.


Изоляция приложений
Но Tails всё же пытается изолировать приложения, чтобы они были менее уязвимы к атакам.
 Хорошо ли это у него получается? Давай разберёмся вместе. Первое, что бросается в глаза: вместо стандартного и проверенного SELinux здесь используется система AppArmor. Это тоже инструмент для ограничения доступа процессов, но он устроен гораздо проще, чем SELinux,  но в данном случае это к лучшему.

Основная идея AppArmor профили, привязанные к конкретным файлам по их пути в файловой системе. Такие профили описывают, какие файлы, каталоги и ресурсы может использовать процесс. при установке новых программ любой доступ, не разрешённый явно в профиле, запрещён.

Профили могут быть в трёх режимах: enforce правила строго применяются, нарушение приводит к отказу в доступе и записи в лог. complain правила не блокируют действия, но фиксируют нарушения в лог. И unconfined профиль не применяется, и процесс работает без ограничений AppArmor.

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

Поэтому я решил проверить, есть ли уязвимости именно в политиках Tails. Первым делом запустил aa-status, чтобы взглянуть на список политик в целом:
Не удалось прогрузить медиа

Картина получилась интересная. Загружено 151 профиль. Самые важные вещи это tor/system_tor torbrowser_firefox с подпрофилями для OpenCL/Clang, thunderbird, onionshare и onionshare-cli, cups/cupsd, php в enforce-режиме. Ещё 36 профилей в complain. Ни одного в kill-режиме, который убивает процесс при попытке нарушения, и ни в prompt, который спрашивает пользователя. И 76 профилей в unconfined. Из всего этого можно сделать вывод, что Tails применяет enforce только к самым важным вещам, а остальное либо просто логирует, либо оставляет почти без контроля. И вот тут сразу бросилось в глаза несколько странностей.

Во-первых, среди профилей почему-то есть абсолютно левые вещи, например, политики для Opera, Edge, Chromium, Steam, Discord и кучи другого софта, которого в Tails отродясь не стояло. Да, большинство из них в unconfined или complain, но сам факт их присутствия выглядит лично для меня странным.
Во-вторых, для некоторых программ, которые в Tails реально есть и работают, профилей вообще нет. Например, отсутствуют профили для Electrum, Audacity, GIMP или Inkscape, хотя, как по мне, это довольно критичные программы.

От этого создаётся впечатление, что разработчики будто взяли готовый набор политик из какого-то большого дистрибутива и просто не почистили. Но это лишь мои домыслы, как оно выглядит со стороны решать уже тебе самому.

Но в любом случае сейчас разберу политики, которые с разработчики Tails писали самостотельно.
Начнём с положительного, а именно с профиля для Tor Browser, который настроен как один из самых параноидальных профилей во всей системе (как и положено одному из самых важных компонентов Tails).
Не удалось прогрузить медиа

Профиль torbrowser_firefox работает в enforce-режиме с флагом attach_disconnected это позволяет профилю продолжать работать, даже если процесс отсоединён от терминала.

Чтож перейдем к разрешеним, а разрешено только то, что строго необходимое. Например, полный доступ для чтения и записи исключительно к своему каталогу. Сеть тоже разрешена строго через Tor: только TCP и onion-сокеты, никаких raw, или прямых подключений.

Дальше идут IBus для ввода текста (чтобы нормально работали клавиатуры, языки и тд), плюс PulseAudio, dbus и Wayland через /dev/shm это нужно, чтобы браузер мог нормально отображаться на Wayland без крашей и глюков.

Из менее необходимого разрешен доступ к документации Tails в /usr/share/doc/tails/website/, но только для чтения. Но это буквально первая страница, которую видит пользователь при запуске.

Ещё разрешена Assistive technologyэто at-spi, система помощи людям с ограниченными возможностями: экранные читалки, увеличение, и тд. И разрешен OpenGL/Vulkan/OpenCL это позволяет браузеру использовать аппаратное ускорение для WebGL, видео и тяжёлых страниц. Но не спеши писать в комментариях, что это можно использовать для фингерпринтинга. В Tails эта api сильно урезаны, до такой степени, что не дают браузеру точно измерить GPU. Всё ограничено минимальным набором, чтобы не сломать совместимость.

Ладно, когда с разрешениями разобрались перейдем к запретам, а  запрещено тут очень много. К примеру, строго запрещено чтение /etc/passwd, /etc/group, /etc/hosts, /etc/resolv.conf, machine-id, /proc/cpuinfo, /sys/devices/system/cpu и тд. Благодаря этому у Tor Browser нет информации о CPU, модели процессора и тд, потому злоумышенник не сможет создать отпечаток устройства.

Ещё запрещён доступ к большинству /dev (кроме shm для IPC/Wayland), так как это тоже может стать мишенью для атак через устройства можно читать память, тайминги, аппаратные параметры или даже делать side-channel утечки. Запись почти куда угодно вне своего каталога тоже запрещена по понятным причинам, эксплойт не сможет ничего сохранить, модифицировать или оставить следы на диске/Persistent.

Так же нельзя отлаживать другие процессы (ptrace полностью заблокирован), и браузер не видит историю открытия файлов другими программами. И наконец, вообще запрещён доступ к /run/user/* за пределами нужного каталога . Из этого браузер не может подсмотреть, какие ещё процессы запущены, какие сокеты открыты или какие временные файлы лежат в user runtime-директории.

В общем, с таким уровнем настроек через WebGL, canvas или любой другой RCE/0-day в движке получить данные или доступ к системе почти невозможно. В случае чего эксплойт просто застрянет в очень тесном sandbox и не сможет выйти за пределы Tor-сети.

Ещё одна политика, которая скорее всего создана разработчиками Tails вручную это профили для LibreOffice:
Не удалось прогрузить медиа

Но здесь увы картина намного слабее, чем с Tor Browser. Основной процесс soffice.bin (тот самый, который реально открывает Writer, Calc, Impress, Draw, Base и всё остальное) работает в режиме complain. AppArmor только пишет в логи каждое нарушение, но ничего не блокирует. Реальной защиты от RCE почти нет если в документе сработает эксплойт (макрос, кривой RTF/DOCX/XLSX, PDF, embedded-объект, Java-апплет), атакующий получит очень широкие права внутри сессии.

Но что конкретно такого опасного разрешено в профиле soffice.bin? Для начала это полный rw-доступ почти ко всей домашней директории @{HOME}/**, /mnt, /media, Persistent Volume (кроме некоторых скрытых папок вроде .cache/fontconfig). Эксплойт может перезаписывать gpg-ключи, настройки Thunderbird/Pidgin/Electrum, закладки Tor Browser, любые файлы в Persistent и всё, что лежит в ~/ или на зашифрованном разделе.

Но если ты вдруг думаешь, что этого мало, видимо специально для эксплойта на блюдечке разрешено чтение системных файлов вроде /etc/passwd, /etc/group, /etc/nsswitch.conf, /proc/, /etc/libreoffice/*. И ты сам понимаешь, чем такое может грозить.

По мимо этого разрешён полный доступ к Java/JVM: java.security, jre/bin/java и тд, это тоже весьма опасно, и при этом не прям необходимо для работы приложения(без этого не будут работать всего лишь макросы на Java, некоторые расширения). Дальше разрешены всякие штуки вроде GStreamer, PulseAudio, Mesa/OpenGL/OpenCL, D-Bus, и тд. Ну и наконец, уже менее опасное, а именно разрешена запись в свой каталог и кэш.

Но не всё так плохо: другие компоненты LibreOffice всё-таки в enforce-режиме. xpdfimport (импорт PDF) заперт относительно нормально, разрешено только чтение нужных библиотек poppler, и минимум доступа к конфигам. Senddoc (отправка документа по почте через xdg-email) тоже enforce, и имеет минимальные права: запуск sh/bash/sed/grep/xdg-open, и доступ к конфигу LibreOffice и /dev/null. НО вот oosplash (сплеш-экран при запуске) увы в complain, и при этом может читать /etc/passwd, /etc/nsswitch.conf и другие файлы, почти без ограничений.

Кто-то может сказать: ну и что в этом такого? В Tails основной вектор атаки - браузер и onion-сервисы, а не офисный пакет, наверное, поэтому разработчики не очень заморочились, чтобы в офисе вдруг что-то не сломалось из-за слишком строгих политик.

Но если честно это всё равно плохое оправдание. LibreOffice изначально слабое место системы, потому что если уж его представили в live-ОС с фокусом на приватность, то могли бы лучше подойти к защите. А так сейчас картина такая: если вдруг в документе подцепится эксплойт, он получит доступ почти ко всему, что есть в сессии (кроме того, что дополнительно блокируют namespaces и seccomp). Да, после перезагрузки следов не останется, но, если атакующий успеет украсть ключи из памяти, скопировать файлы из Persistent или модифицировать настройки, ущерб будет очень серьёзным.

Так же интерес вызывает профиль ibus-engine-hangul:
Не удалось прогрузить медиа

Это для движка ввода Hangul (корейский язык) через IBus браузер (Firefox/Tor Browser) который может его использовать для IME, когда нужно набирать корейские символы. Он находиться в режиме complain, и имеет флаг attach_disconnected. Тоесть ничего не блокирует, а только логирует нарушения. Ну и сама защита слабая, примерно, как у soffice.bin в LibreOffice.

Что именно там разрешено? Для начала разрешены базовые абстракции, конфиги GSettings, dbus-session-strict и библиотеки Hangul. Дальше идёт чтение/запись в каталоги для карт клавиатуры и раскладок. По мимо этого Hangul имеет полный доступ к кэшу и конфигу IBus, плюс rw в /var/run/user/*/dconf/user для пользовательских настроек dconf. Ещё имеется возможность запускать ibus-демона, и читать дескрипторы файлов в /proc/@{pid}/fd.

Вроде нормальные разрешения, да? Но проблема в том, что в complain-режиме он ничего не блокирует. Потому если сработает эксплойт в IME (редко, но возможно через фишинг с корейским текстом или специально подготовленный ввод), он сможет читать/писать конфиги IBus, dconf, запускать ibus-демона. В Tails это критично, потому что IME может быть связано с вводом паролей, seed-фраз, ключей или сообщений в мессенджерах, потому всё это может попасть в кэш IBus или dconf, а оттуда утечь или быть модифицировано. Плюс attach_disconnected профиль применяется даже если процесс отсоединён от терминала, что делает его ещё более "живучим" для атак.

Да, у разработчиков есть оправдание в том, что IBus сложная штука для ограничения, там много динамики. Тем не менее, если уж не можете впихнуть нормальное ограничение не следовало хвататься за такую многоязычность в приватной live-ОС.

На сладкое разберу ещё один слабый профиль, а именно основной профиль Firefox:
Не удалось прогрузить медиа

Это очень слабый профиль он существует только для "имени" приложения, но реально позволяет почти всё. Флаги unconfined, а значит, AppArmor ничего не ограничивает программа работает как будто профиля вообще нет.

Что именно там разрешено? Абсолютно всё чтение/запись любых файлов, сеть, процессы, монтирование, capabilities и тд. Профиль включает глобальные переменные вроде @{HOME}, @{PROC}, базовые абстракции для /usr/bin, /etc и тд, плюс если есть local/firefox ,то локальные оверрайды (для сайтовых исключений или донастроек).

Профиль прикреплён к /usr/lib/firefox-*.esr (или подобным путям)  это для ESR-версии Firefox, которая лежит в системе. Проблемы здесь безопасности на лицо. Да, в Tails есть Tor Browser с жёстким профилем, но как я понимаю: если запустить обычный Firefox никакой защиты вообще не будет. Браузер сможет собрать любые отпечатки железа, если вдруг подцепится эксплойт он сможет читать /etc/passwd и другие файлы, писать в home, запускать шелл, или выходить в сеть напрямую (не через Tor). В Tails это не основной браузер, но многие юзеры могут начать использовать его по привычке, потому разумным было бы позаботиться над его политиками чуть лучше.

Поэтому мой совет не используй Firefox на Tails. Ведь даже разработчики явно не хотят, чтобы ты его использовал, поэтому не стали тратить время на строгий профиль. Впрочем, в любом случае в приватной ОС такое отношение к потенциально опасному софту выглядит странно, особенно когда профиль существует, но ничего не делает. Лучше бы вообще удалили или поставили в enforce с deny на всё, чтобы при запуске сразу вылетало Permission denied.


Защита сети
А что насчёт сети? 
В Tails, как я уже говорил, весь трафик идёт исключительно через Tor. И да, разработчики здесь действительно постарались.
Чтобы было понятнее, я сначала коротко расскажу теорию, а потом разберём, как это всё работает на практике.

Для наглядности я составил схему создания network namespaces:
Не удалось прогрузить медиа

Сразу после загрузки системы запускается скрипт tails-create-netns start. Tails создаёт пять отдельных network namespace и виртуальные интерфейсы veth для каждого из них. Например, для Tor Browser появляется пространство имён tbbNs и соответствующий интерфейс veth-tbb. Каждому namespace назначается свой IP-адрес в подсети 10.200.1.x/30, настраивается NAT и forwarding между этими пространствами и основной системой. Параллельно вызывается скрипт tails-add-session-firewall-rule, который добавляет нужные разрешения для прохождения трафика через эти veth-интерфейсы.

Позднее, когда пользователь подключается к Wi-Fi, NetworkManager запускает диспетчер 00-firewall.sh. Тот в свою очередь выполняет ferm /etc/ferm/ferm.conf. Ferm это оболочка для iptables чтобы вручную вводить множество команд. В данном случае Ferm применяет основные жёсткие правила iptables: ставит политику DROP во всех основных цепочках, включает Transparent Proxy (весь TCP-трафик перенаправляется на порт 9040, а DNS-запросы на 5353), разрешает только необходимый трафик от пользователя debian-tor и включает логирование заблокированных пакетов.

После этого срабатывает скрипт 10-tor.sh. Он перезапускает сервис [email protected], запускает tca.service (Tor Connection Assistant) и синхронизирует время через htpdate. Tor читает свою конфигурацию из /etc/tor/torrc, где включена директива UseBridges 1.

Ещё если пользователь при загрузке в tca пункт "Использовать мосты" как на скриншоте:
Не удалось прогрузить медиа

То список мостов берётся из файла /usr/share/tails/tca/default_bridges. Как только Tor успешно подключается к мостам и завершает bootstrapping, создаётся специальный флаг-файл /run/tor-has-bootstrapped/done, который сигнализирует системе, что сеть готова.

Для большей понятности ниже я подробнее разберу скрипты, которые нашёл в Tails. Скриншоты этих скриптов приводить не буду, так как на каждый из них приходится по 3-4 скриншота. Но ты можешь самостоятельно установить Tails, открыть файлы по нужным путям и убедиться в моих словах лично.

Для начала разберём основной скрипт, который отвечает за создание всех интерфейсов и network namespaces.

Это файл /usr/local/lib/tails-create-netns:
Bash:
#!/bin/bash

ns=tbbNs
guestVeth="veth0"

set -ue

increment_ip_address() {
    echo "$1" | \
    python3 -c 'base, host = input().rsplit(".", 1); print("%s.%s" % (base, int(host)+1))'
}

decrement_ip_address() {
    echo "$1" | \
    python3 -c 'base, host = input().rsplit(".", 1); print("%s.%s" % (base, int(host)-1))'
}

get_netns_guest_address() {
    ns="$1"
    ip netns exec "$ns" ip -4 a show dev "guestVeth" | grep -Po 'inet \K[\d.]+'
}

get_netns_host_address() {
    ns="$1"
    decrement_ip_address "$(get_netns_guest_address "$ns")"
}

expose() {
    if [ $# -ne 3 ]; then
        echo 'Wrong expose usage' >&2
        exit 2
    fi
    ns="$1"
    guestPort="$2"
    hostPort="$3"
    hostAddress="$(get_netns_host_address "$ns")"
    guestAddress="$(get_netns_guest_address "$ns")"
    hostVeth="veth-$ns"

    ip netns exec "$ns" iptables -t nat -A OUTPUT -o lo -d 127.0.0.1 -p tcp --dport "$guestPort" \
        -j DNAT --to-destination "$hostAddress:$hostPort"
}

expose_all() {
    ns="$1"
    hostAddress="$(get_netns_host_address "$ns")"
    guestAddress="$(get_netns_guest_address "$ns")"
    hostVeth="veth-$ns"
    netmask=30

    ip netns exec "$ns" ip route add default via "$hostAddress"

    tails-add-session-firewall-rule --apply -A FORWARD -i "$hostVeth" -j ACCEPT
    tails-add-session-firewall-rule --apply -A FORWARD -o "$hostVeth" -j ACCEPT

    sysctl net.ipv4.ip_forward=1 >/dev/null 2>&1 || true
    sysctl "net.ipv4.conf.$hostVeth.forwarding=1" >/dev/null 2>&1 || true
    ip netns exec "$ns" iptables -t nat -A POSTROUTING -s "$guestAddress/$netmask" -j MASQUERADE
}

forbid_incoming() {
    ns="$1"
    ip netns exec "$ns" iptables -P INPUT DROP
    ip netns exec "$ns" iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    ip netns exec "$ns" iptables -A INPUT -i lo -j ACCEPT
}

delete_netns() {
    basename="$1"
    nsname="$basename"
    hostVeth="veth-$basename"
    ip link del "$hostVeth" 2>/dev/null || true
    ip netns del "$nsname" 2>/dev/null || true
}

create_netns() {
    if [ $# -ne 2 ]; then
        echo "Wrong usage for create_netns" >&2
        exit 2
    fi

    basename="$1"
    hostAddress="$2"
    netmask=30
    nsName="$basename"
    hostVeth="veth-$basename"

    if [ ${#hostVeth} -ge 16 ]; then
        echo "netns name too long '$hostVeth'" >&2
        exit 2
    fi

    guestAddress="$(increment_ip_address "$hostAddress")"

    ip netns add "$nsName" 2>/dev/null || true

    ip link add "$hostVeth" type veth peer name "$guestVeth" 2>/dev/null || true

    ip link set "$guestVeth" netns "$nsName"

    ip addr add "$hostAddress/$netmask" dev "$hostVeth"
    ip link set "$hostVeth" up

    ip netns exec "$nsName" ip link set "$guestVeth" up
    ip netns exec "$nsName" ip addr add "$guestAddress/$netmask" dev "$guestVeth"
    ip netns exec "$nsName" ip link set lo up

    # forbid IP spoofing
    ip netns exec "$nsName" iptables -A OUTPUT -o veth0 ! -s "$guestAddress" -j REJECT
    ip netns exec "$nsName" sysctl net.ipv4.ip_forward=0 >/dev/null 2>&1 || true
    ip netns exec "$nsName" sysctl net.ipv4.conf.all.forwarding=0 >/dev/null 2>&1 || true
    ip netns exec "$nsName" sysctl net.ipv4.conf.lo.route_localnet=1 >/dev/null 2>&1 || true
    ip netns exec "$nsName" iptables -t nat -A POSTROUTING -j MASQUERADE
    sysctl "net.ipv4.conf.${hostVeth}.forwarding=0"
}

if [ "$1" = "stop" ]; then
    delete_netns tbb
    delete_netns onioncircs
    delete_netns tca
    delete_netns onionshare
    delete_netns clearnet
    exit
fi

if [ "$1" = "start" ]; then
    modprobe veth
    modprobe xt_MASQUERADE
    modprobe xt_nat

    netBase='10.200.1'

    create_netns tbb         "${netBase}.1"
    create_netns onioncircs  "${netBase}.5"
    create_netns tca         "${netBase}.9"
    create_netns onionshare  "${netBase}.13"
    create_netns clearnet    "${netBase}.17"

    expose tbb 9050 9050
    expose tbb 951 951
    expose onioncircs 951 951
    expose tca 951 951
    expose onionshare 9050 9050
    expose onionshare 951 951
    expose_onionshare clearnet

    forbid_incoming clearnet
fi

При запуске с параметром start скрипт создаёт пять изолированных сетевых пространств (network namespaces): tbb (для Tor Browser), onioncircs, tca, onionshare и клирнет. Для каждого пространства создаётся пара виртуальных Ethernet-интерфейсов veth. Одна сторона пары (например, veth-tbb, veth-onioncircs и тд.) остаётся в основном хосте, а вторая сторона (всегда с именем veth0) перемещается внутрь соответствующего namespace.

Каждому namespace назначается своя небольшая подсеть /30. Например, для tbb хост получает адрес 10.200.1.1, а сторона внутри namespace 10.200.1.2. Следующие пространства получают адреса со сдвигом по 4 напимер 10.200.1.5/30, 10.200.1.9/30, и тд. Это сделано для того, чтобы все пары находились в разных подсетях и уж точно не пересекались.
Внутри отдельного namespace настраивается собстенная сетевая инфраструктура: поднимается интерфейс lo, добавляется маршрут, запрещается IP-spoofing (пакеты с источником, отличным от назначенного гостевого адреса, отклоняются), отключается форвардинг внутри namespace, а также настраивается NAT-маскарадинг для исходящего трафика.

Для организации связи между хостом и namespace скрипт использует функцию expose(). Она создаёт правила DNAT внутри namespace, которые перенаправляют обращения к определённым портам (например, 9050 и 951) на соответствующие порты на хостовой стороне.

Помимо создания интерфейсов, устанавливаются строгие правила iptables: по умолчанию политика INPUT или DROP, разрешаются только соединения со статусом RELATED и ESTABLISHED, а также локальный loopback-трафик.

Функция expose_all() дополнительно настраивает forwarding и NAT для полного доступа в сеть. Она добавляет маршрут по умолчанию и разрешает форвардинг трафика с помощью скрипта tails-add-session-firewall-rule, так же  включает необходимые sysctl-параметры.

Вот код /usr/local/sbin/tails-add-session-firewall-rule:
Bash:
#!/bin/sh

set -e
set -u

if [ "${1}" = "--apply" ]; then
    APPLY=yes
    shift
else
    APPLY=no
fi

RULE="${*}"

mkdir -p /var/lib/iptables

if ! grep --silent --no-messages --line-regexp --fixed-strings -- "${RULE}" /var/lib/iptables/session-rules; then
    echo "${RULE}" >> /var/lib/iptables/session-rules
fi

if [ "${APPLY}" = "yes" ]; then
    # shellcheck disable=SC2086
    iptables ${RULE}
fi

Как я уже говорил выше, именно через скрипт tails-add-session-firewall-rule добавляются дополнительные правила iptables. Эти правила сохраняются в файл /var/lib/iptables/session-rules, чтобы их можно было автоматически применить заново при перезапуске или восстановлении firewall. Это нужно чтобы ferm в последсвии не блокировал трафик из наших вновь созданных namespaces и veth-интерфейсов.

Правило, которое добавляется в файл /var/lib/iptables/session-rules, выглядит таким образом на ip route:
Code:
-A FORWARD -i veth-clearnet -j ACCEPT
-A FORWARD -o veth-clearnet -j ACCEPT
-t nat -A POSTROUTING -s 10.200.1.18/30 -j MASQUERADE

Кстати, интересный момент: при запуске скрипта tails-create-netns с параметром stop он полностью удаляет все созданные network namespaces и соответствующие veth-интерфейсы, очищая созданную сетевую изоляцию. Для чего именно это предусмотрено, не до конца понятно, но, возможно, для диагностики или при завершении работы системы.


Что ж, мы с тобой разобрали создание сетевых интерфейсов и network namespaces, которое происходит при загрузке системы. Конечно, там есть ещё несколько service systemd, которые отвечают за запуск tails-create-netns, но разбирать код каждого из них, думаю, будет уже излишне.

Когда подключатся Wi-Fi, NetworkManager автоматически запускает все исполняемые скрипты из директории /etc/NetworkManager/dispatcher.d/, передавая им в качестве параметров имена интерфейса.

Вот код из файла /etc/NetworkManager/dispatcher.d/00-firewall.sh, который отвечает за запуск главного файла конфигурации ferm.conf:
Bash:
#!/bin/sh

set -e

if [ "$2" != "up" ]; then
    exit 0
fi

[ -x /usr/sbin/ferm ] || exit 2

/usr/sbin/ferm /etc/ferm/ferm.conf

if [ -e /var/lib/iptables/session-rules ]; then
    while read -r rule; do
        # shellcheck disable=SC2086
        iptables ${rule}
    done < /var/lib/iptables/session-rules
fi
Скрипт сначала проверяет, что событие действительно является поднятием интерфейса. Если тип события отличается от "up", скрипт сразу завершает работу. Далее он проверяет наличие исполняемого файла /usr/sbin/ferm. Если ferm отсутствует, скрипт завершается с ошибкой. После успешных проверок скрипт запускает основную конфигурацию ferm.conf. Затем он проверяет существование файла /var/lib/iptables/session-rules. Если этот файл присутствует, скрипт построчно читает все правила, которые были добавлены во время работы сессии через tails-add-session-firewall-rule и применяет их.

Ещё один важный в /etc/NetworkManager/dispatcher.d/ скрипт это 10-tor.sh.
Вот его код:

Bash:
#!/bin/sh

# We don't start Tor automatically so *this* is the time when it is supposed to start.
# when it is supposed to start.

# Import nm_is_connected()
. /usr/local/lib/tails-shell-library/network.sh

# Run only when the interface is not "lo":
if [ -z "$1" ] || [ "$1" = "lo" ]; then
    exit 0
fi

BASENAME=$(basename "$0")

if [ "$2" = "up" ]; then
    # go on, that's what this script is for
    :
elif [ "$2" = "down" ]; then
    if ! nm_is_connected; then
        echo >&2 "$BASENAME: $1 down: no network is connected, stopping " \
        "tails-tor-has-bootstrapped.target"
        /usr/bin/systemctl --no-block stop tails-tor-has-bootstrapped.target
    fi
    exit 0
else
    exit 0
fi

echo >&2 "$BASENAME: $1 up: restarting [email protected]"
systemctl restart [email protected]

echo >&2 "$BASENAME: $1 up: starting tca.service"
/usr/local/lib/run-with-user-env systemctl --user start tca.service

# To address tails#21014 we don't re-run htpdate if it already succeeded.
if [ ! -f /run/htpdate/success ]; then
    echo >&2 "$BASENAME: $1 up: restarting htpdate.service"
    systemctl --no-block restart htpdate.service
fi

# Wait until the user is done with configuring Tor
echo >&2 "$BASENAME: $1 up: waiting until Tor was configured"
until [ "$(/usr/local/lib/tor_variable get --type=conf DisableNetwork)" = "0" ]; do
    sleep 1
done

echo >&2 "$BASENAME: $1 up: Finished"
Как он работает? Сначала скрипт импортирует вспомогательные функции из /usr/local/lib/tails-shell-library/network.sh, в частности функцию nm_is_connected(). Если интерфейс это lo, скрипт сразу завершает работу. Далее он обрабатывает только события up и down.
При появление сети chfpe перезапускает системный сервис [email protected]. Это делается потому, перезапуск заставляет Tor начать новый процесс подключение к сети Tor.

Сразу после этого скрипт запускает пользовательский сервис tca.service через run-with-user-env, чтобы пользователь мог видеть и настраивать соединение с Tor через графический интерфейс.

Вот код /lib/systemd/user/tca.service:
Code:
[Unit]
Description=Tor Connection Assistant
Requires=tails-ibus-proxy.service
After=tails-ibus-proxy.service
Requires=tails-ally-bus-proxy.service
After=tails-ally-bus-proxy.service
ConditionUser=1000

[Service]
Type=notify
NotifyAccess=all
StandardError=journal
ExecStart=/usr/local/bin/tca
Restart=no

[Install]
WantedBy=default.target
Поскольку tca.service находится в директории /lib/systemd/user/, он запускается на уровне пользователя, а не системы, и работает от имени пользователя. Так что сервис имеет условие ConditionUser=1000, которое гарантирует, что он будет запущен только для основного пользователя Tails. Он также объявляет зависимости: Requires и After для сервисов tails-ibus-proxy.service и tails-ally-bus-proxy.service. Это значит, что TCA стартует только после того, как эти два прокси-сервиса (отвечающие за работу с вводом текста и системными шинами сообщений в изолированной пользовательской среде) будут успешно запущены.
В разделе [Service] лежит тип сервиса Type=notify. Благодаря ему TCA tca уведомляет systemd о своём успешном запуске и готовности через механизм уведомлений, дальше идет стандартный лог ошибок. И наконец сама команда запуска сервисаExecStart=/usr/local/bin/tca, которая просто запускает графическое приложение Tor Connection Assistant.
По мимо этого в разделе [Install] указано WantedBy=default.target, благодаря из за чего сервис автоматически становится частью пользовательского сеанса.

По мимо этого 10-tor.sh еще проверт наличее /run/htpdate/success. Если файл /run/htpdate/success ещё не существует(то есть время ещё не было синхронизировано), скрипт перезапускает сервис htpdate.service. Этот сервис кореектирует системное время через HTTPS-запросы к доверенным серверам. Это необходимо так как Tor Browser просто не будет нормально работать и устанавливать TLS-соединения.

Затем скрипт входит в цикл ожидания: он постоянно проверяет значение параметра DisableNetwork в конфигурации Tor. Пока этот параметр равен 1 (Tor отключён от сети), скрипт продолжает спать по одной секунде. Как только пользователь завершит настройку Tor в TCA и DisableNetwork станет равным 0, и цикл завершается.

Когда интерфейс отключатся (допустим юзер отключился от WiFi) скрипт проверяет, остался ли хотя бы один подключённый интерфейс с помощью nm_is_connected(). Если сеть полностью пропала, он останавливает systemd-таргет tails-tor-has-bootstrapped.target, сигнализируя системе, что Tor больше не считается загруженным.

Вот лог запуска NetworkManager:
Не удалось прогрузить медиа



И вот мы с тобой дошли до самого интересного - а именно, какие правила в ferm.conf обеспечивают полный killswitch в Tails. Что ж, погнали разбираться!
Вот код из /etc/ferm/ferm.conf:
Code:
def $amnesia_uid = 1000;

domain ip {
    table filter {

        chain log_reject {
            LOG log-prefix "Dropped outbound packet: " log-level debug log-uid;
            REJECT reject-with icmp-port-unreachable;
        }

        chain INPUT {
            policy DROP;

            mod state state (ESTABLISHED) ACCEPT;
            interface lo ACCEPT;

            interface veth-tbb saddr 10.200.1.2 daddr 10.200.1.1 proto tcp mod multiport destination-ports (9050 951) ACCEPT;
            interface veth-onioncircs saddr 10.200.1.6 daddr 10.200.1.5 proto tcp mod multiport destination-ports (951) ACCEPT;
            interface veth-tca saddr 10.200.1.10 daddr 10.200.1.9 proto tcp mod multiport destination-ports (951) ACCEPT;
            interface veth-onionshare saddr 10.200.1.14 daddr 10.200.1.13 proto tcp mod multiport destination-ports (9050 951) ACCEPT;

            interface veth-clearnet daddr 10.200.1.0/24 REJECT;
        }

        chain OUTPUT {
            policy DROP;

            mod state state (ESTABLISHED) ACCEPT;

            outerface lo {
                mod state state (RELATED) proto icmp ACCEPT;
            }

            daddr 127.0.0.1 proto tcp syn dport 9050 {
                mod owner uid-owner apt ACCEPT;
                mod owner uid-owner proxy ACCEPT;
                mod owner uid-owner nobody ACCEPT;
                mod owner uid-owner tails-upgrade-frontend ACCEPT;
            }

            daddr 127.0.0.1 proto tcp syn dport 9062 {
                mod owner uid-owner htp ACCEPT;
                mod owner uid-owner tails-upgrade-frontend ACCEPT;
            }

            daddr 127.0.0.1 proto tcp syn dport 9063 {
                mod owner uid-owner tails-iuk-get-target-file ACCEPT;
                mod owner uid-owner $amnesia_uid jump log_reject;
            }

            daddr 127.0.0.1 proto tcp dport 9052 {
                mod owner uid-owner $amnesia_uid jump log_reject;
                mod owner uid-owner root ACCEPT;
            }

            daddr 127.0.0.1 proto tcp dport 951 {
                mod owner uid-owner root ACCEPT;
            }

            daddr 127.0.0.1 proto udp dport (53 5353) {
                mod owner uid-owner $amnesia_uid ACCEPT;
                mod owner uid-owner htp ACCEPT;
                mod owner uid-owner apt jump log_reject;
                mod owner uid-owner root ACCEPT;
            }

            daddr 127.0.0.1 proto tcp syn dport 4101 {
                mod owner uid-owner Debian-gdm ACCEPT;
            }

            daddr 127.0.0.1 proto tcp syn {
                mod owner uid-owner $amnesia_uid ACCEPT;
            }

            outerface ! lo mod owner uid-owner clearnet {
                proto tcp ACCEPT;
                proto udp dport domain ACCEPT;
            }

            mod owner uid-owner debian-tor {
                proto tcp syn mod state state (NEW) ACCEPT;
                proto udp dport domain ACCEPT;
            }

            daddr (10.0.0.0/8 172.16.0.0/12 192.168.0.0/16) @subchain "lan" {
                proto tcp dport domain jump log_reject;
                proto udp dport domain jump log_reject;
                proto udp dport netbios-ns jump log_reject;
                ACCEPT;
            }

            jump log_reject;
        }

        chain FORWARD {
            policy DROP;
        }
    }

    table nat {
        chain PREROUTING {
            policy ACCEPT;
        }

        chain POSTROUTING {
            policy ACCEPT;
        }

        chain OUTPUT {
            policy ACCEPT;

            daddr 127.192.0.0/10 proto tcp REDIRECT to-ports 9040;
            daddr 127.0.0.1 proto udp dport 53 REDIRECT to-ports 5353;
        }
    }
}

domain ip6 {
    table filter {
        chain INPUT {
            policy DROP;

            interface lo saddr ::1 daddr ::1 proto tcp {
                dport 4101 ACCEPT;
                sport 4101 mod state state (ESTABLISHED) ACCEPT;
            }
        }

        chain FORWARD {
            policy DROP;
        }

        chain OUTPUT {
            policy DROP;

            outerface lo saddr ::1 daddr ::1 proto tcp {
                dport 4101 mod owner uid-owner $amnesia_uid ACCEPT;
                dport 4101 mod owner uid-owner Debian-gdm ACCEPT;
                sport 4101 mod state state (ESTABLISHED) ACCEPT;
            }

            LOG log-prefix "Dropped outbound packet: " log-level debug log-uid;
            REJECT reject-with icmp6-port-unreachable;
        }
    }
}
В таблице filter для IPv4 цепочка INPUT имеет политику DROP по умолчанию. Разрешены только уже установленные соединения и весь трафик через loopback-интерфейс. Кроме этого, добавлены правила, которые разрешают входящий трафик с veth-интерфейсов на нужные им порты (этот момент я уже описывал при разборе tails-create-netns, поэтому подробно останавливаться не буду). Из интересного: для clearnet namespace любой входящий трафик с его veth-интерфейса полностью отклоняется.

Цепочка OUTPUT самая строгая часть конфигурации, у неё тоже политика DROP. Разрешены только уже установленные соединения и трафик через localhost. Для локального трафика на порт 9050 разрешён доступ только процессам apt, proxy, nobody и tails-upgrade-frontend. На порт 9062 разрешён доступ htpdate и tails-upgrade-frontend. На порт 951 разрешён доступ только от root. А трафик на порты 9063 и 9052 блокируется с логированием.

Дальше идут правила для DNS-запросов. Они разрешены только пользователям amnesia, htpdate и root. При этом попытки apt использовать DNS специально блокируются. Порт 4101 (используется дисплейным менеджером) разрешён от пользователя debian-gdm. Весь остальной исходящий TCP-трафик от пользователя amnesia на localhost разрешён. Трафик от пользователя clearnet разрешён только по TCP и DNS (UDP 53). А для пользователя debian-tor полностью разрешены новые TCP-соединения и DNS-запросы. Кроме этого, для локальных сетей полностью запрещены DNS и NetBIOS. Всё, что не попало под предыдущие правила, отклоняется с icmp-port-unreachable.

Цепочка FORWARD имеет политику DROP и блокирует маршрутизацию трафика между интерфейсами, чтобы namespaces не могли обойти основные правила firewall.

В таблице nat в цепочке OUTPUT настроен прозрачный прокси: весь TCP-трафик, направленный на адреса из диапазона 127.192.0.0/10, перенаправляется на порт 9040. Все DNS-запросы (порт 53) перенаправляются на порт 5353 (DNSPort Tor).

Для IPv6 конфигурация ещё строже: цепочки INPUT и FORWARD имеют политику DROP, а в OUTPUT разрешён только очень ограниченный трафик - через loopback на порт 4101 для пользователей amnesia и debian-gdm.


А что насчёт torrc?
Не удалось прогрузить медиа

Для начала в конфигурации Tor настроен стандартный SocksPort на адресе 127.0.0.1:9050 с флагами IsolateDestAddr и IsolateDestPort. Эти флаги означают, что для каждого нового адреса и порта назначения Tor будет создавать отдельную цепочку. Дополнительно настроен ещё один SocksPort на порту 9062 он используется для других приложений Tails. Для подобных целей указан и ControlPort на 127.0.0.1:9052 - через него другие приложения могут управлять Tor.
Ещё есть отдельный SocksPort на порту 9063 с флагами NoIsolateDestAddr, NoIsolateDestPort и NoIsolateClientProtocol. Эти флаги отключают изоляцию и все соединения через этот порт могут использовать одни и те же цепочки Tor. Этот порт предназначен в основном для встроенного браузера и упрощает работу с Mirrorbits при скачивании обновлений. Также присутствует SocksPort на адресе 10.200.1.1:9050 с аутентификацией. Он используется для доступа из namespaces.
Кроме того, включён прозрачный прокси TransPort на 127.0.0.1:9040. DNS настроен на порту 5353. При этом Tor автоматически добавляет суффиксы. exit и .onion при разрешении имён. Дальше включена песочница Seccomp. Она нужна для дополнительной защиты: Tor работает в ограниченном режиме, что снижает риск, если в процессе Tor будет найдена уязвимость.
Также отключены предупреждения о небезопасных портах для StartTLS в почтовых клиентах. И наконец, в разделе Misc включена опция AvoidDiskWrites 1, чтобы Tor как можно меньше писал данные на диск.
Как по мне, конфигурация получилась довольно хорошая, особенно с учётом всех killswitch-настроек, о которых я рассказывал ранее.


В дополнение к хорошей конфигурации Tor и маршрутизации, Tails также поддерживает автоматические мосты. Если обычное подключение к Tor заблокировано, система сама предлагает подключиться через obfs4, meek или snowflake.
Не удалось прогрузить медиа

Вот пример текста из файла /usr/share/tails/tca/default_bridges.txt, который был у меня в версии Tails 7.5:
Code:
meek_lite 192.0.2.20:80 url=https://1603626938.rsc.cdn77.org front=www.phpmyadmin.net utls=HelloRandomizedALPN
obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbU00/0k6xYHMPW3vJXICfkMZNdkRrB63ZhL5j9dW3iRGiCx8A7mPhe5T2EDzQ35+Zw iat-mode=0
obfs4 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://1098762253.rsc.cdn77.org/ fronts=app.datapacket.com,www.datapacket.com
ice=stun:stun.epygi.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.mixvoip.com:3478,stun:stun.nextcloud.com:3478,stun:stun.bethesda.net:3478,stun:stun.nextcloud.com:443 utls=imitate-hellorandomizedalpn
snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://1098762253.rsc.cdn77.org/ fronts=app.datapacket.com,www.datapacket.com

Плюс всегда можно вручную ввести свои собственные мосты (например, из почты Tor Project).


Но что же происходит после включения kill-switch в Tails? Действительно ли он работает?
Давай разберем полную картину. Для начала вот схема, которая показывает, как работает сеть после подключения kill-switch:
Не удалось прогрузить медиа

После успешного запуска системы и загрузки конфигурации Tor ([email protected] + /etc/tor/torrc) включаются TransPort на порту 9040 и DNSPort на порту 5353. Также запускается служба tca.service, которая помогает подключиться к мостам, если обычное подключение заблокировано. Когда Tor успешно подключается к сети и завершает подключение (появляется файл /run/tor-has-bootstrapped/done), и включается полноценная защита. Все приложения в Tails работают через namespaces. А их трафик обязательно проходит через TransPort 9040 и DNSPort 5353, а затем попадает в Tor. Если Tor не смог подключиться или цепочка неожиданно упала, система полностью блокирует весь трафик. Поэтому даже если какое-то приложение или вредоносный процесс попытается соединиться с интернетом в обход Tor ничего не выйдет.


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

Tails заставляет все приложения использовать SOCKS-прокси Tor. Кроме того, для каждого уникального адреса и порта создаётся своя отдельная цепочка.

Маршрутизация в Tails тоже полностью контролируется. Вот пример:
Не удалось прогрузить медиа

Строка default via 192.168.72.120 dev wlan0 это просто локальный шлюз Wi-Fi. На самом деле весь исходящий трафик перенаправляется через виртуальные интерфейсы: veth-tbb, veth-onioncircs, veth-onionshare, veth-clearnet и другие. Каждый такой интерфейс привязан к своей отдельной цепочке Tor (или к прямому выходу в случае Unsafe Browser).

Дальше проверил правила iptables:
Не удалось прогрузить медиа

Как видно всё что было в ferm применилось.

Дополнительно я проверил состояние интерфейсов:
Не удалось прогрузить медиа

Как видно созданные tails-create-netns интерфейсы включены, а обычные еth0 и wlan0 отключины.

Для теста работоспособности kill-switch я полностью отключил сервис Tor и убил все оставшиеся процессы Tor. После этого начал проверять разные сценарии.
Сначала попробовал простой curl:
Не удалось прогрузить медиа

Сразу появилась ошибка: Could not connect to 127.0.0.1 port 9050.

Ради интереса попробовал ввести адреса отключенного tor как прокси:
Не удалось прогрузить медиа


После проверил работает ли DNS комондой  dig whoami.akamai.net @8.8.8.8:
Не удалось прогрузить медиа

Результат порадовал: connection refused. Это значит, что обычный DNS полностью заблокирован, а Tor-DNS без работающей цепочки тоже не работает.

Я специально попробовал прямые запросы к IPv6-адресам:
Не удалось прогрузить медиа

Как видно, они тоже не работают, пакеты просто отбрасываются.

Даже ICMP (пинг) не проходит:
Не удалось прогрузить медиа

В общем, в плане настройки Tor-сети и Tor Browser разработчики Tails действительно очень сильно заморочились, и с политиками AppArmor, и с конфигурацией, и с изоляцией потоков, и с kill-switch. За это им стоит отдать должное.
Поэтому я с уверенностью скажу: если ты планируешь использовать Tails исключительно для Tor Browser (хотя к самому Tor Browser у меня тоже есть отдельные вопросы, но это уже как-нибудь в следующей статье), то это один из самых безопасных вариантов на сегодняшний день.


Обзор Unsafe Browser
Но не спеши радоваться, что всё так безопасно. Если вдруг ты решишь открыть не Tor Browser, а обычный браузер (Unsafe Browser), то никакой серьёзной защиты или даже сокрытия отпечатка уже не будет.

Я специально запустил Unsafe Browser (это чистый Firefox ESR, который Tails зачем-то оставил) и открыл coveryourtracks.eff.org, вот результат:
Не удалось прогрузить медиа

Уникальность отпечатка довольно высокая от 4 до 6 бит идентифицирующей информации по разным параметрам. Например, аппаратная совпадение равно4 (число ядер или потоков CPU), разрешение экрана тоже довольно уникальное, системные шрифты вроде Arial, Courier, Helvetica, Times New Roman и другие определяются через JavaScript, а AudioContext даёт уникальный хеш примерно на 5.29 бит, HTTP заголовки тоже типичные для Linux + Firefox ESR, платформа тоже опреляется как Linux x86_64.

В about:config видно, что настройки приватности на минимальном уровне или дефолтные:
Не удалось прогрузить медиа

privacy.resistFingerprinting = false это значит, что браузер не пытается активно скрывать параметры, которые используют для создания отпечатка. Без этой настройки сайт видит разрешение экрана без принудительного сужения, реальное количество ядер CPU, объём памяти, точные шрифты, плагины, и тд. letterboxing тоже не принудительный (resistFingerprinting.letterboxing.didForceSize = false) когда resistFingerprinting включён, браузер добавляет чёрные полосы по краям окна, чтобы округлить видимое разрешение экрана до стандартных значений. Без letterboxing сайт видит реальное разрешение окна с точностью до пикселя.
По мимо этого нет подмены user agent, нет блокировки или спуфинга canvas(только randomization, но хеш всё равно уникальный), нет запрета на WebGL, нет изоляции по умолчанию.

Единственный заметный плюс время и часовой пояс всё равно скрыты на уровне системы, даже в Unsafe Browser.
Вот вывод от timedatectl:
Не удалось прогрузить медиа

Local time и Universal time в UTC, RTC time в UTC, Time zone Etc/UTC, System clock synchronized: no, NTP service: n/a. То есть Tails жёстко скрывает всё в UTC, без синхронизации с локальным временем, и это работает даже в Unsafe Browser. Сайт не получит твой настоящий timezone, который часто используют для грубого фингерпринтинга.

Кто-то может возразить:"Но Unsafe Browser нужен только для редких случаев где Tor не проходит, и зачем там скрывать отпечаток?". Логично, но мне всё равно кажется не очень разумным в анонимной системе намеренно оставлять такую большую дыру. Я не вижу сценария, где разумно одновременно сливать свой реальный IP и довольно уникальный отпечаток. Даже если это "только на минуту" это след остаётся у сайта, у провайдера, или у любого, кто мониторит портал.


Прошлые уязвимости Tails
Напоследок расскажу про уязвимости, которые Tails имел в прошлом, чтобы ты смог сформировать более чёткую картину о нём. Да, да, Tails имел уязвимости от zero-day в зависимостях до проблем с Tor.

Первым делом Tor, так как я его больше всего хвалил... кхм, так как это ключевой элемент Tails. Например, в 2022 году в Tor Browser нашли сразу два zero-day: CVE-2022-1802 и CVE-2022-1529. Оба были связаны с prototype pollution в JavaScript-движке Firefox. Это когда злоумышленник через специально подготовленный сайт может модифицировать прототипы объектов, а потом использовать это для обхода sandbox и выполнения произвольного кода. В итоге эксплойт мог читать куки, пароли из форм, историю сообщений в OnionShare или даже красть данные из расширения Tor. Пользователям Tails 5.0 официально рекомендовали не использовать браузер для важных действий (да, ты правильно прочитал: не патч, а просто "не используйте браузер, пока Tor не выкатит обнову") до выхода фикса в 5.1.

Ещё один пример в Tails могли деанонить пользователей Tor через уязвимости в OpenSSL. Совсем недавно вышла серезная уязвимость CVE-2025-15467 в обработке структур при парсинге сертификатов. Злоумышленник мог создать поддельный релей с кривым сертификатом, а когда Tails-подключённый к Tor парсил это происходило переполнение буфера на стеке. Это приводило, либо к DoS либо, в худшем случае, к RCE прямо в процессе Tor. В теории это могло помочь захватить контроль над узлом, и перенаправить трафик через подконтрольные цепочки. Из-за этого вышел emergency-релиз Tails 7.4.1 с обновлением OpenSSL и Tor. В анонсе прямо сказано, что эти уязвимости могли позволить malicious Tor relay и сдеанонить юзеров Tails, хотя на момент релиза известных эксплойтов в дикой природе не наблюдалось.

Были и аудиты кода Tor, где находили проблемы: в основном мелкие утечки памяти, неправильная обработка ошибок, потенциальные состояния гонки в многопоточном коде. Ничего критического, что бы сразу ломало анонимность. Но разработчики Tails (и Tor Project) всегда реагировали довольно оперативно, нужный фикс выходил в течение 1-2 дней после публикации CVE или отчёта.

Кстати, может ты задумывался, а почему в Tails нет I2P? Сейчас я расскажу причину. В ранних версиях 2014-2015 годов Tails по умолчанию включал I2P. Но увы, там нашли уязвимость, которая позволяла деанонимизировать пользователя при посещении специально подготовленного вредоносного сайта (через JavaScript или другие побочные каналы).  Эту zero-days нашли Exodus Intelligence и продавали их на рынке. Уязвимости работали на полностью пропатченной версии Tails 1.1, без изменений настроек. Exodus сначала публично объявила о находке в Twitter и блоге (с видео демонстрацией), не уведомив разработчиков заранее, а потом заявила, что не будет продавать эксплойты, а передаст их команде Tails для исправления.
Это вызвало скандал, и в итоге из-за этой проблемы I2P полностью вырезали из дистрибутива и так и не вернули. Лично мне кажется, это довольно странное решение особенно с учётом того, что I2P получал обновления от своих разработчиков, а его так и не вернули, к тому же Tor тоже имел серьёзные уязвимости, и его почему-то никто не вырезал.

Изоляция пакетов и дргуие векторы атак тоже не были идеальными. Совсем недавно, в Tails Upgrader нашли серьёзный баг. Из-за него злоумышленник мог подсунуть поддельное обновление, и использовать его например чтобы выполненить rce, обойти песочницу и тд. Разработчики быстро исправили эту уязвимость, но сам факт, что такое вообще оказалось возможно, пугает.

Или CVE-2022-34918 в ядре Linux давала повышение привилегий. Это проблема в подсистеме Netfilte, которая приводила к переполнению буфера в куче. Локальный атакующий (с доступом к непривилегированному пространству имён пользователя) мог получить CAP_NET_ADMIN и затем эскалировать до root-прав. В Tails это означало: если бы атакующий сначала эксплуатировал какую-то неизвестную уязвимость, например в Tor Browser, то дальше смог бы использовать этот баг ядра, чтобы захватить полный контроль. Tails выпустил emergency-релиз 5.3.1  с обновлением ядра до 5.10.127-2 именно для фикса этой уязвимости.

А в 2017 году ФБР использовала zero-day в GNOME Videos (стандартном видеоплеере в Tails) для поимки преступника. Это был случай с Брайаном Килом, который распространял вирусы для эксплуатации несовершеннолетних и тщательно скрывался через Tor. Facebook (по их словам, для защиты пользователей) наняла стороннюю компанию, которая разработала эксплойт zero-day именно в GNOME Videos. Уязвимость позволяла при просмотре специально подготовленного видео раскрыть реальный IP-адрес жертвы (через обход Tor). Эксплойт передали посреднику, а тот ФБР. С его помощью агенты получили IP, вышли на реального человека и арестовали его. Детали уязвимости так и не раскрыли публично, но патч в GNOME Videos вышел позже. Tails-команда узнала об этом постфактум через СМИ и была возмущена, что их не уведомили заранее.

Ещё раньше была возможность USB-атак. Раньше в Tails была просто жёсткая блокировка ввода с USB, но современные устройства, такие как USB Rubber Ducky, маскируются под обычную клавиатуру (HID-устройство) и при подключении автоматически "набирают" заранее запрограммированные команды с огромной скоростью. А BadUSB идёт ещё дальше: он позволяет перепрограммировать контроллер самой флешки на уровне прошивки, чтобы устройство притворялось не просто клавиатурой, а сетевой картой, звуковой картой, хранилищем или чем угодно ещё. Это обходит стандартные блокировки USB, потому что система видит не флешку, а совершенно другое устройство.

Но сейчас Tails по умолчанию вообще отключает автозагрузку и монтирование любых новых USB-устройств после старта системы (кроме тех, что уже были подключены при загрузке). Поэтому такие атаки просто не срабатывают. Устройство подключается, система его увидит, но проигнорирует. Не смонтирует как диск, или не разрешает ввод с клавиатуры без явного вмешательства пользователя.

Были возможны низкоуровневые физические атаки. Например, cold boot в ранних версиях Tails (до 2020-х). Хотя система и стирала память при выключении, это было не всегда полностью.
Но сейчас есть шифрование памяти. Tails поддерживает аппаратный уровень шифрования оперативной памяти, если процессор позволяет. Поэтому даже если извлечь чипы RAM и попытаться прочитать их содержимое на другом оборудовании, данные останутся зашифрованными, ведь ключ шифрования хранится внутри процессора и не извлекается.

Так же раньше была возможность DMA-атак: через порты вроде Thunderbolt или FireWire злоумышленник подключал устройство, которое напрямую читало или писало в память, обходя операционную систему. Tails старался блокировать такие модули ядра, но на старом железе с открытыми портами это оставалось проблемой.

А в аудите 2025 года, который провела компания Radically Open Security, нашли сразу несколько серьёзных проблем в Tails. Например, OTF-001 это повышение привилегий в системе обновлений. Злоумышленник, уже имеющий доступ к обычному пользователю amnesia, мог обмануть механизм обновлений и получить права root. После этого он мог полностью контролировать систему. Вторая проблема это OTF-002, произвольное выполнение кода в Python-скриптах Tails. Некоторые внутренние скрипты на Python неправильно обрабатывали входные данные, что позволяло вставить и запустить свой вредоносный код.  Третья это OTF-003, внедрение аргументов в компонентах GNOME. Через специально сформированные команды или файлы атакующий мог заставить графическую оболочку или приложения GNOME выполнить разные действия, для обхода ограничений.

Да, все эти уязвимости требовали, чтобы атакующий сначала каким-то образом получил доступ к учётной записи amnesia. Тем не менее, я думаю, ты понимаешь, что это всё равно очень плохо, особенно учитывая наличие компонентов в системе вроде LibreOffice и других излишеств, где вполне может возникнуть RCE.


Вывод по Tails
В общем, моё мнение по Tails довольно неоднозначное. 

С одной стороны, это действительно одна из лучших систем именно в плане защиты Tor-сети и Tor Browser. 
Разработчики очень серьёзно подошли к изоляции трафика: есть kill-switch, мосты, строгие политики маршрутизации и многое другое. Также они активно борются с физическими атаками, например заблокировали USB, постарались над защитой от cold boot и других низкоуровневых угроз.

Но, с другой стороны, в Tails полно ненужных излишеств и попыток усидеть на всех стульях сразу. Например, система включает кучу лишних приложений вроде LibreOffice, GIMP и других, которые открывают дополнительные векторы атак. Ещё Tails имеет совершенно бесполезные функции вроде Persistent Storage (она делает систему уязвимее к тому же оставляет данные на диске). Или Unsafe Browser, который полностью сливает отпечатки, IP и кучу других данных, от чего его наличие в такой параноидальной ОС выглядит довольно странно.
Ещё одна проблема в том, что в Tails практически нет "защиты от дурака". Если пользователь сам установит Firefox, Chrome или любой другой браузер, система его вообще его не ограничит. AppArmor-политики на такие приложения просто ничего не делают, открывая пути для атак.

Мои мысли на счет улучшения Tails
По-моему, Tails стал бы в тысячу раз лучше и безопаснее, если бы разработчики выпустили не один, а несколько отдельных образов с отдельной специализацией и максимальным минимализмом. Например: один чисто для серфинга через Tor Browser: минимум программ, максимальная изоляция, без LibreOffice, без Unsafe Browser, без Persistent по умолчанию. Другой для журналистов и активистов: офисные программы (может, не LibreOffice, а что-то более лёгкое и с жёсткими политиками), но без лишних сетевых утилит. Третий для крипто-кошельков и безопасного обмена файлами: с актуальными клиентами для Monero или Bitcoin, без браузеров и офисов.

Мне кажется, только так каждый случай получал бы свою, максимально заточенную защиту. А сейчас Tails это универсальный инструмент, который пытается быть всем для всех и в итоге ни в одном сценарии не даёт по-настоящему выдающейся безопасности (разве что при использовании исключительно Tor Browser).
Впрочем, это только моё личное мнение. А своё ты можешь выразить в комментариях.



Whonix live
Дальше я расскажу про Whonix. Кто-то может сказать, что это система совсем про другое и её принцип защиты в больше про разение сети, а не какой-то live режим. И в чём-то он даже будет прав, но тем не менее у Whonix есть вполне популярный live-режим, который, думаю, стоит кратко разобрать.

Общаяя архетектура
Архитектура и обычного, и live Whonix всегда строится на двух отдельных частях. Первая это Whonix-Gateway, по сути, шлюз, где всё соединение идёт через Tor с жёстким kill-switch: если Tor упал, трафик просто не проходит. Вторая часть это Whonix-Workstation, основная рабочая машина. У неё нет доступа к интернету: сетевой интерфейс смотрит исключительно на внутреннюю виртуальную сеть, ведущую к Gateway (обычно подсеть вроде 10.152.152.0/24). А сама подсеть создаётся внутри виртуальной машины, потому изолирована физически. Workstation даже не знает реального IP, DNS-серверов или родного MAC-адреса. Потому даже если вдруг внутри Workstation заведётся вирус, он не сможет физически добраться до твоего настоящего IP и слить его куда-то.

Архетектура Whonix Live
Поскольку мы сами разбираем именно live-системы, я не вижу смысла в глубоком разборе persistent-режима Whonix, и лучше затронуть внимание исключительно на live и его нюансах
 (но, если захочешь, можешь написать в комментариях, и я сделаю отдельный обзор на Whonix, там много чего можно рассказать, сделаю такой же разбор как с tails).

Whonix Live это специальный режим, который добавляет амнезийные свойства системе. Обычный Whonix по умолчанию загружается в persistent-режиме, где всё сохраняется на диске (и это рекомендуется для большинства пользователей, потому что так проще обновляться, держать стабильные Tor Entry Guards, и тд). А Live-режим это просто опциональная возможность, которую можно включить при загрузке через boot-меню (или настройку виртуальной машины). Когда ты выбираешь live mode, система работает так, что все изменения и данные пишутся только в оперативную память, а после выключения или перезагрузки всё стирается.

То есть да, ты правильно понял: такую "live-систему" даже нельзя загрузить с флешки в классическом понимании, как Tails, по сути, это та же виртуалка, но более приватная в плане следов на диске.

Точнее, я немного слукавил: на флешку Whonix Live поставить можно через Whonix-Host. Для этого нужно скачать ISO на флешку и загрузиться в live-режим. Потом внутри этого хоста на флешке нужно запустить вируталку и испортировать туда Whonix-Gateway + Workstation как VM. Но согласись это очень большой костыль. Который ещё и требует много RAM (особенно если Gateway и Workstation оба в live), работает очень медленно, ещё и может глючить с обновлениями (потому что в чистом live каждый раз пакеты скачиваються заново). Ещё есть экспериментальные способы: например, с OverlayFS в Qubes(но в Qubes-Whonix live-режим официально недоступен, там вместо этого disposable VM), или hidden VM с ручной настройкой. Но всё это требует доработки руками.

Кстати, про ручную доработку она требуется даже в "стандартном" live-режиме Whonix, чтобы он работал нормально. Разработчики рекомендуют вручную делать диск read-only прямо в настройках гипервизора. Без этого live-режим работает криво: данные могут просачиваться на диск (swap, tmpfs, логи), особенно если гипервизор не настроен идеально. Для Gateway в live это вообще лучще запускать только со второго запуска: при первом Tor кэширует важные данные, а если диск read-only сразу, то Tor просто может не запуститься нормально. Поэтому официально советуют: первый запуск Gateway делать в persistent-режиме (чтобы Tor настроился), потом уже переключаться на live для амнезийных сессий.

Из того, что я уже описал, ясно, что live-режим Whonix сильно зависит от того, поддерживает ли хост-ОС или гипервизор такую загрузку. Часто это реализуется через Host Live Mode на базе Kicksecure (grub-live с оверлеем в RAM), но полноценно "из коробки" это не работает как в том же Tails. Даже сами разработчики честно признают в документации, что они не эксперты в чистой анти-форензике, да и полная амнезия в виртуальной машине всё равно ограничена поведением хоста, которое они не могут контролировать.

Вывод про Whonix Live
В общем, моё мнение: 
Whonix Live это один большой костыль, сделанный будто в спешке разработчиками для тех, кто хочет, чтобы данные из его виртуалки не писались на диск. Потому Whonix Live лучше вообще не использовать, а брать стандартный persistent Whonix(с LUKS-шифрованием и стабильными Entry Guards) или Whonix в Qubes. А если нужна именно классическая live-система на флешке, то рассмотреть другие варианты.

Но разработчиков я в принципе могу понять: в такой системе, как Whonix, live-режим совсем не к месту, и я бы очень удивился, если бы получилась хорошая реализация без полной перестройки логики проекта.  Тем не менее, зачем с такими вводными вообще было делать live-режим? И вот этот вопрос для меня так и остаётся открытым.



Cyrethium Linux

Дисклеймер:

В этом разделе я буду не просто обсирать ноунейм-дистрибутив, который никому не интересен(хотя и без этого не обойдётся). Основаня цель раздела показать максимально не стоит, как делать свой live-ОС .

Дальше разберу довольно спорный (мягко говоря) live-дистрибутив Cyrethium Linux, который позиционируется как "ориентированный на приватность и безопасность". Это типичный Debian-based проект, в который авторы накидали просто огромное количество всевозможных инструментов "для приватности" по сути аналог Kali Linux, только вместо пентест-софта тут "приватные" утилиты.

Дистрибутив выпускается в нескольких редакциях, чтобы попытаться угодить разным людям. Есть тяжёлая Full-версия, напичканная всем подряд от Tor-форсирования всего трафика до кучи дополнительных оверлеев вроде I2P, DNSCrypt и прочего. Есть более лёгкая Lite-вариант, который должен быть дружелюбнее к новичкам и слабому железу. Плюс пара ре-спинов с разными окружениями рабочего стола, классический MATE и более свежий GNOME, чтобы каждый мог выбрать по вкусу.

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

Если сравнивать с тем же Tails, разница довольно ощутимая: в Tails практически всё уже настроено из коробки запускаешь и сразу получаешь достаточно надёжную анонимность без лишних телодвижений. А в Cyrethium тебе дают кучу предустановленных программ, а дальше сам разбирайся, что и как включать, комбинировать и настраивать под свой нужный уровень паранойи.

Звучит как нечто, что немного противоречит классической концепции приватных live-систем, не так ли? Но, в любом случае, может, я слишком строг? Сейчас с тобой и разберёмся.

Для начала Cyrethium умеет не только классически грузиться как live-образ с флешки, но и имеет инсталлятор Calamares, так что при желании можно поставить его на диск как полноценную систему. Но ничего страшного, это же не повлияет на работу live-режима, правда? Правда ведь...?


Хранение данных
Для начала расскажу про один из самых важных аспектов для любой live-ОС хранение данных.
 И вот тут уже начинаются первые проблемы. В отличие от чисто амнезийных систем вроде Tails, Cyrethium не заставляет всё исчезать при выключении. Точнее, стирать данные можно, но не по умолчанию.

Сам по себе Cyrethium поддерживает persistence на USB, через сохранения данных между перезагрузками на отдельном зашифрованном разделе флешки. Ты можешь включить его при создании загрузочной флешки или позже через GUI-инструмент. Но если persistence не включён, то по умолчанию работает обычный live-режим: всё в RAM, после выключения данные пропадают. Однако здесь нет автоматического шифрования RAM, нет принудительного стирания памяти при shutdown, нет защиты от cold-boot атак. Просто "данные не сохраняется на диск", и всё.

В системе есть несколько опциональных инструментов и режимов, которые могут помочь в минимизации следов и стирании данных. Первый shredder, который позволяет вручную затирать свободное пространство, временные файлы, кэш браузера, историю и тд. Второй secure-delete набор утилит, которые стирают файлы, заполняют свободное место нулями или случайными данными, очищают swap. Их можно запускать из терминала вручную.

Есть ещё режим "wipe RAM on shutdown" это скрипт, который при выключении пытается перезаписать оперативку случайными данными, но он опциональный, требует ручной настройки и работает не на всех машинах (зависит от железа и объёма RAM). Ещё в этой ОС, как заявлено, есть "амнезийные" браузеры они якобы не сохраняют куки, историю, кэш и тд.

Но насколько это правда? Не на много. Я проверил кэш во время работы Amnesic Firefox:
Не удалось прогрузить медиа

Когда я заглянул в ~/.cache/mozilla/firefox во время его работы размер был 117 МБ, а после закрытия 82 МБ. Это действительно меньше, но точно не полное стирание. Так же я проверил ~/.mozilla и его размер вообще не уменьшился, а storage/default (хранилище сайтов) даже увеличился. Вот и думайте, хороша ли здесь амнезия? Впрочем, наверное, тут и думать не надо =)


А как насчёт шифрования?
Тут ситуация тоже спорная. 
При установке на диск система использует стандартные файловые системы Linux, чаще всего ext4. Это обычная файловая система без встроенного шифрования по умолчанию. Но во время установки через Calamares можно выбрать опцию LUKS. Если ты её выбираешь, весь диск шифруется с помощью dm-crypt + LUKS. Алгоритм шифрования обычно AES-256 в режиме XTS (по умолчанию в современных Debian-based дистрибутивах).

Но в live-режиме шифрования по умолчанию нет вообще. Да, ты верно понял здесь нет даже автоматического шифрования оперативной памяти. Так же нет принудительного стирания swap (если он вдруг включится), и нет защиты от DMA-атак через Thunderbolt/FireWire (если железо позволяет). На DDR4/5 память угасает быстро, но на старом железе или при cold-boot атаке остатки могут сохраняться дольше.

Но не стоит унывать (шутка, не стоит использовать эту ОС)! Кроме базового LUKS, который в live-режиме недоступен, есть ещё разные встроенные утилитки для шифрования отдельных файлов. Например, Crypted Notes для зашифрованных заметок. Шифрование там на Fernet (AES-256-CBC) + PBKDF2 для вывода ключа из пароля.

Есть также VeraCrypt (предустановлен) для создания зашифрованных контейнеров или шифрования отдельных разделов флешки. Плюс есть gnome-disks с GUI для LUKS, cryptsetup в терминале, и даже простой скрипт для быстрого создания зашифрованного архива 7z с AES-256. Но всё это работает на уровне отдельных программ и на защиту системы в целом абсолютно никак не влияет.

В общем, на надёжное шифрование в Cyrethium надеяться не стоит. Можно, конечно, настроить его самостоятельно, но разве это не противоречит концепции live-ОС, где всё должно быть преднастроено и под рукой? Впрочем, выбор как всегда на стороне самого юзера.


Программы и утилиты
Теперь разберу программы и поверьте, тут этого добра очень много. Так много, что даже не верится, что это live-ОС... И думаю, ты понимаешь, насколько это сильно повышает вектор атак.

Для начала расскажу про то, что доступно в MATE-интерфейсе.
Первым делом затрону всё, что связано с криптовалютами:
Не удалось прогрузить медиа

Первое, что бросается в глаза, это Electrum Bitcoin Wallet. К нему я уже высказывал претензии, когда разбирал Tails: отсутствие шифрования seed-фразы по умолчанию (даже при установке пароля на wallet-файл шифрование слабое всего лишь AES-256-CBC с низким числом итераций).

Дальше Monero CLI к нему у меня особых претензий нет, кроме того, что для полной работы ему нужно довольно долго синхронизироваться с сетью (часы или даже дни на слабом железе). И я не знаю, насколько это вообще целесообразно в live-ОС, где ты не хочешь оставлять огромные объёмы данных в RAM или swap, да и используют такие ОС не настолько долго.

Ещё из той же серии есть Monerothium, который почти копирует функции Monero CLI, но работает через Tor. В нём можно создавать, открывать, восстанавливать кошельки, смотреть баланс, адреса, транзакции, отправлять XMR, генерировать субадреса и интегрированные адреса, проверять платежи и тд. Есть даже функции вроде "Make Donation For Monero" и адресной книги.
Опасность этого всего в том, что любой дополнительный кошелёк — это лишний код, который держит приватные ключи и seed в памяти. К тому же Monerothium довольно нишевый инструмент, и у таких проектов аудит обычно слабый или отсутствует. Если в нём есть баг, то возможен RCE или утечка фразы прямо в момент работы. Плюс он сам подчёркивает: "WARNING: Risky to continue without Tor connection!" то есть без Tor твой IP вполне может утечь. Это довольно опасно с учётом изначального отсутствия жёсткого kill-switch в системе.

После идут генераторы кошельков и конвертеры ключей: Cyrethium Paper Wallet Generator и Private Key Converter. На мой взгляд, это вообще не нужно в live-системе. Какой человек в здравом уме будет генерировать новый кошелёк прямо на неизвестной live-ОС, а не до использования? К тому же такая генерация просто не очень безопасна лишние данные в RAM. Особенно с учётом того, что в этой системе даже нет нормальной защиты RAM от cold-boot или дампа памяти.

Дальше разные мониторинги балансов, валидаторы адресов и анализаторы приватности: Coin Watch, Balance Checker, Address Validator, Crypto Privacy Analyzer. Полезно ли это? В теории да. Но не в live-ОС. Каждый такой инструмент тянет сетевые запросы, хранит историю проверок, может логировать IP (даже через Tor) и оставлять следы в кэше.

И наконец Key Backup как по мне вообще не понятно зачем он. Программа для создания резервных копий приватных ключей и seed-фраз. Но зачем хранить бэкапы на системе, которая по идее должна всё стирать после выключения? Это может иметь смысл на persistent-системе, но точно не в live.

Пойдёмте дальше, а именно в программы для приватности:
Не удалось прогрузить медиа

Первым делом Anti-Exploit Suite. Это самописный "антивирус", который сканирует систему на разные типы эксплойтов и атак (около 10 модулей). Написан на Python/Bash, без глубокого аудита. Если в нём баг например, в парсере crontab, запуске команд или обработке вывода возможен RCE или ложные срабатывания, которые заставят пользователя отключить защиту. Плюс он добавляет overhead (CPU/RAM при сканах). В live-системе это лишний код: вирусы и так не должны туда попасть, а даже если попадут система не постоянная, они не поселяются на диск и не так критичны.

Так же есть System Knight как ещё один "антивирус" для детекта руткитов. Он имеет же проблемы: самописный, риски ложных позитивов/негативов, может пропустить реальный rootkit или пометить легитимный процесс. Да и не необходим в live-режиме.

Теперь Paranoia как инструмент для изоляции сети. Он одним кликом блокирует все внешние соединения (iptables/nftables drop all). Это полезно в экстренной ситуации, чтобы быстро обрезать интернет при подозрении на утечку. К нему претензий нет, хотя не очень понятно, почему нельзя установить такое правило вручную. Но в целом одна из немногих действительно полезных фич.

Дальше Plaztek sandbox на базе bwrap. Он помогает запускать приложения в изолированной среде с ограничением доступа к файлам, сети и устройствам по кастомным правилам. Bubblewrap сам по себе надёжен (используется в Flatpak), но правила от разработчиков Cyrethium могут быть слабыми. Ведь как мы с тобой уже видели разработчики не очень хорошо пишут конфиги и политики.

После идет SHA256 Checksum Verifier который проверяет хэши файлов. Это полезно, но в live-режиме не очень понятно, что именно проверять. Обычно юзер верифицирует ISO перед флешингом, а внутри live это уже не так актуально.

Есть и инструменты для блокировки новых USB-устройств после загрузки: USB Guard и USB Toolkit. Это помогает против BadUSB и rubber ducky атак. Но только если конфиги правильные. Настраивать вручную долго, легко ошибиться а значит в live это тоже не очень целесообразно.

Дальше SecDNSChanger, Cyrethium DNSChanger и DNSCrypt-Proxy которые меняют DNS на DoH/DoT/DNSCrypt. Хорошая идея, но без предустановленных надёжных серверов и автоматической настройки смысла мало. Юзеру нужно самому подбирать серверы, проверять их, настраивать -а в live-системе, где всё должно быть готово из коробки, это выглядит странно.

Тоже самое с Change MAC и Change Hostname. Первый меняет меняет MAC-адрес, а второй hostname. Это хорошо для анонимности, но опять же не вручную, так как человек легко может забыть о таких инструментах или не верно их настроить. Потому без автозапуска и ротации при каждой загрузке подобное теряет смысл.

И наконец идет Secure Eraser, для безопасногр удаления файлов (перезапись несколькими проходами). Тут меня смущает что на SSD это работает плохо (TRIM и wear-leveling мешают), а в RAM-диске вообще бессмысленно.

Теперь сетевые инструменты:
Не удалось прогрузить медиа

Здесь есть I2P Router Menu, Cyrethium Tor Router и прочие утилиты звучит солидно, дополнительные слои анонимности всегда плюс. Но даже тут разработчики умудрились обложаться.

Для начала я проверил, какая версия I2P используется:
Не удалось прогрузить медиа

Смотри вывод показал огромный Java-процесс с кучей JAR-файлов. Это заначит что в Cyrethium стоит именно Java-версия (полноценный I2P router), а не лёгкий и более безопасный C++-вариант i2pd.

Почему это плохо?
Во-первых, Java сама по себе -это огромная поверхность атаки: JVM с кучей библиотек, класслоадерами, reflection, динамической компиляцией и garbage collector. В прошлом в Java-версии I2P были уязвимости вроде CVE-2020-26919 (RCE через специально сформированные пакеты), проблемы с десериализацией объектов, утечками памяти и тд. C++-версия же гораздо легче, быстрее, потребляет меньше памяти и имеет меньшую поверхность атак. Плюс i2pd написан на современном C++ и проходит регулярные аудиты, а в последние годы даже улучшил криптографию (переход на более современные примитивы). Не понимаю, почему разработчики Cyrethium не поставили i2pd это было бы логичнее и безопаснее для live-системы.

Впрочем, может быть, не всё так плохо и они хотя бы нормально настроили конфигурацию? Конечно нет!
Смотри, что в файлах i2p/i2ptunnel.config.d:

Не удалось прогрузить медиа

I2P здесь работает стандартно, то есть запускается как демон и создаёт туннели для разных сервисов. В конфигах есть куча преднастроенных туннелей: HTTP Proxy HTTPS Proxy, IRC2P, GitSSH, SAM Bridge, Jetty, Postman SMTP/POP и тд. Каждый туннель это отдельный inbound/outbound канал, который маршрутизирует трафик через I2P-сеть. Например, HTTP Proxy слушает на 4444, и перенаправляет запросы в I2P, а outbound туннель идёт через несколько peers. Всё это работает через I2CP на localhost:7654, где Java-демон общается с приложениями.

А теперь то, что меня смущает в этой конфигурации. Для начала listenPort=6668, 7670, 7654 и тд. Это множество открытых портов на localhost добавляет поверхности атаки. Если в системе есть баг или RCE, который позволит выйти из sandbox'а, эти порты становятся точкой входа для локальных атак (например, через unix socket или TCP на 127.0.0.1).
Так же сомнительная опция option.i2cp.closeIdleTime=1800000 в некоторых туннелях это довольно долго держит idle-соединения 30 минут). Что сильно увеличивает окно для side-channel и timing-атак, особенно если кто-то мониторит трафик. Ещё проблема option.i2cp.newDestOnResume=false это значит что i2p не меняет destination при resume. Что удобно для стабильности, но если сессия переименовывается после компрометации, из за этого атакующий может продолжить работу в старой цепочке.
Ещё один огоромный минус в том что сами туннели в конфиге короткие (outbound.length=3, inbound.length=3) всего 3 хопа. Это ускоряет работу сети, но сильно снижает анонимность против глобальных атак. Логичнее было бы сделать длину хотя бы 4-6 по умолчанию, как рекомендуют в I2P.
Ещё одина проьлема- sharedClients=true/false в разных туннелях. Это значит, что часть туннелей использует shared clients что уменьшается количество уникальных leaseSet, и корреляция по времени/трафику становится проще. В идеале для максимальной анонимности каждый туннель должен иметь отдельный client.
И на последок leaseSetEncType=4 это довольно старый тип шифрования leaseSet (ElGamal 2048). В новых версиях I2P рекомендуют ECIES или AES+ECIES, потому что ElGamal устарел и теоретически уязвим к квантовым атакам в будущем. Сейчас это не так критично, но разработчики могли бы последовать официальным рекомендациям.
В общем, конфиги I2P в Cyrethium выглядят будто разработчики Cyrethium взяли какие-то старые конфиги с GitHub и закинули себе в ОС без серьёзной модификации.

Дальше в меню идут программы для шифрования:
Не удалось прогрузить медиа

Первая программа это Crypted Notes простое приложение для зашифрованных заметок на Fernet (AES-256-CBC + PBKDF2). Опасность в том, что заметки и пароль держатся в памяти в открытом виде во время работы. Если в приложении есть баг (а это нишевый инструмент, аудит минимальный), можно вытащить пароль или расшифрованный текст прямо из RAM. В live-режиме без принудительного wipe RAM это остаётся в памяти до выключения.
Теперь Fangbull Crypt и FastCrypt это инструменты для создания зашифрованных контейнеров/архивов. Главный риск скорость. Чтобы быть быстрыми, они часто используют слабые параметры (мало итераций PBKDF2, короткий salt, иногда AES-128 вместо 256). Если пароль слабый то возможен взлом становится реальным. Плюс во время шифрования/расшифрования большие объёмы данных находятся в незашифрованной памяти, что опасно при cold-boot или если система скомпрометирована.
И наконец Riki ещё один шифровальный инструмент. Как и остальные, он работает в памяти без дополнительной защиты. Основная проблема всех таких программ в Cyrethium они не интегрированы с системным шифрованием RAM и не вызывают принудительное стирание памяти при закрытии. Потому ключи и расшифрованные данные могут остаться в RAM дольше, чем нужно.

Теперь офисы - на первый взгляд всё выглядит довольно скудно, что верно для live-ОС:
Не удалось прогрузить медиа

В меню есть только минималистичные просмотрщики: MATE Image Viewer, Atril Document Viewer и Document Viewer. Это довольно маленькие просмотрщики без всяких макросов, странных плагинов и подобного.
И казалось бы, всё хорошо нет тяжёлого LibreOffice, нет векторов атак через макросы, RTF, сложные фильтры импорта и тд. Но нет, мой наивный читатель, в Cyrethium всё не может быть хорошо и это стоит взять за правило.

Для дополнительной проверки я воспользовался инструментом отображения пакетов Synaptic:
Не удалось прогрузить медиа

И через него отчётливо видно, что все пакеты LibreOffice полностью установлены: libreoffice-core, libreoffice-writer, libreoffice-calc, libreoffice-impress, libreoffice-draw, libreoffice-base, libreoffice-math и все зависимости (включая Java, Python, GTK/Qt и т.д.). Они просто не отображаются в меню. Но если файл .odt, .docx, .xlsx, .pptx или любой другой офисный формат случайно откроется через xdg-open или mime-тип LibreOffice подхватится автоматически и запустится со всеми своими дырами. Эти дыры я подробно описал ранее в разделе про Tails, и не вижу нужды повторяться.

С каждой дополнительной проверкой я всё дальше от понимания логики разработчиков... То есть они зачем-то решили убрать LibreOffice из меню, чтобы юзер не запускал случайно, но оставили все пакеты в системе. Зачем? А просто так! Это худший вариант: нет удобства (нельзя открыть документ нормально без ручного вызова), но есть вся поверхность атаки. Почему просто нельзя было выпилить этот пакет для меня остаётся загадкой.

Дальше в меню раздел Internet:
Не удалось прогрузить медиа

Там есть абсолютно не преднастроенный и оттого бесполезный OnionShare он лежит в системе, но без нормальной интеграции с Tor (нужно вручную запускать, настраивать onion-сервис, порт и тд.), а в live-режиме это вообще геморрой: каждый раз генерируется новый .onion, нет persistence для ключей, потому если сессия упадёт то ip может утечь в сеть. Дальше qTox в целом нормальный мессенджер на Tox-протоколе (P2P, без серверов, end-to-end шифрование), но с постоянными багами при общении: задержки, потеря сообщений при плохом соединении, или двух версиях акаунта на разных устройствах. Ещё там переодически ьывают уязвимости в libtoxcore (были CVE на buffer overflow и RCE в прошлом). Следющим идет ещё один мессенжер Pidgin -ормальный, но достаточно устаревший мессенджер, о котром я уже выразил свое мнение в разделе про Tails. Следующий Thunderbird для почты на котором я не вижу смысла заострять внимание, хотя там тоже есть поверхность атаки(JavaScript в письмах, уязвимости в парсинге MIME, плагины и тд.), но это уже мелочи по сравнению с тем, что уже установлено в системе.
Так же есть довольно избыточные Node Analysis и Tor Portal. Node Analysis это, самописный скрипт/GUI для анализа Tor-нод (проверка exit-политик, uptime, flags, bandwidth и тд.). А Tor Portal сервис для управления Tor.

И наконец разберём последний раздел меню - Видео и мультимедиа:
Не удалось прогрузить медиа

Сначала VLC и mpv оба предустановлены. VLC особенно опасен: это один из самых тяжёлых и исторически уязвимых медиаплееров. За 20 лет существования в нём нашли сотни CVE, включая RCE через кривые контейнеры (AVI, MKV, MP4, ASF), переполнения буфера в парсерах субтитров, кодеках (libavcodec, libavformat), сетевых протоколах (RTSP, MMS, HTTP Live Streaming), даже в обработке плейлистов (.m3u, .pls).

mpv тоже не подарок: хоть он легче VLC, но использует те же libavformat/libavcodec из FFmpeg, которые имеют уязвимости в кодеках (были десятки CVE на integer overflow, use-after-free, heap corruption). Плюс поддержка скриптов на Lua, которые могут быть эксплуатированы через вредоносный .lua-файл или конфиг.
Дальше PipeWire более современный мультимедиа-сервер вместо PulseAudio. У него тоже были уязвимости (например, CVE-2023-44429 в обработке аудио-буферов, позволяющий эскалацию привилегий). Но он хотя бы чуть менее устаревший, чем PulseAudio, и в целом считается надёжнее.

И наконец Kodi это медиа-центр с аддонами, inputstream (RTMP, HLS, DASH), PVR, VFS, скриптами на Python и Lua. Kodi имеет огромную историю RCE через аддоны (множество CVE в 2015-2023 годах), парсинг .nfo, .xml, .m3u, сетевые протоколы UPnP/DLNA, JSON-RPC API (по умолчанию слушает на 8080). А в live его наличие вообще чистый абсурд: зачем медиа-центр с аддонами в анонимной системе, где ты не хочешь оставлять ничего постоянного?

Так что если ты думал, что LibreOffice это плохо на live-системе... ну у него появился ещё более безполезный и уязвимый конкурент. Ха-ха, Cyrethium не перестаёт удивлять!


Дополнительные пакеты в Synaptic
Если ты думаешь, что этих программ слишком много, не переживай это ещё не всё. В системе стоит ещё больше ненужного хлама! В Cyrethium видно больше 2000 установленных пакетов, которые я увидел в Synaptic. Причём среди них куча совершенно ненужного и даже опасного софта.

Для начала есть полный комплект вообще всех баз данных, которые только можно представить:
Не удалось прогрузить медиа

Полный PostgreSQL и клиент, и серверные компоненты. MariaDB тоже клиент и сервер (mariadb-client, mariadb-server, galera и прочее). Ещё Redis + Valkey. Интересно, зачем он вообще здесь? Virtuoso это высокопроизводительная RDF-ориентированная БД, которая используется для семантического веба и имеет огромную кодовую базу. Есть даже PoWA Collector и Prometheus SQL Exporter и прочая серверная аналитика/мониторинг. Ну и на последок RocksDB, LMDB, SQLite3 с инструментами и их CLI и библиотеками.

Ещё из смешного/странного GNOME Desktop Environment:
Не удалось прогрузить медиа

Там есть куча тестовых пакетов (gnome-desktop-testing, gnome-desktop3-data, gnome-desktop-testing-utils и т.д.), плюс половина GNOME-библиотек и зависимостей. Проблема в том, что у меня MATE-интерфейс, и зачем они там неизвестно.

Но мое предположение в том что, возможно, из-за того, что у разработчиков есть две версии (для GNOME и MATE), им было просто лень выпилить лишние пакеты и они свалили всё в один образ. Что как по мне очень плохая практика, особенно для live-системы.


Сеть и kill-switch
Дальше идёт Tor тут тоже всё настроено довольно... специфически. 
Как я уже писал ранее Tor не работает глобально по всей системе, как в Tails с его принудительными туннелями и kill-switch, а через отдельный инструмент Cyrethium Tor Router (который просто запускает сервис Tor) и прокси в браузере.

Вот конфиг из /etc/tor/torsocks.conf:
Не удалось прогрузить медиа

И тут настройки довольно странные. Tor настроен для локального адреса на порту 9040. Там же есть OnionAddrRange 127.42.42.0/24 это диапазон, который Tor использует для отображения .onion-адресов как "cookies" (т.е. локальные IP-адреса, чтобы приложения видели onion-сайты как обычные локальные хосты без реального выхода в сеть). На этом нормальные настройки заканчиваються, а дальше идут странности. В конфиге есть строка AllowInbound 1 она разрешает входящие соединения на Tor (по умолчанию 0). Для обычного клиента это крайне странно и опасно: если включить входящие, Tor может принимать соединения от других узлов сети, что увеличивает поверхность атаки и делает тебя потенциальным relay без твоего ведома.

Ещё есть onion.pac это PAC-файл для браузера. В нём логика простая, если хост заканчивается на .onion то вернеться "SOCKS 127.0.0.1:9050" , а если на .i2p то вернеться "HTTP 127.0.0.1:4444"
иначе return "DIRECT".

То есть PAC-файл перенаправляет только onion и i2p-домены через соответствующие прокси, а всё остальное идёт напрямую. Это значит, что обычный трафик (Google, YouTube, любой HTTPS-сайт) выходит в чистый интернет без Tor.

В настройках Firefox это видно прямо:
Не удалось прогрузить медиа

Стоит "Automatic proxy configuration URL" file:///etc/cyrethium/onion.pac. То есть этот файл автоматически закинут в браузер Cyrethium, и по умолчанию Tor и I2P там работают именно как прокси для .onion и .i2p.

Почему это небезопасно?
Во-первых, как я и упоминал ранее нет даже намёка на глобальный kill-switch. Если Tor упадёт, выключится или не запустится браузер продолжит работать в DIRECT-режиме и сольёт реальный IP (или локальный, если ты в VPN). Никакой блокировки всего трафика без Tor.
Во-вторых, PAC-файл на file:// это локальный файл. Если в системе есть RCE (через LibreOffice, браузерный эксплойт, Java-апплет, любой другой софт), атакующий может модифицировать /etc/cyrethium/onion.pac и перенаправить трафик куда угодно на свой сервер, MITM-прокси и тд.
В-третьих, прокси стандартные и предсказуемые (.onion 9050, и .i2p 4444). Любой, кто сканирует сеть или анализирует трафик (даже пассивно), сразу поймёт, что у тебя стоит Tor + I2P.
В-четвёртых, нет принудительного перенаправления всего трафика. Curl, wget, apt, git, ssh, любой другой инструмент будут выходить напрямую, если ты не настроил их вручную на прокси. А в live-системе, где ты часто качаешь пакеты, обновляешься или тянешь репозитории это гарантированная утечка IP. Из этого можно сделать вывод что Tor настроен откровенно халтурно.


Браузеры и их "приватность"
Но особое внимание хотелось бы заострить на браузерах, а именно Amnesic Firefox и Hardened Firefox.

Сначала разберу "более приватный" Amnesic Firefox. 
То, что он не амнезийный, мы с тобой уже разобрались выше размеры ~/.mozilla и ~/.cache/mozilla/firefox почти не уменьшаются при закрытии. Это значит, что амнезия даже если есть, то не полная.

Дальше коротко пройдусь по user.js, который, как заявлено разработчиками, "хорошо кастомизирован". Из хорошего могу заметить, что там действительно отключены почти все телеметрии Mozilla: datareporting, healthreport, crashreporter, beacon, pocket, snippets и прочее. Плюс куча других настроек: отключены обновления расширений из Mozilla, отключены рекомендации, отключены новые вкладки с активностями и спонсорскими топ-сайтами. Ещё плюс, что network.cookie.lifetimePolicy = 2 это значит, что куки удаляются при закрытии браузера. privacy.clearOnShutdown.session и privacy.clearOnShutdown.history = true это значит что браузер не сохраняет сессии, логины и историю. По идее это и есть та самая амнезия.
Ещё browser.cache.disk.enable = false кэш не должен писаться на диск, но как мы с тобой помним Firefox всё равно кэширует в памяти и в ~/.cache/mozilla/firefox. По мимо этого в browser.bookmarks.* отключены закладки и бекапы. Ещё указан минимальный набор кнопок в browser.uiCustomization.state, а также отключен WebAssembly (javascript.options.wasm = false), что снижает поверхность атаки через WebAssembly-эксплойты.

Всё это действительно делает браузер приватнее дефолтного Firefox ESR, но есть несколько моментов, которые сводят на нет всю идею:
Первое и самое важное user.js применяется только к конкретному профилю (amnesic), но если профиль повреждён или создан новый - настройки могут слететь. Ещё забавный факт тебе в копилку: Hardened и Amnesic буквально отличаются только на уровне профилей на системе (папки с разными названиями), и именно там все настройки, а не на уровне сборки браузера (лол).

Второе, это то что некотрые из настроек кривые(кто то удивлен?). К примеру resistFingerprinting включён частично, а не полностью. В конфиге нет явного privacy.resistFingerprinting = true. Letterboxing не принудительный, нет spoofing hardwareConcurrency, deviceMemory, нет ограничения шрифтов до безопасного набора. Это значит, что сайты могут видеть реальное разрешение экрана, количество ядер CPU, список шрифтов через JS (если юзер отключит плагины по его блокировке). Или конфиге есть canvas randomization, но не спуфинг. Хеш всё равно уникальный для твоей комбинации GPU + драйверов + шрифтов. Потому это не сильно мешает трекерам. Ещё проблема тоже WebGL не заблокирован полностью. В конфиге нет webgl.disabled = true или ограничения vendor/renderer. То есть сайт может получить отпечаток видеокарты.

Из позитивных новстей есть только то что в браузере полностью заблокирован JS. Но даже это реализовано криво - не на уровне браузера, а через плагины uBlock Origin и NoScript:
Не удалось прогрузить медиа

NoScript включён, но в скрине видно, что он позволяет доверенным доменам всё, то есть если ты случайно разрешишь скрипты на подозрительном сайте, защита упадаёт. uBlock в настройках по умолчанию лучше (по крайней мере он не даёт доверенным сайтам делать что хотят). Но главная проблема остаётся это плагины, и их можно отключить или обойти. К примеру NoScript сам по себе имеет историю CVE (в прошлом были RCE через XSS в настройках). Плюс uBlock может быть обойдён через динамический отпечаток или если сайт использует first-party скрипты.

Ещё меня позабавило, что на своём сайте разработчики сравнивали свой Amnesic Firefox с Tor Browser. Как по мне такое сравнение крайне абсурдно. Amnesic конечно заметно приватнее обычного Firefox с дифолтными настройками, но даже близко не Tor Browser. Как минимум там нет глобальной смены отпечатка на уровне браузера, нет жёсткой изоляции, нет принудительного Tor или отключения JS на уровне сборки...

Теперь перейдём ко второму браузеру Hardened Firefox. Его позиционируют как браузер для повседневного использования в Cyrethium. Он сделан на базе Firefox ESR с усиленными настройками через user.js (чуть менее строгими, чем в Amnesic), плюс предустановленные плагины uBlock Origin и NoScript. Разработчики заявляют, что он защищает от трекинга, и имеет высокий уровень изоляции (вроде контейнеризации вкладок). Что даже звучит абсурдно с их уровнем "заботы" о безопасности в "более безопасном" Amnesic.

Для начала разберу user.js. Здесь, как и в Amnesic, отключена вся телеметрия Mozilla, отключены рекомендации, новые вкладки с активностями, спонсорские топ-сайты, улучшенный поиск. Так же, как и в Amnesic, WebGL не заблокирован полностью, а canvas только randomized (хеш всё равно уникальный), WebRTC не на strict.
Но вот дальше идут отличия: resistFingerprinting имеет значение false (что значит отключено полностью). Набор кнопок browser.uiCustomization.state довольно большой (много кастомизации интерфейса). Ещё нет параметров, которые запрещают сохранение куки, истории и паролей между сессиями. А browser.cache.disk.enable = true, что разрешает запись кэша на диск до 1 ГБ. Плюс browser.bookmarks.* то есть разрешает закладки и другие хранилища. Ещё devtools.enabled полностью включён (в Amnesic только частично).

Плагины и их настройки почти идентичны Amnesic: NoScript блокирует скрипты по умолчанию, оставляя только доверенные домены. Но вот uBlock работает без кастомных фильтров уровня "uBlock filters Annoyances" или "Block filters Privacy". Это значит, что он режет базовую рекламу и трекеры, но пропускает много fingerprinting-скриптов.

В целом отличия Hardened и Amnesic не такие существенные разница в основном в сохранении данных после закрытия сессии. Поэтому мой вывод простой: Hardened и Amnesic  Firefox конечно лучше обычного Firefox,  но если тебе нужна серьёзная анонимность используй Tor Browser(котрого нет по умолчанию в Cyrethium).


Изоляция приложений
И на сладкое в AppArmor просто не работает:

Не удалось прогрузить медиа

Точнее, в системе есть папка /etc/apparmor.d и там даже есть какие-то политики, но сам AppArmor в live-режиме фактически не работает. Когда я проверил aa-status, он написал, что модуль ядра загружен, но профили не применяются из-за unmet condition (ConditionPathExists для live-оверлея или tmpfs-корня). Это обычная проблема в Debian-based live-системах, где корневая ФС монтируется read-only + оверлей в RAM, и AppArmor-сервис просто не стартует или не находит нужные пути для enforce/complain-режимов. Но вот проблема, разработчики даже не потрудились допилить конфиг сервиса для запуска в live (как это сделали в Tails: там apparmor профили форсируются через init-скрипты и специальные правила для /live/overlay и тд).

То есть вся заявленная изоляция через AppArmor в live-режиме просто отключена... Профили лежат мёртвым грузом, и ничего не изалированно. Потому есть в системе есть уязвимость в каком-то приложении(и поверь уже они есть с учётом количества софта), эксплойт получит полный доступ к сессии без каких-либо AppArmor-препятствий.


Прошлые уязаимости в Cyrethium
Дальше, если ты так и не смог определиться, стоит ли ставить Cyrethium, несмотря на сомнительные моменты в шифровании, софте и сети, я расскажу про прошлое уязвимости системы, чтобы ты точно понимал, с чем можешь столкнуться при её установке.

Во-первых, главная проблема в том, что проект официально архивирован и не поддерживается с декабря 2025 года (по данным GitHub). Репозиторий заморожен. Это значит, что любые новые уязвимости в Debian (на котором базируется Cyrethium), и тысячах других зависимостей останутся без фиксов навсегда.

Но даже если закрыть глаза на прекращение поддержки, в live-режиме система уязвима к атакам, поскольку не активируются многие hardening-механизмы. К примеру, большая проблема в том, что по умолчанию live-пользователь имеет полный sudo без пароля. Это значит, что любой локальный эксплойт сразу получит root без единого запроса пароля. Сами разработчики подчёркивают что: "Cyrethium не plug&play и live mode уязвим к атакам вирусов". В live-режиме также есть серьёзная деградация производительности из-за тяжёлых hardening и CPU mitigation, поэтому они отключены или ослаблены.

Так как система нишевая, для неё нет специфических CVE именно под Cyrethium, но она полностью наследует проблемы Debian и всех своих пакетов.
Поскольку проект discontinued, эти уязвимости не патчатся в Cyrethium-specific релизах. К тому же из-за отсутствия аудитов конкретно для Cyrethium неизвестно, какие ещё скрытые уязвимости тут могут быть.

Ещё возможны низкоуровневые атаки, например cold boot. Даже при использовании init_on_free=1 или poison-on-free в ядре остатки данных в DRAM могут сохраняться до десятков секунд (особенно на DDR3/ранних DDR4). Потому при быстром извлечении модулей с охлаждением их можно прочитать на другом оборудовании. В Cyrethium нет ни аппаратного шифрования памяти (Intel TME/SGX или AMD SME/SEV не форсируются), ни надёжного стирания видеопамяти, ни таймаутов на полное затирание freed pages.

Ну и конечно же нет защиты или хотя бы нормальных предустановленных конфигураций от BadUSB или Rubber Ducky поэтому они тоже возможны. USB Guard стоит, но без жёстких whitelist/blacklist по VID/PID/class и без блокировки HID-устройств по умолчанию (нужно вручную настраивать правила). А про аппартную защиту как в Tails и заикаться не стоит.


Вывод про Cyrethium
Во первых мне жаль потраченного на обзор Cyrethium времени. Во вторых думаю, мой вывод от этой системы, как ты уже, наверное, понял из этого раздела, весьма неутешительный.

Но даже если закрыть глаза на прекращение поддержки, в live-режиме система уязвима к атакам, поскольку не активируются многие hardening-механизмы. 
К примеру, большая проблема в том, что по умолчанию live-пользователь имеет полный sudo без пароля. Это значит, что любой локальный эксплойт сразу получит root без единого запроса паро
Во-первых, похоже, я зря говорил, что Tails плох, по сравнению с Cyrethium это идеал безопасности. Во-вторых, Cyrethium противоречит самой концепции live-систем: напихано куча лишних программ, нет нормальной изоляции (AppArmor в live просто не работает, sudo без пароля, отключённые hardening-механизмы), нет принудительного kill-switch(трафик идёт DIRECT без Tor), нет жёстких настроек Tor и i2p(PAC-файл легко подменить, короткие в i2p туннели, устаревшее шифрование leaseSet), нет автоматического затирания RAM при выключение.

Ощущение, что разработчики взяли готовый Debian live, накидали туда бездумно всего подряд, добавили  конфиги браузеров с GitHub, наняли дизайнера, который сделал "красивый интерфейс", и выпустили в прод.

Мой тебе совет: если тебе дорога анонимность не используйте эту систему как live. Для persistent-режима ещё можно подумать, если ты готов сам настраивать безопасность, шифрование, изоляцию, чистить всё вручную, патчить пакеты и следить за обновлениями Debian. Но использовать Cyrethium как live особенно для чего то серьёзного, это очень большая ошибка.



heads
Теперь расскажу про Heads OS, это ещё одна live-система, ориентированная на приватность и безопасность. Heads построена на Gentoo (musl + hardened toolchain).

Концепт Heads заключается в принципе "ничего лишнего". 
Она минималистична до предела: musl вместо glibc (меньше кода, меньше уязвимостей), hardened kernel с grsecurity/PaX-подобными патчами (где возможно), нет systemd (используется OpenRC), нет pulseaudio/pipewire по умолчанию, никаких Java, Mono, .NET, или Electron. И ура, наконец-то нет LibreOffice! Зато есть dwm, vis и mpv без GUI. А как браузер стоит только Tor Browser.

В "inside heads" (манифесте от 2017 года от разработчика) прямо пишут, что цел- минимализм, элегантность, non-intrusion и cleverness. Никаких компромиссов ради удобства, или ненужных библиотек и фич, которые только увеличивают кодовую базу, а следовательно поверхность атаки.

Амнезия здесь тоже есть, но не такая хорошая, как в том же Tails. Система работает полностью в RAM (опция toram при загрузке). Так же большой плюс для меня лично это то, что на системе нет даже намёка на persistent-хранилище. То есть вообще никакого зашифрованного раздела для сохранения данных между сессиями, которые могли бы случайно оставить следы.

Но минус в том, что и жёсткого стирания данных после выключения тоже нет. Максимум из того, что есть это очистка freed pages (init_on_free=1 или poison-on-free. Нет принудительного затирания видеопамяти (GPU-буферы могут сохраняться дольше), или нет многократного перезаписывания RAM перед shutdown. Heads полагается на то, что ты используешь toram  и выключаешь систему нормально, но если выдернуть питание резко то cold boot остеться возможным особенно на старом железе.

Сеть в heads
Дальше кратко расскажу, как в Heads работает Tor. Tor запускается через rc-скрипт как демон в фоне. 
Так же есть полный kill-switch, так что без Tor в сеть выйти не получится.

Вот конфигурация torrc:
Не удалось прогрузить медиа

Как видно на картинке(Это фото с телефона, прокинутое через ИИ, так как вытащить картинку из heads было довольно сложно. Из за старых пакетов браузера и моего нежелания настраивать мосты или сбрасывать kill-switch), всё настроено с упором на изоляцию. Каждый запрос идёт на разные адреса или порты, тем самым получая полностью отдельную цепочку Tor. Порт 9040 используется для прозрачного проксирования TCP-трафика.

Ещё есть несколько SocksPort специально для разных сценариев: 9061 с IsolateDestAddr (изоляция по адресу), 9062 с IsolateSOCKSAuth (изоляция по аутентификации), 9150 с IsolateSOCKSAuth + KeepAliveIsolateSOCKSAuth (для приложений, которые держат соединение долго, но хотят изоляцию). Это позволяет запускать разные программы через разные порты и быть уверенным, что они точно не пересекутся в цепочках.

В конфиге видно что разрешны DNS-запросы, включая .onion и .exit, на DNSPort 5353, по мимо этого обычные UDP DNS тоже перенаправляется на него. Дополнительно есть флаг AvoidDiskWrites 1 он нужен для того, чтобы Tor держал кэш и всё остальное в RAM, и ничего не писал на диск.

Для того чтобы подробнее разобраться в настройках  kill-switch я открыл правила iptables:
Не удалось прогрузить медиа

Тут всё как и в конфиге: TCP-трафик перенаправляется на TransPort 9040, UDP DNS на 5353, плюс локальные диапазоны 127.192.0.0/10 тоже идут в Tor. Это не полный kill-switch в стиле Tails (где OUTPUT DROP без Tor), но довольно жёсткая маршрутизация: обычный трафик без Tor просто не пройдёт, если ты не настроил исключения вручную. Всё, что пытается выйти наружу, попадает в REDIRECT и либо уходит в Tor, либо зависает. Единственный минус что нет глобального блокирующего правила (если Tor упадёт или демон не запустился). Но думаю, это не прям критично, если обычный трафик и так перенаправлен и без Tor не работает. Впрочем, для полной паранойи не помешало бы добавить DROP в OUTPUT по умолчанию.

Изоляция в heads
В отличие от Tails или Cyrethium, где пытаются навязать AppArmor с кучей профилей (и периодически это работает криво или вообще не запускается в live - да-да, Cyrethium, это я про тебя), Heads идёт совсем другим путём. В Heads нет ни AppArmor, ни SELinux по умолчанию, ни любых других пробных программ для мандатного контроля. Нет даже попытки "закрутить" всё в профили, потому что любой дополнительный слой правил добавляет код, сложность и потенциальные баги.

"Изоляция" строится на радикальном сокращении поверхности атаки и жёстких настройках ядра с библиотеками. Например, использование musl libc вместо glibc, из за этого в разы меньше кода, нет legacy-фич, и меньше потенциальных багов в обработке строк, памяти, или динамической загрузке. По мимо этого, все бинарники компилируются с защитой от переполнений, stack smashing и перезаписи GOT. Так же нет dbus или systemd это значит, что нет шины, через которую можно атаковать (в Tails dbus-session часто становится слабым звеном).

Но минус очевиден: если эксплойт всё же сработает в любом запущенном приложении, он получит доступ к сессии без дополнительных барьеров. В Tails AppArmor хотя бы пытается ограничить LibreOffice или Tor Browser, а Heads полагается на то, что ты сам не запустишь ничего опасного или используешь firejail вручную.

Вывод про heads
Я уже собрался хвалить эту систему ведь мне действительно понравилась её идея, минималистичный список утилит, и большой манифест в "inside heads". Но как как на зло, когда я ввёл uname -a, то увидел один прискорбный нюанс: ядро не обновлялось с 2018 года.

Всё верно, сейчас проект фактически не развивается и уже 8 лет находится в заморозке. Последний стабильный релиз (0.4 или около того) вышел где-то в 2018-м. Сайт heads.dyne.org до сих пор висит, но выглядит как музейный экспонат: последняя дата в changelog 2019 год, репозитории на GitHub неактивны уже лет семь. А главный разработчик ушёл в другие проекты, и Heads остался в подвешенном состоянии.

Это значит, что система наследует все уязвимости, которые Gentoo и Debian закрыли за последние годы. Даже если ты сам соберёшь ОС из исходников с нуля, базовый toolchain и stage3 сильно устарели, и привести всё к современному уровню безопасности будет крайне сложно(придётся вручную фиксить и переделывать кучу библиотек под актуальные версии).

Увидев это, я понял, что дальнейший разбор ОС просто не имеет смысла. Потому что, несмотря на любые красивые настройки и правильную философию, без нормальных патчей и обновлений Heads останется опасной для реального использования.

И это очень грустно. Ведь Heads одна из немногих live-систем с действительно интересным и честным концептом. Поэтому я хочу сказать спасибо разработчику за эту, интересную ОС, и одновременно выразить грусть от того, что проект так и не получил должного развития, улучшения амнезии или хотя бы стабильных обновлений.



Kicksecure USB
Теперь расскажу про Kicksecure USB это live-система от разработчиков Whonix. Г
лавная идея здесь взять всю философию Whonix (изоляция через виртуализацию и Tor) и упаковать её в портативный формат, чтобы можно было загружаться с флешки на любом железе без установки VirtualBox, KVM или других костылей.

Архетектура Kicksecure
Kicksecure USB, и у Whonix, строится на трёх столпах: 
изоляция через разделение, hardening и анонимность по умолчанию. По уровню анти-форензики она очень близка к Tails, но при этом гораздо сильнее заточена под hardening. Так же в Kicksecure есть опциональное Persistent Storage (зашифрованный LUKS-раздел на той же флешке), но оно не включено по умолчанию и рекомендуется только тем, кто понимает риски(собственно как и в Tails).

Но вот архитектура сети тут сильно отличается от Tails. Вместо простого kill-switch с туннелями Kicksecure USB использует архитектуру, взятую прямиком из Whonix: две виртуальные машины (Gateway и Workstation), запущенные прямо с флешки через встроенный KVM/QEMU. Gateway работает как Tor-шлю- только он имеет доступ к интернету, и весь трафик Workstation идёт исключительно через него.

По мимо этого система старается не пихать кучу лишних, не настроенных программ для приватности, как в том же Cyrethium что для меня тоже является большим плюсом.


Как работает стирание памяти и амнезия?
Амнезия в Kicksecure сильно напоминает подход в Tails. 
Во-первых, здесь применяется агрессивное стирание освобождённой памяти. В параметрах ядра задаётся опция вроде "init_on_free=1", которая заставляет систему автоматически заполнять нулями или случайными шаблонами все блоки памяти, как только они освобождаются. Как только процесс завершает работу, и отпустил кусок памяти тот сразу затирается.

Кроме того, добавляется очистка кэшей структур ядра вроде буферов, inode, и прочих. Для этого используются параметры вроде "slab_nomerge" плюс "slub_debug=PZ", которые вводят "отравление" и обнуление этих аллокаторов. Зачем? Чтобы избежать утечек через атаки вроде "use-after-free".

А теперь третье, моё любимое: частичная очистка видеопамяти. Хоть Kicksecure и полагается в основном на естественное угасание данных в GPU. Но чтобы усилить эффект, добавляются параметры ядра, вроде "video=efifbff" или "nomodeset", которые минимизируют использование видеопамяти вообще. Плюс, при выключении системы идёт очистка через интерфейсы вроде fbdev или drm.

Из минусов: в Kicksecure нет многократного перезаписывания всей оперативной памяти перед выключением, как в Tails с их sdmem. Но это компенсируется тем самым стиранием освобождённой памяти на лету(которое в прочем есть и в Tails).


Утилиты и программы
Теперь расскажу про программы, которые есть в этой ОС. На самом деле список довольно минималистичный и это большой плюс.

Первое, что бросается в глаза, это крипто-кошельки:
Не удалось прогрузить медиа

Там есть Electrum Bitcoin Wallet, и к нему у меня те же претензии, что и раньше в разделе про Tails: seed-фраза по умолчанию не шифруется, даже если ставишь пароль на wallet-файл шифрование слабое. Но не буду заострять внимание, поскольку уже проходил это в Tails.

Дальше видео и графика, спискок программ тут хоть и немного спорный, но в целом приемлимый:
Не удалось прогрузить медиа

Есть VLC и mpv. VLC опасен: огромная история уязвимостей, сотни CVE, RCE через контейнеры (MKV, AVI, MP4), парсеры субтитров, сетевые протоколы. mpv легче, но использует те же libavcodec/libavformat из FFmpeg тоже с дырами в кодеках. В live это лишний вектор что поствлю как минус. Но хотя бы нет Kodi с аддонами или чего-то ещё тяжёлого.

Теперь самое интересное браузеры. 
Как видно на скриншоте выше, в разделе Programming есть значок Icon Browser. Если на него нажать, вместо контекстного меню браузера появится Python-интерфейс с выбором одного из четырёх браузеров.

Вот как выглядит "Browser Choice" меню:
Не удалось прогрузить медиа

Там  можно выбрать из списка: Brave, Chromium, Firefox, Mullvad Browser, Tor Browser. И это для меня крайне странно и неуместно на live-ОС, особенно с учётом всего, что мы разбирали раньше. Зачем в анонимной системе предлагать Brave, Chromium или обычный Firefox? Это же прямые векторы утечек IP, fingerprinting, WebRTC, canvas и тд. К тому же мне кажется сомнительным, что за установку браузеров отвечает какой-то Python-скрипт(вероятно, dev/browser-choice или что-то подобное). Нет гарантии, что он не модифицирует систему или не тянет пакеты с неофициальных источников.

Tor Browser есть, но его нужно выбирать вручную для устаноки, а не по по умолчанию. В регионах без мостов Tor не работает сразу (мостов в настройках нет), и подключить их можно только после установки браузера. Получается замкнутый круг: без Tor браузер недоступен, так как только в Tor Browser можно получить мосты, чтобы подключиться к сети, а установить его без Tor невозможно, потому что сеть просто не работает.


Безопасность сети
Теперь немного затрону сеть, изоляцию и приватность, которыми так кичились Kicksecure, и расскажу, правда ли там всё действительно так чудесно. Спойлер: увы, совсем нет.

Для начала Tor работает через сервис в systemd (tor-service-defaults-torrc и tor-service-defaults-tor-instances), а не как заявлено "через виртуалки". Да, всё верно, все рассказы про встроенный KVM и две VM скорее всего были просто маркетингом.

Вот конфиги сервисоа:
Не удалось прогрузить медиа

DataDirectory хранит consensus, keys и роутер-листы. PidFile отвечает за PID-файл демона. User debian-tor позволяет запускаться от непривилегированного пользователя debian-tor. ControlSocket /run/tor/control GroupWritable RelaxDirModeCheck это unix-сокет для контроля (nyx, tor-ctrl), group-writable для доступа из группы debian-tor. SocksPort это SOCKS-порт через unix-сокет, доступный всем чтобы приложения могли подключаться без прав root. И наконец CookieAuthentication 1 + CookieAuthFileGroupReadable 1 + CookieAuthFile  это cookie-аутентификация для control port.

Это стандартный Debian/Tor systemd-юнит с cookie-аутентификацией и unix-сокетом. Даже нет, никаких дополнительных настроек безопасности вроде IsolateDestAddr, IsolateSOCKSAuth (которые нужны для stream isolation чтобы разные приложения не пересекались в цепочках Tor), или нескольких SocksPort.

Но может, я слишком строг, и хотя бы настройки iptables нормальные? Впрочем… думаю, это даже для шутки, слишком глупо.
Первое, что мне бросилось в глаза, тут всего одна настройка... И это REDIRECT на 9040 для TCP, 5353 для UDP DNS, плюс локальные диапазоны 127.192.0.0/10 тоже перенаправляются в Tor. Это даже не полный kill-switch. Если Tor упадёт, демон не запустится или просто будет перезапущен REDIRECT просто не сработает, и трафик уйдёт напрямую в чистый интернет.

Ещё один момент Tor имеет всего один единственный туннель:
Не удалось прогрузить медиа

На скриншоте видно, что нет нескольких SocksPort с разными Isolate* (как в старых версиях Whonix или Heads). Только базовый 9050. Stream isolation отсутствует по умолчанию, а все приложения используют одну цепочку Tor. Если одно приложение скомпрометировано и делает запросы, а параллельно работает Tor Browser цепочки могут коррелироваться по времени/объёму трафика. Это сильно ослабляет анонимность против глобальных атак.

Кстати, помнишь, я говорил в начале раздела, что в Kicksecure хорошая изоляция сети и ничего не может просочиться? Так вот я вас обманул точнее, не я, а разработчики. В ряде тестов я засёк, что пакеты без включённого Tor и правда скачивать нельзя.

Но когда я протестировал curl, то был сильно удивлён:
Не удалось прогрузить медиа

Оказалось, что с выключенным Tor curl вполне себе работает. Уровень безопасности и изоляции ты можешь оценить сам. А я постараюсь разобраться, почему так происходит.

Всё просто это из-за пресловутого iptables REDIRECT, который настроен только для TCP и UDP DNS, но не для всего трафика. Apt падает, потому что репозитории Kicksecure используют tor+http:// и требуют Tor, а без него просто не соединяются. Curl же идёт через HTTP/HTTPS, попадает в REDIRECT на 9040, Tor обрабатывает запрос и выходит. То есть REDIRECT срабатывает только для определённых типов трафика и портов, а не для всего исходящего. Если Tor не запущен REDIRECT просто не находит, куда перенаправить, и трафик уходит напрямую .


Изоляция приложений
С изоляцией приложений через AppArmor в Kicksecure дела обстоят немного лучше, чем с сетью. Во-первых, AppArmor действительно включён и активно работает(привет Cyrethium). Во-вторых, он довольно жёстко настроен.

Вот что показал вывод aa-status:
Не удалось прогрузить медиа

Как видно, загружено 146 профилей, из них 25 в enforce-режиме, 45 в complain, а остальные без строгих ограничений или вообще без профиля. В enforce-режиме находятся самые критичные компоненты. Это в первую очередь Tor Browser (его профиль обычно называется home.tor-browser.firefox), сам демон Tor (system_tor). По моему мнению, это правильно именно эти процессы обрабатывают весь анонимный трафик и должны быть максимально ограничены.
Под enforce так же попали и некоторые медиа-предпросмотры вроде totem-audio-preview и totem-video-preview. Это важно, потому что Totem (GNOME Videos) использует GStreamer, который периодически получает RCE-уязвимости при открытии кривых медиафайлов. Enforce-режим здесь ограничивает доступ к файлам, сети и устройствам, чтобы эксплойт не вышел за пределы предпросмотра. Также под enforce hexchat(мессенджер для IRC/XMPP), и pidgin с sanitized_helper который открывают файлы/URL от пользователя.
Ещё ограничение имеют нескольно системных проверок: timesanitycheck (проверяет время, чтобы предотвратить атаки на сертификаты/Tor через подмену времени), systemdcheck (проверяет состояние systemd-юнитов, чтобы выявить сбои или скрытые сервисы), haveged (генератор энтропии, чтобы не зависеть от слабого /dev/random), nscd (кэшер DNS/имён пользователей).

Для примера подробнее разберу профиль AppArmor для Tor Browser:
Не удалось прогрузить медиа

Этот профиль очень сильно напоминает профиль Tor Browser в Tails. Первое, что бросается в глаза полный rw-доступ даётся только внутри директории самого Tor Browser, то есть ~/tor-browser. Всё остальное в home по умолчанию закрыто на запись, а чтение сильно ограничено. Так же профиль позволяет читать корень home (@{HOME}/ r) и некоторые конфиги вроде ibus или kde, но запись идёт только в строго определённые места: Downloads, Desktop (через XDG-переменные), и поддиректории внутри Tor Browser.

Системные файлы, которые могут выдать реальную машину или сеть, жёстко deny на чтение. Например конфиги связанные с системой (/etc/passwd, /etc/group, /etc/hosts, /etc/resolv.conf и подобные) имеют deny. Или конфиги с информацией об оборудовании вроде /proc/cpuinfo, /proc/meminfo тоже частично через deny на /proc//cmdline, environ, status, stat, net/route, arp и тд. Так же deny r на файлы, которые могут выдать устройство вроде /sys/devices/, /sys/bus/pci/. Ну и всё, что отвечает за задачи вроде /proc//fd, /proc/*/task/ или /sys/kernel/random/uuid тоже deny или owner-only.
Это действительно полезно: даже если злоумышленник как-то обойдёт sandbox Tor Browser и захочет собрать отпечаток железа или вообще внедрить эксплойт у него ничего не выйдет, потому что доступа просто нет.

Но это ещё не всё, доступ к /dev сильно урезан: deny на большинство устройств, разрешён только /dev/shm/org.mozilla.ipc.* rw (для межпроцессного общения внутри Firefox sandbox) и /dev/dri/** r (для аппаратного ускорения видео). Но /dev/mem, /dev/kmem, tty, input за пределами полностью закрыты.

Наконец профиль запрещает ptrace (отладку других процессов), чтение /proc/fd других процессов, ptrace полностью заблокирован. Полностью запрещён доступ к /run/user/ за пределами нужного каталога, потому браузер не видит другие процессы, сокеты или временные файлы других пользователей.

Впрочем, есть и менее хорошие конфигурации. У обычных браузеров профили либо в complain-режиме, либо вообще unconfined, либо с минимальными deny (passwd, cpuinfo), но без полной изоляции home, без строгой сети, без запрета на /sys и /proc. Потому если ты установишь обычный Firefox (а такая возможность, как я показывал выше, есть), он легко может слить твой /proc, /sys, прочитать ~/.ssh, ~/.gnupg или много чего ещё. Эксплойт или просто скрипт на сайте получит доступ к hardware fingerprint, реальному времени, списку процессов и другим данным, которые Tor Browser в enforce-профиле жёстко блокирует.
Ещё как минус могу засчитать то что в Kicksecure есть много странных конфигов вроде Discord, которые тут вообще ни к чему, но их зачем-то всё равно добавили.


Кстати, если говорить про изоляцию, есть ещё один интересный нюанс: в дефолтной версии sudo и su для обычного пользователя недоступны. Чтобы использовать sudo, нужно выбирать специальную версию Kicksecure с его поддержкой при загрузке это отдельный пункт в GRUB или boot-меню. Отсутствие sudo сделано для безопасности: в live-режиме обычный юзер не может легко получить root, даже если эксплойт дал shell. Но это крайне неудобно. Например, мне для тестирования системы пришлось использовать версию с sudo, так как многие вещи без него проверить просто нельзя.

Но и для обычного юзера это тоже крайне неудобно. Представь ситуацию: хочешь сделать apt update, чтобы обновить систему. Но тут выскакивает ошибка, что нет прав. В итоге приходится лезть в recovery или вручную добавлять правила в /etc/sudoers.d (на что часто тоже не хватает прав). Впрочем, если пользователь будет пользоваться только браузером и программами, не заходя в терминал, такой варинт системы может для него подойти.


Прошлые уязвимости
Мы с тобой уже выяснили, что сеть в Kicksecure настроена довольно плохо, но вот с AppArmor разработчики хоть немного заморочились. Чтобы окончательно расставить точки над и, а ты окончательно смог разобраться, можно ли использовать эту ОС, расскажу, какие уязвимости могут быть в Kicksecure.

Поскольку Kicksecure это не отдельный дистрибутив с собственной кодовой базой, а модифицированный Debian, он наследует все уязвимости Debian, которые не закрыты в upstream или в репозиториях Kicksecure. При этом команда Kicksecure активно патчит и добавляет свои фиксы, но не всё успевает, особенно если CVE касается ядра, системных библиотек или браузеров.

Теперь про уязвимости в браузерах. Tor Browser в Kicksecure, как мы с тобой разбирали выше, действительно очень хорошо защищён AppArmor-профилем. Но вот с обычным Firefox, Brave, Mullvad Browser и Chromium всё намного хуже. Профили для них либо в complain-режиме (логирует нарушения, но не блокирует), либо вообще unconfined (полный доступ). Потому, если ты случайно (или через Browser Choice) запустишь любой из них вместо Tor Browser, то защита будет минимальная. Эксплойт или просто скрипт на сайте легко сольёт /proc/cpuinfo, /sys/devices, или прочитает ~/.ssh, и тд.

Обычный Firefox в Kicksecure имеет несколько свежих CVE. Первая это CVE-2025-1080: RCE через Office URI Schemes и собственную схему vnd.libreoffice.command. Злоумышленник создавал ссылку, которая выглядит безобидно, но при клике передаётся в Firefox, а оттуда в LibreOffice (если он скачен), и запускает макросы с произвольными аргументами. Вторая CVE-2025-2866 это подделка PDF-подписей в старом формате adbe.pkcs7.sha1 (PKCS#7 с SHA-1). Из-за ошибки в верификации подписи система может принять явно фейковую подпись как валидную. Если злоумышленник создаст документ, который Firefox показывает как "легитимный подписанный", то сможет обмануть пользователя или внедрить вредоносный код через embedded-объекты.

С Brave всё ещё хуже. Это Chromium с их встроенными блокировками рекламы и трекеров. Brave в прошлом (2018-2020) использовался ФБР для деанонимизации пользователей даркнета через уникальный fingerprint Brave (даже с Tor), и их Rewards-систему (которая тянула данные о просмотрах и кошельках). Хотя сейчас Rewards отключаемы, а fingerprinting частично прикрыт, Brave всё равно Chromium-based, а это огромная поверхность атаки. Из недавних cve в Chromium была CVE-2025-15523 которая повышение привилегий через Python-интерпретатор (TCC-права), и позволяла запускать скрипты от имени браузера. По мимо это были ещё несколько use-after-free и prototype pollution в V8, которые позволяли обойти sandbox и читать куки, пароли, историю.

Дальше уже чуть более безопасный Mullvad Browser. Это форк Tor Browser от Mullvad VPN (на базе Firefox ESR), с отключённой телеметрией, resistFingerprinting и uBlock/NoScript по умолчанию. Mullvad позиционирует его как "Tor Browser без Tor" для тех, кто хочет максимальную приватность в обычном интернете, без onion-сети. Исходники открыты (GitHub Mullvad/mullvad-browser), но часть инфраструктуры (серверы обновлений, сертификаты) контролируется Mullvad. Потому доверяешь ли ты этому VPN-провайдеру или нет, это уже твое дело. А как известно, у VPN-компаний, особенно на бесплатных продуктах вроде браузера, часто бывают "дыры" в системе или скрытые "способы заработка".

По мимо этого Mullvad Browser наследует все уязвимости Firefox ESR. Например, несколько use-after-free в Gecko. Первый use-after-free в DOM-обработке событий, позволяющий обойти sandbox и выполнить код и второй use-after-free в JS JIT-компиляторе IonMonkey, приводящий к утечке памяти и RCE. А так же CVE-2025-2866 это подделка PDF-подписей. Фейковые "подписанные" документы показывались как легитимные.

Теперь наиболее опасный и неуместный здесь это голый Chromium без патчей Mullvad/Brave/Tor. Недавние уязвимости те же, что и в Brave (который на нём основан). Но самое опасное в нем не возможные cve, а то что Chromium почти полный отпечаток устройства. Всё потому что что абсолютно любые патчи или дополнительные политики которые блокируют сбор по дефолту отсутствуют.


Вывод про Kicksecure
С одной стороны, Kicksecure лучше какого-нибудь сомнительного Cyrethium или Heads, который уже много лет не поддерживают. 
В ней нет кучи лишних программ за что я могу похвалить ОС, хоть и с оговорками. Browser Choice очень странное решение на приватной системе live, но в целом предустановленный набор минимальный и разумный. Программы имеют хорошие конфигурации AppArmor, особенно Tor Browser и важные системные сервисы, что тоже большой плюс.

Но с другой стороны Kicksecure всё ещё не соответствует тому описанию, которое дают разработчики. Моя главная претензия в том, что виртуализация сети оказалась просто маркетингом. Настройки сети работают через обычный Tor, запущенный в systemd, и кривой конфиг iptables. Камон, этот конфиг даже нормально не блокирует сеть при отключении Tor. Конечно, есть SOCKS-прокси для установки пакетов, но другие сервисы типа curl всё равно работают. Я вообще не понимаю: зачем придумывать такой костыль с конфигом iptables без полной блокировки и SOCKS-прокси. И почему просто нельзя сделать нормальные настройки iptables?

По мимо этого меня смутило, что нет авто-подбора мостов, как в Tails, или хотя бы предустановленного Tor Browser, чтобы юзер мог сам получить мосты и вставить туда. Получается замкнутый круг: в странах, где Tor заблокирован сеть не работает без мостов, Tor Browser нужно ставить вручную, но без сети это невозможно.

Ещё одна вещь, которая лично мне показалась странной при тестировании Kicksecure это отсутствие прав на sudo при дефолтной загрузке у юзера (что дико неудобно, если планируешь работать с терминалом). При этом если юзер загружается с sudo он не может настроить пароль (как в Tails при выборе нужного параметра), и система автоматически будет работать без пароля.

В итоге, если свести все факты, я считаю, что ставить как live Kicksecure всё же не стоит. Единственное её преимущество перед тем же Tails это отсутствие LibreOffice. Но думаю, это не настолько важно в приватной live-ОС, как работоспособность и нормально настроенная сеть.

Кто-то может сказать: "Но Kicksecure можно использовать для запуска Whonix". Но как по мне, это бред. Во-первых, самое главное на Kicksecure нет никакой встроенной VM. Во-вторых, live-система просто не предназначена, чтобы тянуть другую ОС на виртуалке. Даже если Whunix чудом поместится на флешку c Kicksecure, то будет сильно тормозить из-за нехватки мощностей.

Потому разработчикам отдельно могу пожелать всё же доработать kill-switch до рабочего состояния. Возможно, тогда эта ОС станет пригодной для использования на практике и сможет хоть минимально конкурировать с Tails. А пока это просто Debian с хорошими политиками AppArmor, небольшим набором программ и криво настроенным Tor.


Мое мнение про приватные live
На этом я завершаю обзор приватных live-ОС. 
Причина проста: 
больше нет систем, которые были бы по-настоящему ориентированы на приватность, работали в live-режиме и при этом оставались актуальными или хотя бы интересными для подробного разбора.

Конечно, можно было бы ещё упомянуть Linux Kodachi в live-режиме(но большинству и так известно, насколько он плох с точки зрения реальной безопасности), или Parrot OS и Kali Linux в live-варианте. Однако эти дистрибутивы изначально создавались преимущественно для десктопа, а их live-версии служат в первую очередь для пентеста, а не защиты приватности.

В любом случае этом разделе мы с тобой уже разобрали несколько live-систем, и у каждой из них есть свои подводные камни
Например, Tails предлагает относительно неплохую защиту от аппаратных атак и отлично настроенную маршрутизацию через Tor с надёжным kill-switch. Однако страдает от устаревшего софта и наличия LibreOffice, который создаёт огромный вектор атак (особенно через обработку документов и макросов).

Whonix в live-режиме вообще не является полноценной live-системой: запуск в виртуальной машине сильно зависит от настроек гипервизора, а не от самой ОС. Из-за этого часто происходят утечки через хост-систему, что сводит на нет многие преимущества анонимности и амнезии.

Heads имеет красивую идею максимального минимализма и хорошо интегрированного свободного ПО, но, увы, проект давно заморожен. Без регулярных обновлений он становится просто опасным.

Но единственная по-настоящему плохая ОС в этом разделе это Cyrethium. Это буквально свалка из кучи "приватного софта", где юзеру приходится самому разбираться, что из этого работает и как это настроить. AppArmor в live-режиме вообще не активен (по политике Debian), ещё сеть настроена криво и без kill-switch.
И наконец, Kicksecure: он предлагает неплохой уровень хардененга, минимальный набор программ, хорошо настроенный AppArmor, но картину сильно портит откровенно слабая реализация kill-switch.

Из всего этого напрашивается простой, но довольно неутешительный вывод. Многие некоммерческие проекты с интересными идеями быстро перестают поддерживаться. А коммерческие решения не видят смысла в серьёзных доработках из-за отсутствия реальной конкуренции. Тот же Kicksecure мог бы стать отличным дистрибутивом, если бы разработчики хотя бы немного подтянули сетевую часть. Tails стал бы в разы лучше, если бы его разделили на несколько специализированных образов: один чистый минимумом программ и Tor Browser, другой для журналистов с офисным пакетом, третий для работы с криптовалютой и кошельками.

Впрочем, это лишь мои фантазии. А если смотреть честно, на данный момент в публичном доступе не существует live-ОС, которая по-настоящему подходила бы под критерии хорошей приватной live-системы с достойным уровнем безопасности и анонимности.



Создние live своего дистрибутива

Что ж, готовые приватные дистрибутивы мы с тобой разобрали и пришли к выводу, что "достойных альтернатив" среди них, по сути, нет.
Поэтому, следуя принципу "критикуешь - предлагай", я покажу тебе альтернативный вариант,  а именно сборку собственного минимального приватного live-дистрибутива!

Скажу сразу: этот раздел лишь пример с идеями, которые я бы хотел реализовать или воплотить. Здесь не будет сложных вещей вроде прям губокой защиты от cold boot (как в Tails), или полноценной блокировки USB-устройств после загрузки системы для защиты от BadUSB и подобных атак. Тем не менее я постараюсь показать, как собрать ОС с максимально нужным набором софта, хорошим kill-switch, строгими политиками безопасности и маскировкой устройства пользователя. Дальнейшую кастомизацию и доработки ты уже сможешь делать самостоятельно под свои конкретные нужды.


Идея дистрбутива
Теперь расскажу свою концепцию. 
Я хочу сделать ОС именно для приватного серфинга сети и безопасных крипто-транзакций без какой-либо обработки документов, мессенджеров или других "лишних" функций. Так как мне кажется, что это одни из самых частых и важных задач, которые должна закрывать приватная live-ОС: вставил флешку, зашёл на форум или сделал транзакцию и вышел, не оставив следов на своем личном пк.

Кто-то может сказать: "А как же общение? Почему не добавить хотя бы какой-то мессенджер?"
Я отвечу так: во-первых, любые мессенджеры даже самые "безопасные" создают дополнительный вектор атак (плагины, обновления, утечки метаданных, зависимости от библиотек, социальная инженерия, фишинг и тд). Во-вторых, мессенджеры просто противоречат минимализму, о котором я говорил раньше.

Поэтому, по-хорошему, для общения нужно делать отдельную систему, в которой вообще ничего нельзя украсть (seed-фразы, куки, отпечатки и тд.), а вся работа строится вокруг жёсткой изоляции мессенджера и подделки данных о системе. Но этим мы с тобой займёмся(если будет хороший фидбек в комментариях) как-нибудь в другой раз.


Наполнение дистрибутива
За основу возьму Debian Linux потому что на нём проще всего собирать live-ОС. У него огромные и стабильные репозитории, официальная поддержка live-build,,плюс все уже привыкли к его пакетам и инструментам. Да ещё и большинство приватных live-систем (тот же Tails) используют Debian. Да возможно тот же Arch Linux привлекателен своей свежестью пакетов, но для live-системы это создаёт слишком много гемора: rolling-release сложнее удерживать стабильным в образе, а при каждом обновлении выше риск сломать сборку.

Сборка будет в виде обычного ISO-образа, как и у большинства live-систем. Persistent-хранилища или зашифрованного раздела в системе не будет. Так как я думаю что это противоречит самой концепции чистой live-ОС. На диск будет производиться только минимальная запись, а swap в live-сессии полностью отключён. Также при загрузке будет установлен пароль для sudo.

Загрузка системы
Инициализация будет через systemd (как в Tails). Я
 выбрал его, потому что в Debian он отлично поддерживается из коробки, имеет хорошую интеграцию с AppArmor и другими важными вещами.
Возможно, кто-то скажет: "Вот systemd слишком перегружена, монолитная и сложна в управлении". Я отвечу так: проблемы с systemd обычно возникают уже после успешного взлома и закрепления в системе, а в чистой live-ОС, которую используют несколько часов без сохранения изменений на диск, закрепиться и эксплуатировать её внутренние слабости крайне проблематично.
Можно было бы, конечно, использовать runit. Debian даже частично поддерживает его официально и пакеты есть в репозиториях. Но его нормально можно использовать только как супервизор поверх уже существующей init-системы. Есть и отдельный пакет runit-init, однако это экспериментальная  версия. В ней часто возникают проблемы с графическим окружением, зависимостями служб и тд. Так что, на мой взгляд, он не стоит проблем и головной боли которые принесёт.
Раз уж я про минимализм, то почему не использовать OpenRC или s6? Для начала OpenRC, он частично полагается на shell-скрипты, что делает его медленным и не очень надёжным при параллельном запуске служб. А s6 сложен в настройке, и требуетсного больше ручной работы с конфигами служб.

Дальше загрузчик, c ним выбор посложнее. Стандартный GRUB слишком дрявый и имеет множество уязвимостей: проблемы с загрузкой модулей, возможность запуска без проверки подписи, известные связанные с переполнением буфера.
С другой стороны, для live-систем реальных альтернатив почти нет. systemd-boot работает только с UEFI и не поддерживает BIOS. Limine слишком молодой и модный, но поддержка в сообществе пока слабая, ещё и документации почти нет. Syslinux давно устарел, практически не развивается и по безопасности оставляет желать лучшего. Поэтому в итоге мой выбор всё-таки падает на GRUB, но с мнинималистичной настройкой, которая хотя бы приближают его к приемлемому уровню безопасности.

Программы
Когда с низкоуровневой частью разобрались, пора подумать и о более пользовательских компонентах. 
Для начала нужно выбрать браузер. 
Здесь есть два основных варианта: Tor Browser или сильно кастомизированный Firefox. Антидетект-браузеры я сразу отбрасываю нормальных в открытом доступе нет, а те, что продаются в привате, во-первых, стоят денег, а во-вторых, из-за закрытых исходников их почти невозможно нормально пропатчить или доработать под себя в будущем.
На первый взгляд, Tor Browser кажется лучшим вариантом. "Вон он даже в Tails используется". И да, это действительно хороший выбор с точки зрения защиты сети и скрытия некоторых отпечатков например, часовых поясов, шрифтов или языка браузера. Плюс разработчики активно закрывают известные уязвимости, которые могут использоваться для деанонимизации.
Однако… в последние годы моё доверие к Tor Browser сильно упало. С 2024 года разработчики начали довольно странную кампанию по "защите от подмены отпечатков". Например, они перестали полностью скрывать user-agent. Теперь он может частично выдавать реальную версию и платформу: у всех пользователей Windows он показывает Windows, у Android Android, у Linux Linux. И самое неприятное это нельзя отключить через about:config. Думаю ты понимаешь какой это маразм: они буквально вырезали функционал которая есть в обычном Firefox.

Второй вариант сильно кастомизированный Firefox. Но хорошо заточить его под приватность и антифингерпринтинг довольно сложно. Можно использовать user.js и политики но, как показал пример Cyrethium, они далеко не всегда работают на 100%. Ещё более радикальный способ кастомизация прямо на уровне исходного кода и генерация поддельного отпечатка. Но, думаю, ты и сам понимаешь: в одиночку поддерживать и постоянно обновлять форк Firefox это очень сложная задача.

Поэтому в итоге я всё-таки решил использовать Tor Browser, но с максимально жёсткими политиками AppArmor. Плюс я вручную подменяю те отпечатки, которые Tor Browser сам не закрывает.

Теперь, какой кошелёк будет использоваться в моём дистрибутиве? Для начала это будет горячий кошелёк. Аппаратный кошелёк добавить не получится, потому что невозможно сделать нормальную поддержку сразу нескольких разных брендов. Если поддерживать только одну модель это сильно ограничит пользователей. А добавлять сразу несколько резко увеличит поверхность атаки.
Ещё для меня важно, чтобы кошелёк поддерживал разные криптовалюты, но при этом не требовал долгой синхронизации. Поэтому чисто Monero-кошельки сразу отпадают. Также мне нужен максимальный минимализм кода, хорошее шифрование seed-фразы по умолчанию и полностью открытые исходники.

Ближе всего к моим требованиям оказался Cake Wallet. И не спеши кидаться помидорами из-за того, что он относительно молодой и доверия к нему может быть меньше, чем к старым Electrum или Sparrow.
Ведь вм отличие от Electrum, где seed по умолчанию лежит в открытом виде, а при включённом пароле используется AES-256-CBC с довольно слабыми настройками PBKDF2, в Cake Wallet seed-фразу шифруют по умолчанию очень серьёзно: Argon2id для вывода ключа и AES-256-GCM для самого шифрования. Другой большой плюс  полностью открытые исходники, так что код можно проверить самому или собрать приложение из исходников. А ещё Cake Wallet из коробки отлично работает через Tor: все запросы к нодам идут через onion-сервисы по умолчанию.
Да, есть и минусы. Например, Cake Wallet не так часто выпускает обновления для Linux, потому что основной фокус проекта на iOS и Android. Из-за этого десктоп-версия иногда отстаёт по функциям и исправлениям. К тому же он написан на Flutter, что добавляет runtime-оверхед, увеличивает размер приложения и теоретически расширяет поверхность атаки (хотя сам код довольно компактный). Но мне кажется, что эти недостатки всё равно меньше его обьективных плюсов.

Изоляция и сеть
Дальше поговорим про изоляцию. 
Она будет реализована через политики AppArmor. SELinux я сразу отмёл, потому что он слишком сложный в настройке, требует очень много ручной работы и часто приводит к ошибкам, поэтому его лучше оставить для серверов. Основные политики будут, конечно, для кошелька и браузера(что логично). Плюс я добавлю базовые политики для других программ, которые пользователь может установить сам.

Теперь про сеть. Вся сеть в системе будет идти исключительно через Tor. Это будет сделано по принципу kill-switch. При загрузке сети автоматически будет запускаться Tor, и только через него (и порт i2p) будет разрешён выход в интернет.  Ещё одна важная фича автоматическая смена MAC-адреса и других идентификаторов при каждой загрузке. Система будет генерировать случайный MAC для всех сетевых интерфейсов.


Сборка Дистрибутива
Ладно, хватит тянуть кота за хвост. 
Думаю, ты уже с нетерпением ждёшь чтобы узнать, как собрать свою собственную минималистичную приватную live-ОС.

Подготовка к сборке
Сначала расскажу, что тебе для этого понадобится.

Во-первых, носитель. Тебе понадобится обычная USB-флешка объёмом минимум 8 ГБ. У меня для тестов была 16-гигабайтная с ней работать удобнее, но и 8 ГБ вполне хватит для базовой системы.

Во-вторых, компьютер для сборки. Подойдёт практически любой рабочий компьютер или ноутбук. Я собирал систему на довольно стареньком ThinkPad T400, и он отлично справился. Главное требование на этом компьютере должна быть установлена Debian (или производный дистрибутив). Я настоятельно рекомендую именно чистый Debian, потому что дальше мы будем активно работать с инструментом live-build. На Ubuntu и её производных тоже можно попробовать, но я не могу гарантировать, что всё соберётся без ошибок и дополнительных танцев с бубном.

Почему именно live-build? Я выбрал именно этот инструмент, потому что на мой взгляд это один из самых простых и удобных способов создания кастомных live-образов. В нем можно контролировать состав системы, размер образа и уровень минимализма, при этом не требуя глубоких знаний низкоуровневой сборки.

Сначала установим все необходимые пакеты:
Code:
sudo apt install live-build squashfs-tools xorriso isolinux syslinux-common syslinux-efi grub-efi-amd64-bin mtools dosfstools live-boot live-config live-boot-initramfs-tools debootstrap apt-utils rsync gnupg dpkg-dev
 
После установки пакетов создаём рабочую папку для дистрибутива:
Code:
mkdir my-ermine

Я назвал свой проект ermine в честь горностая.
Почему именно горностай? 
Это довольно мелкий зверь, но при этом невероятно ловкий, юркий и универсальный: он отлично плавает, лазает по деревьям и в целом очень быстрый. А ещё зимой он полностью становится белым, мастерски маскируясь под окружающую среду. Из-за этого поймать горностая крайне сложно, скажу больше он один из самых неуловимых хищников среди животных своего размера. Но даже если его всё-таки загнать в угол, гоностай очень смелый и яростно защищается.

Мне показалось, что это отличная метафора для моего дистрибутива. Он минималистичный и довольно лёгкий, но при этом содержит всё необходимое для безопасной работ (браузер, кошелёк и тд). Кроме того, система достаточно приватная, а в плане защиты очень "юркая" её действительно сложно "поймать"(то есть взломать), потому что вектор атаки давольно небольшой. Ну и честно признаюсь горностаи просто очень прикольные зверьки.


Сборка с live-build
Что ж, с названием дистрибутива мы разобрались, папку создали, необходимые инструменты установили можно наконец приступать к самой сборке.

Для начала инициализируем среду и сгенерируем базовую конфигурацию live-build, которую в дальнейшем будем подстраивать под себя и дополнять нужными пакетами:
Code:
 lb config \
--distribution bookworm \
--system live \
--binary-images iso-hybrid \
--archive-areas "main contrib non-free non-free-firmware" \
--bootloader grub-pc \
--debian-installer false \
--debootstrap-options "--variant=minbase"

Эта команда создаёт начальную структуру проекта и настраивает основные параметры будущей live-системы. Она указывает, что мы собираем образ на базе Debian Bookworm, в формате iso-hybrid (который можно записать как на флешку, так и на диск), использует GRUB в качестве загрузчика, отключает графический установщик Debian и создаёт максимально минимальную базовую систему с помощью debootstrap в режиме minbase. Всё остальное мы будем добавлять позже вручную.

Я буду вносить изменения в дистибутив и собирать его командой lb build. Эта команда создает файловую систему и итоговый iso проекта

Вот пример тестовой сборки:
Не удалось прогрузить медиа


Что должно появиться после сборки:
Не удалось прогрузить медиа

Если всё прошло успешно, в папке binary появятся несколько файлов. live-image-amd64.hybrid.iso это готовый загрузочный ISO-образ, который можно записать на флешку. chroot.packages.install содержит список всех пакетов, которые были установлены в систему во время сборки. chroot.packages.live показывает пакеты, специфичные именно для live-режима. live-image-amd64.packag- полный список всего, что попало в итоговый образ. chroot.files и live-image-amd64.files содержат списки файлов, а live-image-amd64.contents показывает структуру директорий внутри образа. binary.modified_timestamps нужен live-build, чтобы понимать, что изменилось с прошлой сборки.


Деректории проекта
Но перед основной настройкой параметров дистрибутива давай я подробнее расскажу про важные директории, с которыми в основном придеться работать.
После выполнения команды lb config у нас появится несколько папок: config, auto, local, а чуть позже, во время сборки, также chroot и некоторые другие:
Не удалось прогрузить медиа

Самые важные для нас это именно config и chroot. В chroot во время сборки будет находиться файловая система нашей будущей live-ОС. По сути, это "корень" системы, который мы собираем. Всё, что там находиться, в итоге окажется внутри готового образа.

Теперь про папку config. Именно здесь мы будем вносить основные изменения:
Не удалось прогрузить медиа

Внутри неё не давольно много подпапок, но при сборке я мы будем работать только с пятью из них.  Главные это hooks, includes.chroot и package-lists. Также иногда придеться заглядывать в includes.binary и archives.Разберём по порядку, что делает каждая из них.

Самая важная и часто используемая hooks. Сюда мы кладём скрипты(хуки), которые выполняются на разных этапах сборки. С их помощью можно автоматически включать или отключать сервисы, создавать пользователей, чистить систему и тд.

Дальше includes.chroot. Всё, что лежит в этой папке, будет скопировано "как есть" в chroot, а позже в готовый образ. Поэтому сюда удобно класть свои конфиги, скрипты, обои, или любые другие файлы, которые должны сразу оказаться в системе.

Следующая не менее важная директория это package-lists. Здесь мы создаём списки дополнительных пакетов, которые нужно установить в систему. Пакеты из этих списков устанавливаются через apt во время сборки.  Похожая по смыслу папка archives. Только вместо пакетов сюда добавляются источники репозиториев (например, сторонние репозитории или backports), если тебе нужны пакеты, которых нет в стандартных архивах Debian.

И наконец includes.binary. В ней можно кастомизировать всё, что касается непосредственно ISO-образа. Грубо говоря, сюда кладутся файлы, которые после сборки окажутся прямо в корне ISO(папки boot/, EFI/, isolinux/ и тд). Сюда удобно добавлять свои версии загрузчика, дополнительные EFI-файлы, кастомные меню, картинки или любые другие файлы, которые должны лежать на самом образе, а не внутри live-системы.


Базовая настройка
Дальше когда я проверил текстовую сбоку на рабосбоность время притупить к второму этапу. Сначала я решил установить стандартные пакеты. Мы же не хотим, чтобы наш дистрибутив запустился без интерфейса и базовых инструментов.

Вся настройка пакетов происходит в папке /config/package-lists. Для начала я создал эту папку:
Code:
mkdir -p config/package-lists

Я решил не делать один огромный список, а разбить пакеты на несколько разных файлов. Мне кажется, так гораздо удобнее их редактировать и менять в будущем.
Первый список config/package-lists/xfce.list.chroot. Он содержит интерфейс и основные программы:
Code:
systemd-sysv
xfce4-panel
xfce4-session
xfce4-settings
xfwm4
xfdesktop4
thunar
thunar-archive-plugin
thunar-volman    
xfce4-terminal
xfce4-taskmanager
sudo
wget
curl
nano
Здесь собрано всё необходимое для XFCE: панель, сессия, оконный менеджер, рабочий стол, файловый менеджер Thunar, терминал, диспетчер задач и базовые утилиты.

Второй список config/package-lists/live.list.chroot. Это базовые пакеты самой live-системы:
Code:
linux-image-amd64
live-boot
live-config
systemd
systemd-sysv
ca-certificates
lightdm
iptables
iptables-persistent
Там есть ядро, live-boot и live-config отвечают за запуск live-системы, lightdm это графический вход в систему(который мы позже будем настраивать), а iptables нужен для настройки нашего kill-switch позже.

Так как я хочу, чтобы в моем дистрибутиве был и sudo, и юзер мог свободно работать в терминале, я решил создать отдельного пользователя.
Для этого я просто написал хук по пути: config/hooks/normal/2000-live-user.hook.chroot

В папке hooks есть две основные подпапки: normal и live. 
Я использую именно normal, потому что эти хуки выполняются внутри chroot во время сборки системы, а не на уже загруженной live-системе. В live хуки запускаются уже после загрузки готового образа. Мне же нужно было создать пользователя именно на этапе сборки, поэтому я выбрал папку normal. К тому же в ней обычно и размещают пользовательские скрипты.

Вот сам хук:
Bash:
#!/bin/bash
set -e

if ! id ermine >/dev/null 2>&1; then
    useradd -m -s /bin/bash ermine
    echo "ermine:ermine" | chpasswd
fi

adduser ermine sudo
Этот скрипт проверяет, существует ли уже пользователь ermine. Если нет создаёт его с домашней папкой и оболочкой bash, сразу ставит пароль ermine, а потом добавляет пользователя в группу sudo.

После создания хука его обязательно нужно сделать исполняемым, иначе live-build его просто проигнорирует:
Code:
chmod +x config/hooks/normal/2000-live-user.hook.chroot

Итоговый юзер:
Не удалось прогрузить медиа


Когда юзер был добавлен я решил разобраться с сетью, a именно настроить NetworkManager. Всё потому что без сети, не комфортная работа с системой, не тем более без kill-switch с будут невозможны.

Для этого я создал файл config/package-lists/network.list.chroot и добавил туда два пакета:
Code:
network-manager
network-manager-gnome
Первый пакет это сам менеджер сети, который отвечает за подключения, Wi-Fi, Ethernet и всё остальное. А второй network-manager-gnome это графический интерфейс, через который пользователь может удобно выбирать сети, подключаться, и тд.

Но этого оказалось недостаточно. По умолчанию сервис NetworkManager не запускается автоматически при старте системы. Чтобы исправить это, я создал ещё  хук config/hooks/normal/5000-networkmanager.hook.chroot.

Вот его содержимое:
Bash:
#!/bin/bash
set -e

systemctl enable NetworkManager
Скрипт просто включает автозапуск сервиса NetworkManager, чтобы он стартовал сразу при загрузке системы.


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


 Я сделал два варианта загрузки: один работает полностью с флешки(почти как в Tails), а второй запускает систему полностью в оперативной памяти(RAM mode). Оба варианта относительно безопасны, и я считаю, что дать пользователю выбор это хорошая практика.

Мой код загрузчика GRUB лежит в файле config/includes.binary/boot/grub/grub.cfg:
Bash:
source /boot/grub/config.cfg

set default=0
set timeout=4

menuentry "ERMINE OS" --unrestricted {
    linux /live/vmlinuz-6.1.0-44-amd64 boot=live components quiet splash apparmor=1 security=apparmor findiso=${iso_path}
    initrd /live/initrd.img-6.1.0-44-amd64
}

menuentry "ERMINE OS (RAM mode)" --unrestricted {
    linux /live/vmlinuz-6.1.0-44-amd64 boot=live components toram=filesystem.squashfs overlay-size=70% quiet splash apparmor=1 security=apparmor findiso=${iso_path}
    initrd /live/initrd.img-6.1.0-44-amd64
}

menuentry "Safe Mode" {
    linux /live/vmlinuz-6.12.74+deb12-amd64 boot=live components nomodeset noapic noapm nodma nomce nosmp nosplash
    initrd /live/initrd.img-6.12.74+deb12-amd64
}

if [ "${grub_platform}" = "efi" ]; then
    menuentry "UEFI Firmware Settings" {
        fwsetup
    }
fi

Этот код создаёт таймаут 4 секунды при появлении меню, а так же даёт пункта в загрузке: обычный режим работы с флешки, режим полного запуска в оперативной памяти(RAM mode) и безопасный режим. Кстати, изначально я пытался добавить эти изменения в includes.chroot. Но ничего не работало.  Проблема была в том, что includes.chroot копирует файлы уже внутрь готовой системы (в chroot), а конфигурация GRUB нужна на уровне самого ISO-образа, ещё до загрузки ядра. Поэтому пришлось класть файлы конфигурации grub в config/includes.binary который добавляет файлы напрямую в готовый ISO-образ.

Но после написания кода у тебя может возникнуть вопрос: как именно работают разные варианты загрузки и чем они отличаються?

Первый вариант 
- ERMINE OS монтирует образ filesystem.squashfs прямо с USB-флешки. Все изменения и временные файлы во время работы системы пишутся в tmpfs. Tmpfs существует только в оперативной памяти, а значит исчезает при выключении компьютера. Из за этого основной жёсткий диск практически ничего не записывается(кроме небольшого количества служебных данных в /run и /var/run).

Второй вариант работает немного поинтереснее. Здесь система копирует необходимые данные в оперативную память, и после успешной загрузки флешку можно даже вытащить.
Сначала я хотел реализовать RAM-режим через обычный параметр toram=1. Но при такой загрузке система сразу падала с ошибкой:
Kernel panic not syncing: Attempted to kill init!
Эта ошибка обычно возникает, когда ядро пытается завершить процесс init, но не может из-за нехватки памяти или проблемы на раннем этапе загрузки. Поскольку я знал, что мой дистрибутив в работает нормально, пя понял что проблема именно в нехватке RAM.

Я попробовал сильно ужать размер образа с помощью флагов --apt-indices false и --apt-recommends false. Первый флаг отключает скачивание индексов пакетов, а второй запрещает установку рекомендуемых пакетов. Размер действительно заметно уменьшился, но при этом начали ломаться важные функции, в том числе интерфейс.

Поэтому я отказался от идеи сильно уменьшать систему и выбрал другой подход - zramswap. В отличие от toram=1, zramswap работает умнее и экономнее. Он создаёт в оперативной памяти сжатый блок(zram) и использует его как быстрый swap. Система загружается в обычном live-режиме, подгружая файлы по мере необходимости, а самые часто используемые данные автоматически сжимаются и остаются в zram.

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

Третий режим Safe Mode же нужен на случай, когда система по какой-то причине не хочет нормально загружаться. Например, из-за проблем с видеокартой, новых драйверов или несовместимого железа. В нем я специально отключаю почти все современные функции ядра, которые часто вызывают проблемы. Графика может работать хуже, а скорость будет ниже, зато шансы, что система хотя бы запустится, сильно возрастают. При этом система всё ещё работает полностью с флешке (никаких изменений на основной жёсткий диск компьютера не записывается).

Чтобы второй режим работал, я добавил пакет zram-tools через файл config/package-lists/zram.list.chroot:
Code:
zram-tools

А автозапуск настраивается через хук config/hooks/normal/9990-zram-enable.hook.chroot:
Bash:
#!/bin/sh
set -e
systemctl enable zramswap.service || true
Этот хук просто включает systemd-сервис zramswap, чтобы он запускался автоматически при каждой загрузке.

А вот конфигурация самого zram, которую я разместил в config/includes.chroot/etc/default/zram-tools:
ALGO=lz4
PERCENT=75
PRIORITY=100
ALGO= задаёт алгоритм сжатия lz4 выбран потому, что он очень быстрый. Значение PERCENT означает, что под zram можно отдать до 75% от всей оперативной памяти. А PRIORITY устанавливает высокий приоритет этому swap-разделу, чтобы система в первую очередь использовала именно его.

Когда основной функционал GRUB готов, можно наконец заняться его украшательством! Если ты не любишь всякие красивости, то этот раздел можно смело пропустить. А для тех, кому интересно сейчас я покажу, как сделать приятную тему grub со своими обоями.

Для начала я положил свой файл с обоями в папку config/includes.binary/boot/grub/ и назвал его splash.png.

После этого создал файл config/includes.binary/boot/grub/config.cfg. Вот его содержимое:

Code:
set default=0

if [ x$feature_default_font_path = xy ] ; then
    font=unicode
else
    font=$prefix/unicode.pf2
fi

if loadfont $font ; then
    set gfxmode=800x600
    set gfxpayload=keep
    insmod efi_gop
    insmod efi_uga
    insmod video_bochs
    insmod video_cirrus
else
    set gfxmode=auto
    insmod all_video
fi

insmod gfxterm
insmod png

source /boot/grub/theme.cfg

terminal_output gfxterm

insmod play
play 960 440 1 0 4 440 1
Этот конфиг в основном занимается подготовкой: загружает нужные шрифты и модули, настраивает графический режим, включает поддержку png-картинок и подключает файл с темой. По сути, он почти ничего не делает для "красоты", кроме запуска приятного короткого звука при загрузке меню и подключения темы.

А вот настоящее добавление темы происходит в файле config/includes.binary/boot/grub/theme.cfg:
Code:
set color_normal=light-gray/black
set color_highlight=white/dark-gray

if [ -e /isolinux/splash.png ]; then
    # binary_syslinux modifies the theme file to point to the correct
    # background picture
    set theme=/boot/grub/live-theme/theme.txt
elif [ -e /boot/grub/splash.png ]; then
    set theme=/boot/grub/live-theme/theme.txt
else
    set menu_color_normal=cyan/blue
    set menu_color_highlight=white/blue
fi
Этот файл устанавливает базовые цвета меню и проверяет, существует ли файл с обоями. Если обои найдены, он подключает кастомную тему theme.txt. Если обои нет просто включает стандартную синюю тему.

И наконец, самый важный файл config/includes.binary/boot/grub/live-theme/theme.txt.  Вот его содержимое:
CSS:
desktop-image: "../splash.png"

title-color: "#b2b9c2"
title-text: "ermine"

+ label {
        top = 100%-50
        left = 0
        width = 100%
        height = 22
        text = "@KEYMAP_SHORT@"
        align = "center"
        color = "#b2b9c2"
}

+ boot_menu {
        left = 12%
        width = 76%
        top = 48%
        height = 45%

        item_color = "#8a94a3"
        selected_item_color = "#e0e8f5"

        item_height = 22
        item_padding = 8
        item_spacing = 6
}

+ progress_bar {
        id = "__timeout__"
        left = 15%
        top = 100%-75
        height = 20
        width = 70%

        text_color = "#242c38"
        fg_color = "#b2b9c2"
        bg_color = "#1c2330"
        border_color = "#4a556b"
        text = "@TIMEOUT_NOTIFICATION_LONG@"
}
Этот файл делает основную красоту: ставит мой splash.png на фон, задаёт цвет заголовка и текст "ermine", рисует красивое меню загрузки с приятными цветами, а также добавляет прогресс-бар внизу, который показывается при таймауте.

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



Установка AppArmor
Загрузка дистрибутива готова, а значит можно переходить к безопасности. А именно к установке и настройке AppArmor для моих будущих политик. Сначала мне нужно было добавить необходимые пакеты, потому что в стандартном Debian Live их по умолчанию нет.

Для этого я создал файл config/package-lists/apparmor.list.chroot со следующим содержимым:
Code:
apparmor
apparmor-utils
apparmor-profiles
Первый обычный apparmor который принудительного контроля доступа. apparmor-utils содержит утилиты для работы с профилями. А apparmor-profiles добавляет готовые профили безопасности для многих программ.

Чтобы AppArmor запускался автоматически при старте системы, нужно было создать systemd-сервис. Дело в том, что в live-окружении AppArmor не всегда стартует сам по себе, особенно если мы хотим, чтобы профили загружались очень рано.

Сервис я разместил по пути includes.chroot/etc/systemd/system/apparmor.service. Вот его код:
Bash:
[Unit]
Description=Load AppArmor profiles
DefaultDependencies=no

Before=sysinit.target
After=local-fs.target
After=systemd-journald-audit.socket

ConditionSecurity=apparmor

[Service]
Type=oneshot
ExecStart=/lib/apparmor/apparmor.systemd reload
ExecReload=/lib/apparmor/apparmor.systemd reload
ExecStop=/bin/true
RemainAfterExit=yes

[Install]
WantedBy=sysinit.target
Этот сервис немного отличается от стандартного. Он запускается очень рано(ещё до sysinit.target), использует тип oneshot и остаётся активным после выполнения.

И наконец, я добавил хук, который включает автозапуск сервиса config/hooks/normal/4000-apparmor-enable.hook.chroot:
Bash:
#!/bin/bash
set -e

systemctl enable apparmor

Ещё одно важное замечание: ты наверняка заметил, что в каждом пункте загрузки в GRUB у меня стоит параметр apparmor=1. Это не просто так. В live-системах AppArmor по умолчанию часто отключён, и без этого параметра ядра наши политики просто не применились бы даже при наличие сервиса для автозапуска.

Проверяем работает ли apparmor:
Не удалось прогрузить медиа



Настройка кошелька
Что ж, вот мы и разобрались с окружением, теперь пришло время основных программ в Ermine. 
Первым делом я решил заняться Cake Wallet, так как это одна из самых простых вещей в настройке. Но несмотря на простоту, он очень важен: именно через него будут проходить все транзакции пользователя, поэтому нужно настроить его максимально удобно и аккуратно.

Сначала я создал хук config/hooks/normal/3000-cakewallet.hook.chroot, чтобы установить Cake Wallet как полноценное приложение с иконкой в меню и на рабочем столе.

Вот самые важные части скрипта:
Bash:
#!/bin/bash
set -e
apt-get update
apt-get install -y wget tar xz-utils ca-certificates

cd /opt
URL="https://github.com/cake-tech/cake_wallet/releases/download/v5.9.0/Cake_Wallet_v5.9.0_Linux.tar.xz"
wget -O cakewallet.tar.xz "$URL"
tar -xf cakewallet.tar.xz
DIR=$(find . -maxdepth 1 -type d -name "*Cake_Wallet*" | head -n 1)

mv "$DIR" cakewallet
rm -f cakewallet.tar.xz
BIN=$(find cakewallet -type f -name "cake_wallet" -executable | head -n 1)
chmod +x "$BIN"
ln -sf "/opt/$BIN" /usr/local/bin/cakewallet
Здесь скрипт просто скачивает Cake Wallet, распаковывает его в /opt/ и создаёт удобную команду cakewallet, чтобы программу можно было запускать из терминала.

Далее создаётся desktop-файл на рабочий стол пользователя ermine:
Bash:
DESKTOP_DIR=$(su - ermine -c "echo \$HOME")/Desktop
mkdir -p "$DESKTOP_DIR"

cat > "$DESKTOP_DIR/cake-wallet.desktop" << 'EOF'
[Desktop Entry]
Version=1.0
Name=Cake Wallet
GenericName=Monero Wallet
Comment=Privacy-focused cryptocurrency wallet
Exec=/opt/cakewallet/cake_wallet
Icon=/opt/cakewallet/data/flutter_assets/assets/images/cakewallet_logo.png
Terminal=false
Type=Application
Categories=Finance;Network;
StartupWMClass=cake_wallet
EOF

chown ermine:ermine "$DESKTOP_DIR/cake-wallet.desktop"
chmod 755 "$DESKTOP_DIR/cake-wallet.desktop"
Тут всё довольно стандартно: создаётся ярлык, прописывается путь к исполняемому файлу и иконке. Единственное, что интересное тут есть это правильный полный путь к иконке внутри папки Cake Wallet. В остальном запуск приложения происходит как у обычной программы.

После создания хука его, конечно, нужно сделать исполняемым:
Code:
chmod +x config/hooks/normal/3000-cakewallet.hook.chroot

И в конце я создал хук hooks/normal/5000-cake_wallet-enable.hook.chroot, который подготавливает нужные папки для кошелька:
Bash:
#!/bin/bash

mkdir -p /home/ermine
chown -R ermine:ermine /home/ermine
chmod 755 /home/ermine

mkdir -p /home/ermine/.config/cake_wallet
mkdir -p /home/ermine/.cache/cake_wallet
mkdir -p /home/ermine/.local/share/cake_wallet

chown -R ermine:ermine /home/ermine/.config /home/ermine/.cache /home/ermine/.local
chmod -R 755 /home/ermine/.config /home/ermine/.cache /home/ermine/.local
Этот скрипт создаёт домашнюю папку пользователя ermine (если её ещё нет), а также директории для конфигов, кэша и данных Cake Wallet: .config/cake_wallet, .cache/cake_wallet и .local/share/cake_wallet. Потом он правильно выставляет права доступа, чтобы только пользователь ermine мог работать с этими папками. Это нужно в первую очередь для правильной работы AppArmor чтобы политика могла разрешить доступ только к этим конкретным папкам, а не ко всему домашнему каталогу.

Вот как выглядит кошелек:
Не удалось прогрузить медиа



И вот мы дошли до самого интересного создания политики AppArmor для кошелька. Все политики лежат в папке includes.chroot/etc/apparmor.d/.

Вот код самой политики для Cake Wallet includes.chroot/etc/apparmor.d/cakewallet:
C-like:
#include <tunables/global>
 
profile cakewallet /opt/cakewallet/cake_wallet {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  #include <abstractions/ssl_certs>
  #include <abstractions/fonts>
  #include <abstractions/audio>
 
  network tcp,
  network udp,
  network netlink raw,
  network unix,
 
  /opt/cakewallet/** rix,
 
  owner @{HOME}/.config/cake_wallet/** rwk,
  owner @{HOME}/.cache/cake_wallet/** rwk,
  owner @{HOME}/.local/share/cake_wallet/** rwk,
 
  /dev/dri/** rw,
  /dev/dri/card* rw,
  /dev/dri/renderD* rw,
 
  /sys/devices/pci*/** r,
  /sys/devices/** r,
 
  /etc/fonts/** r,
  /usr/share/fonts/** r,
  /usr/local/share/fonts/** r,
 
  /tmp/.X11-unix/** rw,
  unix (connect, send, receive) type=stream,
  unix (connect, send, receive) type=dgram,
 
  /usr/lib/** mr,
  /lib/** mr,
 
  deny capability sys_ptrace,
  deny capability sys_admin,
  deny capability sys_rawio,
 
  audit deny /proc/** w,
}

Эта политика разрешает Cake Wallet читать и выполнять файлы только внутри своей папки /opt/cakewallet, работать только со своими конфигами и кэшем. Также разрешает доступ к видеокарте (для нормального отображения), шрифтам и некоторым системным директориям, которые нужны для запуска(я тестировал без них и Cake Wallet просто нормально не запускался). При этом запрещает опасные возможности (например, ptrace, sys_admin), а все попытки писать в /proc будут логироваться.

Вот как это выглядит в aa-status:
Не удалось прогрузить медиа



Установка и настройка i2p
Что ж, дорогой читатель, вот мы и добрались до i2p одного из главных отличий моей системы от Tails, где его нет из коробки.
Я решил установить i2pd это C++-версия i2p. Выбрал её по нескольким причинам. Во-первых, она имеет гораздо меньший объём кода по сравнению с классической Java-версией. Во-вторых, меньший размер кода означает и меньшую поверхность атаки. Кроме того, i2pd быстрее запускается, потребляет меньше памяти, лучше работет на старых ноутах с ограниченным ресурсами и да ещё и имеет более современную архитектуру.

Помимо самого демона, я решил добавить простой графический интерфейс. Через него можно будет одной кнопкой запустить i2p, остановить его или быстро посмотреть текущий статус.

Чтобы добавить i2pd я сначала добавил пакет в список config/package-lists/i2pd.list.chroot:
Code:
i2pd

Дополнительно я установил утилиту zenity через файл config/package-lists/gui-extra.list.chroot:
Code:
zenity
Она нужна, чтобы создавать простые графические окна и диалоги-именно с её помощью я сделаю интерфейс для управления i2pd.

После нужно было добавить официальный репозиторий i2pd, потому что пакет из стандартных репозиториев Debian может быть устаревшим. Для этого я создал хук config/hooks/normal/5500-i2pd-install.hook.chroot.

Вот что делает этот скрипт:
Bash:
#!/bin/bash
set -e

apt-get update
apt-get install -y wget gnupg apt-transport-https ca-certificates

wget -q -O - https://repo.i2pd.xyz/.help/add_repo | bash

apt-get update
apt-get install -y i2pd

Он просто устанавливает необходимые инструменты для работы с репозиториями, затем скачивает и выполняет официальный скрипт добавления репозитория i2pd, и дополнительно обновляет списки пакетов и в конце устанавливает сам пакет i2pd.

И вот мы с вами добрались до главного настройки i2pd. Для этого я создал хук config/hooks/normal/3200-i2pd.hook.chroot.
В нём довольно много всего: от создания конфигов до создания графического интерфейса. Потому я решил разбить скрипт на несколько частей, чтобы проще было объяснять весь его функционал.

Первая часть просто создает папку i2pd и добавляет права:
Bash:
mkdir -p /etc/i2pd
chmod 700 /etc/i2pd

Дальше я добавлю основной конфиг i2pd, который лежит в файле /etc/i2pd/i2pd.conf он давльно длнный так что отавлю только самые вадные парметры:
Bash:
cat > /etc/i2pd/i2pd.conf << 'EOF'
ipv4 = true
ipv6 = false
notransit = true
share = 100
log = file
loglevel = warn

[httpproxy]
enabled = true
address = 127.0.0.1
port = 4444

[socksproxy]
enabled = true
address = 127.0.0.1
port = 4447

[http]
enabled = true
address = 127.0.0.1
port = 7070

[reseed]
verify = true
urls = https://reseed.i2p.rocks/,https://reseed-fr.i2pd.xyz/,https://i2p.novg.net/,https://reseed.i2p.io/

[limits]
transittunnels = 0
EOF

chmod 600 /etc/i2pd/i2pd.conf

В целом мой конфиг похож на стандартный, но я специально подкрутил несколько параметров в сторону большей безопасности и минимализма. Я отключил IPv6, полностью запретил быть транзитным узлом (notransit = true), выключил все ненужные интерфейсы управления (SAM, BOB, I2CP, I2PControl и UPnP). Оставил только два рабочих прокси: HTTP на порту 4444 (для браузера) и SOCKS на порту 4447 (для других программ).
Единственный спорный момент в моем конфиге это параметр share. Сначала я хотел поставить share = 0, чтобы вообще не раздавать чужой трафик, но тогда i2p очень долго подключался и работал крайне медленно. Значение 100 оказалось минимальным, при котором сеть нормально функционирует. В конце я поставил права 600 на файл конфига, чтобы его мог читать только root.

Потом я сделал конфиг для туннелей:
Bash:
cat > /etc/i2pd/tunnels.conf << 'EOF'
[IRC-ILITA-Paranoid]
type = client
address = 127.0.0.1
port = 6668
destination = irc.ilita.i2p
destinationport = 6667
inbound.length = 5
outbound.length = 5
inbound.quantity = 5
outbound.quantity = 5
i2cp.close.idletimeout = 480

[IRC-IRC2P-Paranoid]
type = client
address = 127.0.0.1
port = 6669
destination = irc.postman.i2p
destinationport = 6667
inbound.length = 5
outbound.length = 5
inbound.quantity = 5
outbound.quantity = 5
i2cp.close.idletimeout = 480
EOF

chmod 600 /etc/i2pd/tunnels.conf

Я добавил туда два клиентских туннеля для подключения к IRC-серверам внутри i2p-сети. Из за этого когда  ты запускаешь IRC-клиент то говоришь ему подключаться не напрямую к какому-то адресу, а к обычному локальному порту на твоей машине. Дальше i2pd перехватывает это соединение и автоматически направляет его через цепочку узлов i2p.
Первый мой туннель называется IRC-ILITA-Paranoid и перенаправляет всё, что приходит на локальный порт 6668, на сервер irc.ilita.i2p:6667. Второй туннель это IRC-IRC2P-Paranoid перенаправляет порт 6669 на сервер irc.postman.i2p:6667.
На оба туннеля я поставил inbound.length = 5 и outbound.length = 5 благодаря этим натройкам весь трафик будет проходить через пять промежуточных узлов. Каждый узел в этой цепочке знает только предыдущий и следующий узел, но не видит всю картину целиком. Поэтому чем больше узлов, тем выше уровень уровень приватности, но задержка при соединении больше.
Также я добавил параметр i2cp.close.idletimeout = 480. Он означает, что если туннель долго не используется, то через 8 минут он автоматически закроется. А в конце как и на i2pd.conf я поставил права 600 на файл.

После этого я сделал автозапуск i2pd:
Code:
systemctl enable i2pd || true

Наконец то мы с тобой дошли до графического интерфейса упаления i2p:
Bash:
cat > /usr/local/bin/i2p-launcher << 'EOS'
#!/bin/bash
set -e

CHOICE=$(zenity --list \
  --title="I2P Control" \
  --column="Action" \
  "Start i2pd" \
  "Stop i2pd" \
  "Status" \
  "View log")

case "$CHOICE" in
  "Start i2pd")
    sudo systemctl start i2pd
    zenity --info --text="i2pd started"
    ;;
  "Stop i2pd")
    sudo systemctl stop i2pd
    zenity --info --text="i2pd stopped"
    ;;
  "Status")
    systemctl status i2pd | zenity --text-info --width=800 --height=600
    ;;
  "View log")
    journalctl -u i2pd -n 100 | zenity --text-info --width=800 --height=600
    ;;
  *) exit 0 ;;
esac
EOS

chmod +x /usr/local/bin/i2p-launcher

Эта часть скрипта создаёт простое графическое меню с помощью утилиты Zenity. Сама утилита Zenity позволяет из bash-скриптов создавать диалоговые окна, не пиша полноценный графический интерфейс. Она использует библиотеку GTK (ту же, на которой построен рабочий стол GNOME). После того как пользователь выбирает нужный пункт в созданом интерфейсе и нажимает кнопку, Zenity возвращает выбранный текст в переменную CHOICE. Далее конструкция case анализирует значение этой переменной и выполняет соответствующую команду. В моем случае после нажатия выполняються команды запуска i2pd, остановки, просмотра статуса или последних 100 строк лога.

И конечно, без отдельной иконки на рабочем столе нашему i2p-launcher не обойтись:
Bash:
mkdir -p /home/ermine/Desktop

cat > /home/ermine/Desktop/I2P.desktop <<EOF
[Desktop Entry]
Name=I2P
Exec=/usr/local/bin/i2p-launcher
Icon=network-vpn
Type=Application
Terminal=false
EOF

chown -R ermine:ermine /home/ermine/Desktop
chmod 755 /home/ermine/Desktop/I2P.desktop

Этот блок создаёт обычный ярлык с названием I2P прямо на рабочий стол пользователя ermine. В нём прописано, что при клике по иконке должен запускаться скрипт /usr/local/bin/i2p-launcher, который мы сделали раньше. Иконка берётся стандартная network-vpn. После создания ярлыка я устанавливаю правильные права, чтобы пользователь ermine мог его видеть и запускать.

И в конце может показаться, что идёт не самая значительная часть скрипта, но, на мой взгляд, она довольно важная.
Речь идёт о добавлении нужных прав доступа к i2pd:
Bash:
chown -R i2pd:i2pd /etc/i2pd

На самом деле это одна из самых важных строк во всём хуке. Когда я первый раз тестировал систему, я долго не мог понять, почему запуск i2pd не работет. Я проверял конфиги, смотрел логи вроде всё было правильно, ошибок нет. Но сервис упорно не стартовал. В итоге оказалось, что проблема была в правах доступа. Дело в том, что сервис i2pd работает будет работать не от пользователя ermine или даже от от root. I2pd работает только от специального системного пользователя i2pd, который создаётся автоматически при установке пакета. Этот пользователь i2pd запускается для повышения безопасности, чтобы даже если кто-то взломает i2pd, он не смог получить права обычного пользователя или root. Но из-за этого у него по умолчанию нет доступа к файлам в папке /etc/i2pd. Потому без команды chown -R i2pd:i2pd /etc/i2pd сервис просто не может прочитать свои конфигурационные файлы.

Вот как выглядит панель:
Не удалось прогрузить медиа


Вот что происходит при выборе графическом интерфейсе status:
Не удалось прогрузить медиа



Подмена отпечатка в будующем Tor Browser
После настройки i2pd я решил заняться подменой fingerprint браузера. 
На самом деле, по количеству нервов, времени и моих неудачных тестов это оказалось одним из самых сложных и интересных мест во всей моей сборке. Сложнее, пожалуй был только kill-switch, но о нём я расскажу чуть позже.

Как я уже говорил в описании концепции, Tor Browser в последние годы перестал полностью скрывать многие параметры, которые помогают идентифицировать пользователя. Простыми about:config настройками это уже не фиксится, как было в Firefox. Поэтому пришлось импровизировать. В итоге я написал свой собственный плагин для подмены отпечатка.

Я назвал его Fingerprint Spoofer. Вот его manifest.json:
JSON:
{
  "manifest_version": 2,
  "name": "Fingerprint Spoofer",
  "version": "1.2",
  "description": "Advanced fingerprint spoofer",
  "icons": {
    "48": "icon.png"
  },
  "applications": {
    "gecko": {
      "id": "[email protected]",
      "strict_min_version": "78.0"
    }
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["injector.js"],
      "run_at": "document_start",
      "all_frames": true
    }
  ],
  "permissions": []
}
Этот манифест довольно простой. Он загружает иконку расширения и главное подключает мой скрипт injector.js. Скрипт запускается на каждой странице максимально рано и работает во всех фреймах. Из за этого плагин меняет JavaScript на сайте ещё до того, как страница начнёт собирать информацию об окружении браузера.

После манифеста я создал главный файл injector.js именно в нём происходит вся основная подмена отпечатка браузера. На самом деле скрипт получился довольно длинным, поэтому я покажу здесь только самые важные части.

Код начинается с установки конфигурации:
JavaScript:
const CONFIG = {
    USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
    TIMEZONE: 'America/New_York',
    TIMEZONE_OFFSET: 300,
    LOCALE: 'en-US',
    POPULAR_FONTS: ['Arial', 'Times New Roman', 'Courier New', 'Calibri', 'Segoe UI'],
    SCREEN: { width: 1920, height: 1080, availWidth: 1920, availHeight: 1040, devicePixelRatio: 1 },
    NAVIGATOR: {
        oscpu: 'Windows NT 10.0; Win64; x64',
        hardwareConcurrency: 8,
        platform: 'Win32',
        deviceMemory: 8,
        vendor: 'Google Inc.'
    },
    WEBGL: { vendor: 'Intel', renderer: 'Intel(R) UHD Graphics 630' },
    AUDIO: { sampleRate: 44100 }
};
Здесь я просто задаю все значения, которые хочу подменить: user-agent, часовой пояс, разрешение экрана, характеристики железа, WebGL и тд.

Далее идёт вспомогательная функция для безопасной подмены свойств:
JSON:
function safeDefine(obj, prop, value) {
                try {
                    if (Object.getOwnPropertyDescriptor(obj, prop)?.configurable === false) return;
                    delete obj[prop];
                    Object.defineProperty(obj, prop, { configurable: true, get: () => value });
                } catch(e) {}
            }
Она нужна, что
бы переопределять свойства объектов. Если свойство нельзя изменить(non-configurable), скрипт просто пропускает его, чтобы не вызвать ошибку.

Затем происходит сама подмена основных параметров:
JSON:
safeDefine(navigator, 'userAgent', CONFIG.USER_AGENT);
            Object.entries(CONFIG.NAVIGATOR).forEach(([k,v]) => safeDefine(navigator, k, v));
            safeDefine(navigator, 'language', CONFIG.LOCALE);
            safeDefine(navigator, 'languages', [CONFIG.LOCALE]);

            Object.entries(CONFIG.SCREEN).forEach(([k,v]) => safeDefine(screen, k, v));
            safeDefine(window, 'innerWidth', CONFIG.SCREEN.width);
            safeDefine(window, 'innerHeight', CONFIG.SCREEN.availHeight);
            safeDefine(window, 'outerWidth', CONFIG.SCREEN.width);
            safeDefine(window, 'outerHeight', CONFIG.SCREEN.height);
            safeDefine(window, 'devicePixelRatio', CONFIG.SCREEN.devicePixelRatio);
На этом этапе мы подменяем user-agent, информацию о платформе, языки, разрешение экрана и другие важные характеристики, которые сайты часто используют для fingerprinting. Функция safeDefine() сначала пытается удалить оригинальное свойство, а потом заново создаёт его с помощью Object.defineProperty, но уже с геттером, который всегда возвращает наше поддельное значение.

Дальше идёт подмена даты и часового пояса:
JavaScript:
const OrigDate = Date;
            function FakeDate(...args) {
                if (args.length === 0) {
                    const d = new OrigDate();
                    d.setHours(d.getHours() + 6);
                    return d;
                }
                return new OrigDate(...args);
            }
            FakeDate.now = () => new OrigDate().getTime() + 6*3600000;
            FakeDate.UTC = OrigDate.UTC;
            FakeDate.parse = OrigDate.parse;
            window.Date = FakeDate;

            const origResolved = Intl.DateTimeFormat.prototype.resolvedOptions;
            Intl.DateTimeFormat.prototype.resolvedOptions = function() {
                const opts = origResolved.call(this);
                return {...opts, timeZone: CONFIG.TIMEZONE, locale: CONFIG.LOCALE};
            };
Как именно это работает? Отрывок скрипта заменяет глобальный объект Date на свою фейковую версию. Когда сайт вызывает new Date() без аргументов (самый частый случай), скрипт создаёт реальную дату, но сдвигаем её на +6 часов. Также переопределяется Date.now(), чтобы он возвращал смещённое время.
Ещё, скрипт перехватывает метод resolvedOptions() у Intl.DateTimeFormat чтобы они всегда возвращали America/New_York и локаль en-US.

После этого идут подмены Canvas и WebGL:
JavaScript:
const origGetImageData = CanvasRenderingContext2D.prototype.getImageData;
            CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
                const data = origGetImageData.call(this, x, y, w, h);
                for (let i = 0; i < data.data.length; i += 4) {
                    data.data   ^= Math.random() * 12 | 0;
                    data.data[i+1] ^= Math.random() * 12 | 0;
                    data.data[i+2] ^= Math.random() * 12 | 0;
                }
                return data;
            };

            if (WebGLRenderingContext) {
                const origGetParam = WebGLRenderingContext.prototype.getParameter;
                WebGLRenderingContext.prototype.getParameter = function(p) {
                    if (p === 0x9245) return CONFIG.WEBGL.vendor;
                    if (p === 0x9246) return CONFIG.WEBGL.renderer;
                    return origGetParam.call(this, p);
                };
            }
Как это работает? Скрипт перехватывает вызов getImageData() и слегка «зашумляет» каждый пиксель изображения: меняет значения красного, зелёного и синего каналов на очень маленькую случайную величину. Глаз человека эту разницу не заметит, а вот отпечаток Canvas сильно ломается. Для WebGL скрипт перехватывает метод getParameter() и при запросе специальных констант возвращает поддельные значения в данном случае Intel и Intel(R) UHD Graphics 630.

В самом конце скрипт выводит сообщение в консоль и внедряется на страницу:
JavaScript:
JavaScriptconsole.log('%c[Fingerprint Spoofer] Injected into page context should work better!', 'color: #00ff88; font-weight: bold');
        })();
    ';

    if (document.documentElement) {
        document.documentElement.appendChild(script);
    } else {
        document.addEventListener('DOMContentLoaded', () => {
            document.documentElement.appendChild(script);
        });
    }
    script.remove();
})();
Это создаёт новый <script>-элемент, вставляет в него весь код с подменами и добавляет его на страницу как можно раньше. После внедрения элемент сразу удаляется, чтобы не оставлять следов в DOM.

Теперь нужно упаковать плагин. Делается это очень просто одной командой:
Code:
zip -r fingerprint-spoofer.xpi *
После этого полученный файл .xpi нужно положить в папку /extensions/fingerprint-spoofer.xpi.

Установка плагина 
Tor Browser по умолчанию не видит плагины, которые просто лежат в папке extensions. Даже если вручную править файлы extensions.json и extension-preferences.json, плагин может появиться в списке, но он всё равно не будет инжектиться на страницы так как нужных разрешений не будет. Чтобы это исправить, мне пришлось установить плагин вручную через интерфейс Tor Browser.

Для этого первым делом скачал Tor Browser локально и зашёл и в раздел Extensions (в настройках браузера нажал на шестерёнку), затем выбрал пункт Install Add-on From File:
Не удалось прогрузить медиа


Далее я указал путь к файлу Browser/TorBrowser/Data/Browser/profile.default/extensions/fingerprint-spoofer.xpi:
Не удалось прогрузить медиа

Именно в эту папку внутри профиля Tor Browser, потому что браузер не видит плагины, лежащие за пределами файлов Tor Browser.

После этого появилось стандартное предупреждение Add Fingerprint Spoofer:
Не удалось прогрузить медиа

Я нажал OK. Такое окно появляется в Tor Browser (и вообще в Firefox) при установке любого расширения из файла как защита от нежелательных плагинов.

Затем я открыл настройки плагина и разрешил ему все необходимые права:
Не удалось прогрузить медиа


После установки я проверил результат на сайте browserleaks.com/javascript:
Не удалось прогрузить медиа

Как видишь, всё работает и мой отпечаток теперь выглядит как обычный Windows с Chrome.

Однако вручную устанавливать плагин каждый раз после пересборки системы это не вариант. Поэтому я придумал другой способ: я просто скопирую весь профиль profile.default из своего уже настроенного Tor Browser, добавлю туда свои prefs.js (об этом расскажу позже) и заменю дефолтный профиль в своей live-системе.


Добавление и настройка браузеров
Кстати, про браузеры в live-системе. Я решил сделать два отдельных браузера: один специально для Tor, а второй для i2p.
Сделал я это по двум причинам:

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

Что ж, приступим к настройке. Для этого я скопировал папку Tor Browser и назвал новую копию i2p-tor-browser. Это нужно для того, чтобы можно было удобно и независимо настраивать конфиги для Tor и для i2p.

Вот мои конфиги для браузеров. Кстати, в обоих prefs.js нужно дополнительно разрешить установку плагинов.
Для этого добавь следующие строки:

Code:
user_pref("xpinstall.whitelist.required", false);
user_pref("extensions.autoDisableScopes", 0);
user_pref("extensions.enabledScopes", 15);

Вот как выглядит первый конфиг prefs.js для основного Tor Browser:
Code:
user_pref("browser.cache.disk.enable", false);
user_pref("browser.cache.memory.enable", true);
user_pref("browser.cache.disk.capacity", 0);
user_pref("browser.sessionstore.enabled", false);
user_pref("browser.sessionstore.resume_from_crash", false);
user_pref("places.history.enabled", false);
user_pref("privacy.history.custom", true);
user_pref("privacy.clearOnShutdown.history", true);
user_pref("privacy.clearOnShutdown.cookies", true);
user_pref("privacy.clearOnShutdown.cache", true);
user_pref("privacy.clearOnShutdown.sessions", true);
user_pref("privacy.clearOnShutdown.siteSettings", true);
user_pref("extensions.torbutton.local_tor_check", false);
user_pref("extensions.torbutton.security_slider", 1);
user_pref("extensions.torbutton.settings_method", "custom");
user_pref("extensions.torbutton.startup", false);
user_pref("extensions.torbutton.use_privoxy", false);
user_pref("extensions.torlauncher.control_port", 9152);
user_pref("extensions.torlauncher.prompt_at_startup", false);
user_pref("extensions.torlauncher.start_tor", false);
user_pref("torbrowser.settings.bridges.enabled", true);
user_pref("torbrowser.settings.bridges.source", 2);
user_pref("xpinstall.signatures.required", false);
user_pref("pdfjs.enabledCache.state", false);
user_pref("network.proxy.socks_port", 9050);

Этот конфиг в первую очередь отключает встроенное меню загрузки мостов Tor Browser, потому что у меня будет свой kill-switch который управляет Tor. Потому здесь я полностью отключаю автоматическую проверку соединения с Tor, а так же запрещаю запуск Tor Launcher при старте браузера и указываю, что мосты будут настраиваться вручную. По мимо этого в конфиге я отключаю запись истории, сессий и кэша на диск.

Проверяем дейсвительно ли все идет через tor:
Не удалось прогрузить медиа


Второй prefs.js для i2p-tor-browser:
Code:
user_pref("browser.cache.disk.enable", false);
user_pref("browser.cache.memory.enable", true);
user_pref("browser.cache.disk.capacity", 0);
user_pref("browser.sessionstore.enabled", false);
user_pref("browser.sessionstore.resume_from_crash", false);
user_pref("places.history.enabled", false);
user_pref("privacy.history.custom", true);
user_pref("privacy.sanitize.sanitizeOnShutdown", true);
user_pref("privacy.clearOnShutdown.history", true);
user_pref("privacy.clearOnShutdown.cookies", true);
user_pref("privacy.clearOnShutdown.cache", true);
user_pref("privacy.clearOnShutdown.sessions", true);
user_pref("privacy.clearOnShutdown.siteSettings", true);
user_pref("browser.fixup.fallback-to-https", false);
user_pref("dom.security.https_first", false);
user_pref("dom.security.https_first_pbm", false);
user_pref("dom.security.https_first_schemeless", false);
user_pref("dom.security.https_only_mode", false);
user_pref("dom.security.https_only_mode_pbm", false);
user_pref("extensions.torbutton.local_tor_check", false);
user_pref("extensions.torbutton.security_slider", 1);
user_pref("extensions.torbutton.settings_method", "custom");
user_pref("extensions.torbutton.startup", false);
user_pref("extensions.torbutton.use_nontor_proxy", true);
user_pref("extensions.torbutton.use_privoxy", false);
user_pref("extensions.torlauncher.control_port", 9152);
user_pref("extensions.torlauncher.prompt_at_startup", false);
user_pref("extensions.torlauncher.start_tor", false);
user_pref("torbrowser.settings.bridges.enabled", true);
user_pref("torbrowser.settings.bridges.source", 2);
user_pref("pdfjs.enabledCache.state", false);
user_pref("xpinstall.signatures.required", false);
user_pref("network.proxy.http", "127.0.0.1");
user_pref("network.proxy.http_port", 4444);
user_pref("network.proxy.on_proxies_on", "localhost, 127.0.0.1, ::1, *local, *.i2p");
user_pref("media.peerconnection.ice.proxy_only", true);
user_pref("privacy.prioritizeonions.showNotification", false);

Мой конфиг устанавливает HTTP-прокси на порт 4444 (стандартный порт i2p), разрешает использование не-Tor прокси и добавляет исключения для всех .i2p доменов, чтобы они шли именно через i2p, а не через Tor. Ещё, он полностью отключает принудительный HTTPS , который мешает открывать i2p-сайты, отключает предупреждение о приоритизации onion-сервисов и запрещает WebRTC использовать прямые соединения (чтобы весь трафик шёл только через прокси).

Проверяем работу i2p-сайта в браузере:
Не удалось прогрузить медиа

Как видно всё работает

Когда плагин готов и конфиги настроены, база для Tor Browser фактически готова. Я скопировал два профиля в папку includes.chroot/ и назвал их:
Code:
i2p_profile.default.zip
tor_profile.default.zip

Также в корень системы я добавил иконку для i2p-браузера tor_i2p.png(это необязательно, но выглядит приятнее).
Не удалось прогрузить медиа



Дальше я создал хук 3100-tor-browser.hook.chroot. Он довольно большой, поэтому расскажу только про самые важные части.

Идет скачивание и установка Tor Browser в opt:
Bash:
cd /opt
TOR_VERSION="15.0.9"
TOR_ARCHIVE="tor-browser-linux-x86_64-${TOR_VERSION}.tar.xz"
TOR_URL="https://dist.torproject.org/torbrowser/${TOR_VERSION}/${TOR_ARCHIVE}"

wget --no-verbose -O "${TOR_ARCHIVE}" "${TOR_URL}"
tar -xJf "${TOR_ARCHIVE}"
rm -f "${TOR_ARCHIVE}"

cp -a tor-browser tor-browser-i2p

Здесь скрипт скачивает актуальную версию Tor Browser, распаковывает её и сразу создаёт вторую копию tor-browser-i2p для работы через i2p.

После этого идет установка готовых профилей:
Bash:
if [ -f /tor_profile.default.zip ]; then
    rm -rf /opt/tor-browser/Browser/TorBrowser/Data/Browser/profile.default/*
    unzip -o /tor_profile.default.zip -d /opt/tor-browser/Browser/TorBrowser/Data/Browser/
    chown -R ermine:ermine /opt/tor-browser/Browser/TorBrowser/Data/Browser/profile.default
fi

if [ -f /i2p_profile.default.zip ]; then
    rm -rf /opt/tor-browser-i2p/Browser/TorBrowser/Data/Browser/profile.default/*
    unzip -o /i2p_profile.default.zip -d /opt/tor-browser-i2p/Browser/TorBrowser/Data/Browser/
    chown -R ermine:ermine /opt/tor-browser-i2p/Browser/TorBrowser/Data/Browser/profile.default
fi
if [ -f /tor_i2p.png ]; then
    mkdir -p /usr/share/icons/hicolor/128x128/apps/
    cp /tor_i2p.png /usr/share/icons/hicolor/128x128/apps/tor-browser-i2p.png
    chmod 644 /usr/share/icons/hicolor/128x128/apps/tor-browser-i2p.png
else
    echo "tor_i2p.ico не найден в корне будет использована стандартная иконка" >&2
fi

Именно здесь происходит самое важное: скрипт заменяет стандартные пустые профили на наши заранее подготовленные (с плагином Fingerprint Spoofer и всеми нужными настройками). Также копируется иконка tor_i2p.png в системную папку иконок, чтобы i2p-браузер мог её использовать.

И последним идет создание ярлыкова на рабочем столье:
Bash:
mkdir -p /usr/share/applications

cat > /usr/share/applications/tor-browser.desktop << 'EOF'
[Desktop Entry]
Name=Tor Browser
Exec=/opt/tor-browser/Browser/start-tor-browser --detach
Icon=/opt/tor-browser/Browser/browser/chrome/icons/default/default128.png
Type=Application
Categories=Network;WebBrowser;Privacy;Security;Tor;
EOF

cat > /usr/share/applications/tor-browser-i2p.desktop << 'EOF'
[Desktop Entry]
Name=Tor i2pd Browser
Exec=/opt/tor-browser-i2p/Browser/start-tor-browser --detach
Icon=tor-browser-i2p
Type=Application
Categories=Network;WebBrowser;Privacy;Security;Tor;i2p;
EOF
Для обычного Tor Browser используется стандартная иконка, а для i2p-версии наша кастомная tor_i2p.png. При создании ярлыков у меня сначала была проблема: браузер запускался из неправильной папки (я указывал текущую директорию вместо /opt). В итоге я быстро решил это, прописав полный путь к start-tor-browser в файлах .desktop.

А в самом к конце хука просто выставляются правильные права доступа на папки, файлы и ярлыки, чтобы пользователь ermine мог нормально работать с обоими браузерами.

Проверяем в live системе появились и браузеры на рабочем столе:
Не удалось прогрузить медиа

Как видно всё работает.


Когда оба Tor Browser успешно установлены, осталось только обезопасить их с помощью AppArmor. Я создал две политики: torbrowser и i2p_torbrowser в папке includes.chroot/etc/apparmor.d/. Они почти одинаковые, отличаются только путём к браузеру.

Для примера приведу политику для обычного Tor Browser:
C-like:
#include <tunables/global>
@{torbrowser_home}=/opt/tor-browser
@{tor_exec}=@{torbrowser_home}/Browser/firefox.real

profile torbrowser @{tor_exec} flags=(attach_disconnected,mediate_deleted) {

#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/ssl_certs>
#include <abstractions/fonts>
#include <abstractions/X>

network tcp,
network udp,
deny network raw,
deny capability net_raw,

@{torbrowser_home}/** rix,
owner @{torbrowser_home}/Browser/** rwk,
owner /tmp/** rw,
owner /dev/shm/** rw,

deny /home/** rw,
deny /media/** rw,
deny /mnt/** rw,
deny /etc/machine-id r,
deny /proc/cpuinfo r,
deny /proc/meminfo r,
deny capability sys_ptrace,
}

На самом деле моя политика очень давольно ограничивает, что браузер может делать в системе. Она разрешает Tor Browser только самое необходимое: работать с интернетом, читать и запускать свои файлы из папки /opt/tor-browser, а также писать во временные папки /tmp и /dev/shm.
При этом браузеру полностью запрещено что-либо записывать в домашнюю папку пользователя, на флешки и другие съёмные диски, а также в папку /mnt.
Кроме того, ему нельзя читать важные системные файлы, такие как machine-id, информацию о процессоре и памяти. Ещё ему также запрещено использовать ptrace для отладки других процессов. По сути, даже если браузер будет взломан, он почти ничего не сможет сделать за пределами своей собственной папки и временных файлов.


Настройка Kill-switch
Вот мы и добрались до того самого, о чём я так много говорил... Kill-switch. Ох, kill-switch, kill-switch... 
Сколько же нервов и тестов ты мне стоил, кто бы знал.

Сначала я хотел сделать всё "как в Tails" с их сложной схемой на ferm, разными интерфейсами и цепочками. Думал: "Я же знаю, как это работает, почему бы просто не скопировать?". Но когда начал тестировать, быстро столкнулся с реальностью.

Оказалось, что не всё так просто. Одного только создания интерфейсов и прописывания правил было явно недостаточно. В конце концов я понял, что в Tails есть ещё какая-то дополнительная настройка с перенаправлением трафика и обработкой приложений, из-за которой у меня ничего не работало. Имею ввиду даже без загрузки при старте сети и ручном тесте сеть всё равно ломалась.

Тогда я решил упростить задачу: "Ладно, обойдусь без интерфейсов, просто поставлю очень строгие правила в ferm при запуске сети". Но и это не сработало. Ferm даже на одном интерфейсе, с прописанными туннелями, вёл себя странно: сеть блокировалась, DNS падал в общем, ничего нормально не функционировало.

В итоге мне пришлось полностью отказаться от идеи копировать подход Tails и честно признать: я зря потратил почти четыре дня на тесты. После этого я начал писать kill-switch полностью с нуля. Впрочем, в этом были и свои плюсы. Я получил ценный опыт, потому что настраивать kill-switch именно под Tor мне раньше не доводилось.
В любом случае, мой дорогой читатель, если ты энтузиаст и готов потратить больше времени на тесты, чем я, - я буду только рад. Лучшую версию kill-switch  в Tails я описал в соответствующем разделе.

Когда я начал разработку с чистого листа, сначала тестировал все iptables-правила на своей основной Debian-машине. Я делал так, чтобы при каждой ошибке не пересобирать live-систему по часу. Когда правила наконец идеально заработали на обычной системе, я перенёс их в live-образ... и всё сломалось. Сеть просто не поднималась, трафик не проходил, а kill-switch вообще перестал работать. Пришлось дальше подкручивать правила, проверять дейсвительно ли Tor запустился, разбираться, когда именно на этапе загрузки должен срабатывать kill-switch и многое другое.
Впрочем хватит лирики. Погнали разбираться, что и как нужно правильно настроить, чтобы у тебя не возникло таких же проблем с kill-switch как у меня!


Как бы парадоксально это ни звучало начнём с самого начала. Перед основной настройкой kill-switch в Ermine мне сначала нужно было установить необходимые пакеты для Tor и iptables.

Для этого я создал файл package-lists/my-tor.list.chroot со следующим содержимым:
Code:
tor
obfs4proxy
snowflake-client
zenity     
iptables 
iproute2

В этом файле tor это основной демон Tor, obfs4proxy и snowflake-client нужны для работы мостов, zenity используется для графических диалогов в скриптах, а iptables и iproute2 это инструменты для настройки firewall и управления сетью.


Дальше я написал конфигурационный файл Tor includes.chroot/etc/tor/torr спейцально под kill-switch:
Bash:
SocksPort 127.0.0.1:9050 IsolateDestAddr IsolateDestPort
ControlPort 127.0.0.1:9052
CookieAuthentication 1

DNSPort 5355
AutomapHostsOnResolve 1
AutomapHostsSuffixes .exit,.onion

TransPort 127.0.0.1:9040

AvoidDiskWrites 1
Log notice syslog
UseBridges 1

VirtualAddrNetworkIPv4 10.192.0.0/10
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy

Bridge obfs4 мост

Сначала я настроил TransPort и DNSPort. Кстати, с DNS у меня была интересная история. Изначально я использовал стандартный порт To (5353), но у меня никак не получалось, чтобы DNS-запросы шли через Tor. Я долго думал, смотрел, какие сервисы вообще слушают этот порт в основном с помощью команды ss -tuln. В итоге оказалось, что этот порт был занят  systemd-resolved. Я просто сменил порт на 5355, и проблема решилась. Также из интересного в конфиге присутствуют SocksPort и ControlPort. SocksPort это основной порт, через который браузер и другие программы будут подключаться к Tor. ControlPort нужен для управления демоном Tor из скриптов (например, чтобы проверять статус соединения или отправлять команды).
Ещё один важный параметр VirtualAddrNetworkIPv4. Он задаёт диапазон виртуальных IP-адресов, которые Tor будет использовать для .onion-сайтов.

По мимо этого я добавил в конфиг несколько встроенных мостов, но они довольно быстро устаревают. Поэтому при первой загрузке лучше всего использовать свои собственные мосты например, заранее подготовленные на другой флешке. Ещё можно также временно отключить kill-switch и вручную добавить мосты, хотя это и не очень безопасно. Других действительно удобных вариантов я пока не придумал.
К сожалению, если в стране сильная блокировка, то даже официальный сайт Tor Project может быть недоступен, и запросить мосты через него не получится. Именно поэтому у Tails и других подобных систем часто возникают проблемы, и они используют заранее подготовленные списки мостов.
Конечно, можно пробовать получать мосты по почте через IMAP, но это довольно долгий и неудобный способ. Возможно, в будущем я придумаю что-то более практичное. Буду рад предложениям в комментариях, если кто-то знает, как это можно сделать лучше.


Прежде чем настраивать автоматический запуск kill-switch при старте системы, нужно сначала сделать базу.

А именно создать два важных скрипта: для очистки правил и данных (на случай, если что-то пойдёт не так). 
И непосредственно сам скрипт, который будет настраивать правила kill-switch (ведь ferm у меня так и не заработал нормально)

Первый скрипт очень важный. Особенно он мне помог во время тестов, когда всё постоянно ломалось и нужно было быстро сбросить правила, чтобы начать настройку заново. Но и в готовой системе он тоже пригодится. Впрочем, об этом чуть позже.

Сначала разберёмся, что он делает. Скрипт лежит по пути config/includes.chroot/usr/local/bin/clean_all.sh.
Вот его код:
Bash:
#!/bin/bash

sudo systemctl stop tor@default i2pd 2>/dev/null || true
sudo pkill -9 tor obfs4proxy 2>/dev/null || true

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo ip6tables -P INPUT ACCEPT
sudo ip6tables -P FORWARD ACCEPT
sudo ip6tables -P OUTPUT ACCEPT
sudo iptables -F && sudo iptables -X && sudo iptables -Z
sudo iptables -t nat -F && sudo iptables -t nat -X && sudo iptables -t nat -Z
sudo iptables -t mangle -F && sudo iptables -t mangle -X
sudo ip6tables -F && sudo ip6tables -X && sudo ip6tables -Z

sudo iptables-save > ~/iptables-backup-$(date +%F-%H%M).rules 2>/dev/null || true

sudo rm -f /var/log/tor/*
sudo truncate -s 0 /var/log/syslog 2>/dev/null || true

Сначала он останавливает сервисы Tor и i2pd, а также убивает все процессы tor и obfs4proxy. Затем сбрасывает все политики iptables и ip6tables на ACCEPT (то есть разрешает весь трафик) и полностью очищает все таблицы правил: filter, nat и mangle. По сути, он возвращает firewall в полностью открытое состояние. Дополнительно скрипт сохраняет текущие правила iptables в бэкап-файл (на всякий случай), удаляет все логи Tor и очищает системный syslog.

Второй скрипт лежит в /includes.chroot/usr/local/bin/tor-killswitch.sh. Если говорить честно, он довольно большой, поэтому я разберу его по самым важным частям.

Первая часть самая простая:
Bash:
#!/bin/bash

MAX_WAIT=150
for i in $(seq 1 $MAX_WAIT); do
    if journalctl -u tor@default -n 50 --no-pager 2>/dev/null | grep -q "Bootstrapped 100% (done)"; then
        break
    fi

    if [ $((i % 30)) -eq 0 ]; then
        echo "   Ожидание... ($i/$MAX_WAIT секунд)"
    fi

    if [ $i -eq 80 ]; then
        sudo systemctl restart tor@default
        sleep 8
    fi

    sleep 3
done

Эта часть скрипта ждёт, пока Tor полностью запустится и подключится к сети. Она проверяет логи через journalctl, ищет строку "Bootstrapped 100% (done)" и делает это каждые 3 секунды. Если через 80 секунд Tor всё ещё не достиг 100 %, скрипт автоматически перезапускает сервис tor@default.
Вообще такая же проверка у меня уже есть сразу при поднятии сети, но лишний раз перестраховаться никогда не бывает. Лучше подождать чуть дольше, чем включить kill-switch раньше времени и заблокировать весь трафик.

Дальше идёт самое интересное основные правила iptables:
Bash:
iptables -F
iptables -t nat -F
ip6tables -F
ip6tables -t nat -F

iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT DROP

iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -p tcp --sport 9040 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 9040 -j ACCEPT
iptables -A OUTPUT -p udp --sport 5355 -j ACCEPT
iptables -A OUTPUT -p udp --dport 5355 -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner debian-tor -j ACCEPT
iptables -A OUTPUT -m owner --gid-owner debian-tor -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner i2pd -j ACCEPT
iptables -A OUTPUT -m owner --gid-owner i2pd -j ACCEPT

iptables -A OUTPUT -d 10.0.0.0/8 -j ACCEPT
iptables -A OUTPUT -d 172.16.0.0/12 -j ACCEPT
iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT

iptables -A OUTPUT -p icmp -j DROP

iptables -t nat -A OUTPUT -p tcp ! -d 127.0.0.0/8 -j REDIRECT --to-ports 9040
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5355
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5355

ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT DROP

ip6tables -A INPUT  -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT

ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT

Сначала я полностью очищаю все текущие правила в iptables и ip6tables. После этого устанавливаю политику по умолчанию для исходящего трафика на DROP. Это означает, что весь трафик, который не разрешён явно, будет автоматически блокироваться. Далее я разрешаю трафик через loopback-интерфейс, а также через порты Tor TransPort 9040 и DNSPort 5355. Эти порты необходимы, чтобы Tor мог принимать перенаправленный от других программ трафик.
Затем я разрешаю уже установленные соединения (ESTABLISHED, RELATED), чтобы ответы от сайтов могли нормально приходить обратно. Также полностью разрешаю весь трафик от пользователей debian-tor и i2pd - это основные пользователи, под которыми работают Tor и i2pd.
На самом деле это один из самых спорных моментов в kill-switch. Если бы эти пользователи были взломаны, теоретически они могли бы выйти в интернет напрямую. Однако для такого взлома злоумышленнику сначала нужно закрепиться в системе, а в live-окружении это крайне сложно в основном из-за нехватки времени. Так как обычно такая система используется максимум несколько часов, после чего флешка просто вытаскивается.
Дальше, я разрешаю трафик в локальные сети чтобы не было ошибок при работе в ней. А после запрещаю ICMP, чтобы уменьшить возможность утечки информации через ping. Дальше IPv6, для него я применил максимально жёсткий подход: полностью отключил весь входящий, исходящий и форвардный трафик, оставив только loopback и уже установленные соединения. Это сделано потому, что в большинстве случаев IPv6 нам не нужен,  но при этом он может стать дополнительным каналом утечки данных.


Когда основные скрипты были готовы, мы дошли до самого важного момента запуска kill-switch при старте сети.
Для этого я написал два отдельных скрипта: 20-tor-start.sh и 45-tor-killswitch.sh и поместил их в папку includes.chroot/etc/NetworkManager/dispatcher.d/. NetworkManager использует её для автоматического запуска скриптов при изменении состояния сети. Каждый раз, когда сетевой интерфейс поднимается или отключается, NetworkManager по очереди выполняет все скрипты из этой папки.

Обрати внимание на названия этих скриптов. Цифры в начале имени здесь играют очень важную роль. NetworkManager выполняет скрипты строго в алфавитном порядке. Поэтому скрипт, который начинается с 20-, запускается одним из первых сразу после того, как интерфейс поднялся. А скрипт с 45- запускается уже позже, когда сеть уже частично готова. На тестах я пробовал ставить 30 на tor-killswitch и какое-то время не мог понять, почему kill-switch не работает как надо. Оказалось, что Tor ещё не успевал полностью запуститься к моменту выполнения скрипта, и правила срабатывали слишком рано тем свмым мешая подключению.

Если уж речь зашла о подключении к Tor, то за это отвечает первый скрипт 20-tor-start.sh:
Bash:
#!/bin/bash
BASENAME=$(basename "$0")
TOR_USER="debian-tor"

if [ "$2" = "up" ]; then
    iptables -F OUTPUT
    iptables -t nat -F OUTPUT 2>/dev/null || true
    iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A OUTPUT -o lo -j ACCEPT
    iptables -A OUTPUT -m owner --uid-owner "$TOR_USER" -j ACCEPT
    iptables -P OUTPUT DROP

    systemctl restart [email protected]
elif [ "$2" = "down" ]; then
    iptables -P OUTPUT ACCEPT
    iptables -F OUTPUT
    exit 0
fi

На самом деле этот скрипт нужен не только для запуска Tor. Он выполняет ещё одну очень важную задачу: сразу после того, как сетевой интерфейс поднимается, он устанавливает жёсткие правила, которые блокируют весь исходящий трафик, кроме самого необходимого.
Кстати, эти предварительные правила я добавил не сразу. Сначала я их не ставил, и при одном из тестов, пока Tor ещё не успел запуститься, я заметил что мой реальный IP может утечь в интернет. После этого случая я понял, что без такой "предохранительной сетки" на старте никак нельзя. Потому что юзер может попробовать выйти в интернет или установить пакеты ещё до старта tor.

Теперь переходим к запуску kill-switch. Вот скрипт 45-tor-killswitch.sh:
Bash:
#!/bin/sh

if [ -z "$1" ] || [ "$1" = "lo" ]; then
   exit 0
fi

if [ "$2" = "up" ]; then

    MAX_WAIT=300
    for i in $(seq 1 $MAX_WAIT); do
        if journalctl -u tor@default -n 100 --no-pager 2>/dev/null | grep -q "Bootstrapped 100% (done)"; then
            systemctl restart i2pd.service 2>/dev/null || true
             sleep 5
        
            /usr/local/bin/tor-killswitch.sh
            exit 0
        fi

        if [ $((i % 30)) -eq 0 ]; then
            echo "[20-killswitch] Ждём Tor... ($i/$MAX_WAIT секунд)"
        fi

        sleep 3
    done
fi

exit 0

На самом деле этот скрипт сам по себе не содержит правил kill-switch. Он просто в цикле следит за логами Tor и ждёт, пока не появится сообщение "Bootstrapped 100% (done)". Как только Tor полностью загрузился, скрипт запускает основной файл /usr/local/bin/tor-killswitch.sh, который уже и применяет все жёсткие правила(и тоже кстати на всякий случай проверяет работает ли ещё tor).

Вот как выглядят скрипты на итоговой сборке:
Не удалось прогрузить медиа


После настройки запускаем сеть и смотрим какие скрипты запустились:
Не удалось прогрузить медиа



А помнишь, помнишь clean_all.sh, о котором я говорил в самом начале? Так вот, я не зря сказал, что он нам пригодится. На самом деле это одна из самых важных частей всего kill-switch.

Дело в том, что при загрузке live-системы iptables уже содержит какие-то стандартные правила по умолчанию. Если их не сбросить, то никакой запуск Tor, а следовательно и kill-switch, нормально работать не будут. Ты бы знал, сколько тестов и времени мне понадобилось, чтобы это понять...
Как я это понял? Обычно я тестировал kill-switch прямо на live-системе, но несколько раз просто включал и выключал сеть, а между запусками для очистки старых правил выполнял clean_all. И вот я заметил закономерность: при первом тесте ничего не работало, но стоило мне выполнить clean_all и запустить всё заново - "магическим образом" kill-switch начинал работать.

Я перебрал в голове все возможные варианты, почему так происходит. Сначала думал, что проблема в том, что сеть не успевает нормально подняться перед запуском скриптов или что-то в этом роде. Но в итоге я пришёл к простому выводу: не стоит мучиться этими вопросами, если есть надёжное решение - просто запускать clean_all при каждой загрузке системы.

Чтобы clean_all запускался автоматически, я создал обычный systemd-сервис. Он лежит по пути includes.chroot/etc/systemd/system/clean_all.service.

Вот его код:
Code:
[Unit]
Description=Run clean_all after network is ready
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/clean_all.sh
User=root
RemainAfterExit=yes
WorkingDirectory=/usr/local/bin

[Install]
WantedBy=multi-user.target
Этот сервис довольно стандартный. Он запускается один раз после того, как сеть полностью поднялась, выполняет скрипт clean_all.sh от имени root и завершает работу.

Проверяем статус clean_all:
Не удалось прогрузить медиа



И вот наконец, когда вся база kill-switch была выстрадана… кхм, готова, я сделал последний хук, который приводит всё в рабочее состояние.
Хук я назвал 5000-tor-enable.hook.chroot и разместил его по пути config/hooks/normal/5000-tor-enable.hook.chroot.

Вот его код:
Bash:
#!/bin/bash
set -e

systemctl enable tor.service
systemctl enable [email protected]
systemctl enable i2pd.service

chmod +x /usr/local/bin/clean_all.sh
chmod +x /usr/local/bin/tor-killswitch.sh
chmod +x /etc/NetworkManager/dispatcher.d/20-tor-start.sh
chmod +x /etc/NetworkManager/dispatcher.d/45-tor-killswitch.sh

systemctl daemon-reload
systemctl enable clean_all.service

Этот хук делает несколько важных вещей. Он включает автозапуск сервисов Tor и i2pd, делает все наши скрипты исполняемыми и в конце включает сервис clean_all.service.


Дальше я решил для тебя, дорогой читатель, наглядно провести тесты. Всё для того чтобы ты мог убедиться, что я тут не пустые байки рассказываю и kill-switch действительно работает.

Первым делом я проверил все правила iptables:
Не удалось прогрузить медиа

Здесь видно что почти весь входящий и исходящий трафик блокируется по умолчанию. В правилах разрешены только локальные соединения через интерфейс lo и ответы на уже установленные соединения. Политика по умолчанию для цепочек INPUT и OUTPUT это DROP. Это значит, что новые соединения извне на машину не принимаются.

После этого проверил ip6tables:
Не удалось прогрузить медиа

Как видно, всё установилось как надо. Политика для входящего трафика разрешительная . А вот исходящий трафик сильно ограничен. Здесь разрешены соединения только с определённых портов, в частности порт 9040, и только для определённых пользователей и групп. Также разрешены ответы на уже установленные соединения. Всё остальное исходящее соединение отбрасывается.

Дополнительно я проверил туннели:
Не удалось прогрузить медиа

Здесь видно, что у компьютера один основной маршрут в интернет. По умолчанию весь трафик идёт через шлюз 192.168.72.1 по интерфейсу wlp2s0.

Когда я убедился, что все правила настроены верно, я перешёл к проверкам на стороне сети. 
Сначала я проверил ping:

Не удалось прогрузить медиа


Затем проверил IPv6:
Не удалось прогрузить медиа

Для начала я подключился к сети и намеренно выключил сервис Tor, после чего попробовал получить свой IP-адрес с помощью curl с параметром -6(для IPv6), но ничего не вышло. Затем я включил Tor и повторил команду. На этот раз curl успешно выдал мне один из адресов Tor-сети.

Далее я попробовал воспользоваться браузером с отключенным Tor:
Не удалось прогрузить медиа

И вполне естественно я получил ошибку прокси, так как curl работал через Tor на порту 9050.

И наконец проверил, не выходит ли в клирнет DNS. Для этого я сначала отключил Tor, а потом включил его:
Не удалось прогрузить медиа

С отключённым Tor соединение на порту 53 не проходило, но стоило его включить всё сразу начало работать.


Смена MAC-адреса
Когда все страдания с kill-switch наконец закончились, дальнейшие настройки сети дались мне максимально просто и быстро
. Впрочем, осталась ещё одна последняя важная настройка - автоматическая смена MAC-адреса. Делал я это в первую очередь для того, чтобы по MAC-адресу нельзя было определить информацию о сетевой карте, а также связать эту сессию с предыдущими запусками live-системы на одной машине.

Для смены MAC я написал небольшой скрипт. Раньше я делал похожий скрипт для своей статьи про смену отпечатков в Linux на XSS, но ссылку давать не буду XSS сейчас уже не самая безопасная платформа, и я туда не захожу. Если кому-то интересно, могу скинуть скрипт в PDF в комментариях.

Вот сам скрипт, который будет лежать в системе по пути config/includes.chroot/usr/local/bin/mac_gen.sh:
Bash:
#!/bin/bash
MAC_FILE="/usr/local/share/mac_list.csv"
if [ ! -f "$MAC_FILE" ]; then
    exit 1
fi

OUI_LIST=$(awk -F',' 'NR>1 {gsub(/"/,"",$1); print $1}' "$MAC_FILE" | tr -d ' ')
INTERFACES=$(ip -o link show | awk -F': ' '{print $2}' | grep -E '^(wlan|wlp|wlx|en)' | grep -v '^lo$')

if [ -z "$INTERFACES" ]; then
    exit 1
fi

for iface in $INTERFACES; do
    if ! ip link show "$iface" > /dev/null 2>&1; then
        continue
    fi

    OUI=$(echo "$OUI_LIST" | shuf -n 1 | tr -d ':')
    RANDOM_PART=$(openssl rand -hex 3 | tr '[:lower:]' '[:upper:]' | sed 's/\(..\)/\1:/g' | sed 's/:$//')
    MAC="${OUI:0:2}:${OUI:2:2}:${OUI:4:2}:${RANDOM_PART}"

    sudo ip link set dev "$iface" down
    sudo ip link set dev "$iface" address "$MAC"
    sudo ip link set dev "$iface" up

done

Скрипт сначала ищет все сетевые интерфейсы, имена которых начинаются с типичных префиксов wlan, wlp, и тл. Все найденные интерфейсы он сохраняет в переменную INTERFACES. Затем для каждого интерфейса по очереди генерируется новый MAC-адрес. Для этого скрипт берёт данные из файла с готовыми OUI-префиксами(это первые три байта MAC-адреса), случайно выбирает один из них, и генерирует случайные последние три байта с помощью openssl после чего собирает из них уже полноценный новый MAC-адрес. Дальше с помощью утилиты ip он применяет этот новый адрес к текущему интерфейсу.

А вот файл, на основе которого генерируются MAC-адреса config/includes.chroot/usr/local/share/mac_list.csv.
Пример строки от туда:
Code:
Mac Prefix,Vendor Name,Private,Block Type,Last Update
00:00:0C,"Cisco Systems, Inc",false,MA-L,2015/11/17

Этот файл содержит большую таблицу официально зарегистрированных OUI-префиксов (первых трёх байт MAC-адреса) и названий производителей сетевого оборудования.


После того, как скрипт готов, возникает закономерный вопрос: а как сделать так, чтобы он запускался автоматически при каждой загрузке системы? Ведь обычному пользователю было бы неудобно каждый раз запускать его вручную. На помощь приходит systemd, а именно его сервисы. Я сервис для автозапуска mac_gen.sh и разместил его по пути includes.chroot/etc/systemd/system/mac-spoof.service.

Вот содержимое сервиса:
Bash:
[Unit]
Description=Random MAC Address Spoofer on boot
After=network-pre.target
Before=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/mac_gen.sh
RemainAfterExit=yes
User=root

[Install]
WantedBy=multi-user.target

Этот сервис запускается один раз при загрузке системы, выполняет наш скрипт mac_gen.sh от имени root и сообщает systemd, что задача успешно завершена. Он стартует достаточно рано после network-pre.target, но перед network.target, чтобы MAC-адреса успели поменяться до того, как сеть полностью поднимется.

Однако одного создания файла сервиса недостаточно для автозапуска. Нужно ещё "включить" его.
Для этого я написал ещё один хук hooks/narmal/5000-mac-enable.hook.chroot:
Bash:
#!/bin/bash

systemctl enable mac-spoof.service

chmod +x /usr/local/bin/mac_gen.sh

Этот хук просто включает автозапуск сервиса и делает скрипт генерации MAC-адреса исполняемым.

После сборки и запуска системы сервис успешно работает. Вот как он выглядит его статус:
Не удалось прогрузить медиа


А вот как в итоге выглядят изменённые MAC-адреса:
Не удалось прогрузить медиа



Смена hostname
Ну и последнее, что связано с сетью это смена hostname.

По умолчанию Debian ставит имя хоста debian. Я решил заменить его на своё ermine. Конечно, ты можешь оставить debian или поставить любое другое имя.
Сделал я это довольно просто.

Во время сборки я добавил файл config/includes.chroot/etc/hostname со следующим содержимым:
Code:
ermine

После этого создал файл config/includes.chroot/etc/hosts:
Bash:
127.0.0.1       localhost
127.0.1.1       ermine localhost.localdomain localhost
127.0.1.1       ermine

::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters

Эти два файла вместе задают имя хоста системы. Первый просто содержит короткое имя, а второй связывает это имя с локальными IP-адресами, чтобы система правильно понимала своё собственное имя и не выдавала лишних предупреждений.


Удаление лишних пакетов
Дальше, для большего минимализма системы, я решил удалить ненужные пакеты. 
Но сделал я это довольно хитро. Возможно, ты уже знаешь, но Debian иногда может незаметно для тебя тянуть какие-то пакеты, которые напрямую ты не запрашивал. Из-за зависимостей их потом нормально удалить не получается.
Чтобы избежать таких ситуаций, я поступил интересно: сначала я просто явно "выпилил" всё лишнее.

Для этого я создал файл в config/archives/no-unwanted.pref.chroot. Этот файл состоит из блоков по три строки.

Каждый блок выглядит примерно так:
Code:
Package: xfce4
Pin: version *
Pin-Priority: 1001

Package: xfce4-pulseaudio-plugin
Pin: version *
Pin-Priority: -1

Строка Pin-Priority: 1001 означает, что пакет очень важный и должен обязательно устанавливаться. А Pin-Priority: -1 говорит системе, что этот пакет устанавливать нельзя. Для xfce4 я поставил высокий приоритет, а для всех остальных ненужных пакетов -1. Среди них были: xfce4-pulseaudio-plugin, libpulse-mainloop-glib0, alsa-utils, alsa-oss, gnome-accessibility-themes, gnome-icon-theme, gnome-keyring*, gnome-themes-extra*, pinentry-gnome3, policykit-1-gnome, seahorse, xfburn, xfce4-goodies, firmware-atheros и firmware-ath9k-htc.
Это было нужно, чтобы полностью избавиться от GNOME-компонентов, которые тянутся вместе с XFCE, а также для удаления всего звукового стека (PulseAudio и связанного с ним ПО) и ненужных прошивок для беспроводных адаптеров.

Но и это ещё не всё. Чтобы окончательно очистить систему, я добавил хук config/hooks/normal/9000-remove-unneeded-packages.hook.chroot:
Bash:
#!/bin/bash
set -e

apt-get purge -y --autoremove \
    gnome-keyring \
    pinentry-gnome3 \
    network-manager-gnome \
    policykit-1-gnome \
    gnome-themes-extra \
    gnome-themes-extra-data \
    gnome-icon-theme \
    gnome-accessibility-themes \
    libpam-gnome-keyring \
    seahorse \
    gnome-online-accounts \
    goa-daemon \
    dconf-gsettings-backend \
    dconf-service \
    gcr \
    libgcr-ui-3-1 \
    libsecret-1-0 \
    gnome-keyring-pkcs11 \
    libpam-gnome-keyring \
    evolution-data-server || true


apt-get purge -y --autoremove pulseaudio \
    pulseaudio-utils
 
apt-get purge -y --autoremove \
    bluez-firmware \
    pulseaudio \
    pulseaudio-utils || true

apt-get autoremove -y
apt-get autoclean -y
apt-get clean
Этот хук полно

Скрипт удаляет остатки графических компонентов GNOME (менеджер ключей, сеахорс, policykit-гномовские утилиты и тд.), если что-то всё-таки просочилось через archives. Также он удаляет PulseAudio и всю связанную с ним звуковую инфраструктуру.
А в конце выполняются команды autoremove, autoclean и clean. autoremove удаляет пакеты, которые были установлены как зависимости, но больше не нужны. autoclean очищает локальный кэш от старых версий скачанных пакетов. А clean полностью очищает кэш загруженных пакетов.

Проверяем наличие ненужных пакетов:
Не удалось прогрузить медиа

Как видно, тех пакетов что я удалил в системе нет. Правда, на скриншоте видно, что установлен xfce4-screenshooter. Но по умолчанию его в моей системе нет я установил его позже, чтобы сделать скриншоты для демонстрации.


Защита на уровне ядра
Теперь поговорим про ядро. С ним я поступил довольно интересно.

Изначально у меня была идея собрать систему на linux-hardened. 
Это спейцальное ядро заточенное под безопасность ядро с дополнительными патчами и усиленной защитой от эксплойтов. Я даже начал изучать конфиги и пробовать его собрать.

Но довольно быстро отказался от этой идеи. У linux-hardened есть несколько серьёзных минусов. Во-первых, оно заметно сложнее в настройке и поддержке(после трёх неудачных сборок я это прочувствовал на себе). Во-вторых, из-за дополнительных защитных механизмов иногда возникают проблемы с совместимостью с некоторым оборудованием и драйверами. В-третьих, оно немного медленнее обычного ядра и может вызывать глюки в live-окружении. В-четвёртых, могли возникнуть сложности со сборкой и интеграцией в мою систему.

В итоге я пришёл к выводу, что сложность и риски того не стоят. Для нашей минималистичной live-системы гораздо разумнее и проще использовать обычное стабильное ядро Debian, но при этом тщательно его настроить под свои нужды с помощью файлов в папке /etc/sysctl.d/.

Если кто не знает, в sysctl.d можно размещать свои конфигурационные файлы с параметрами ядра. Система автоматически применяет все эти настройки при каждой загрузке.

Чтобы сделать такое "кастомное hardening" ядра, я создал хук config/hooks/normal/3100-kernel-hardening.hook.chroot.
Вот его код:
Bash:
#!/bin/bash
set -e

cat > /etc/apt/sources.list.d/backports.list << EOF
deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
EOF

apt-get update
apt-get install -y -t bookworm-backports linux-image-amd64 linux-headers-amd64
apt-get install -y hardening-runtime

cat > /etc/sysctl.d/99-max-hardening.conf << EOF
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.printk = 3 4 1 7
kernel.unprivileged_bpf_disabled = 2
kernel.yama.ptrace_scope = 2
kernel.randomize_va_space = 2

vm.init_on_alloc = 1
vm.init_on_free = 1
vm.mmap_rnd_bits = 32
vm.mmap_rnd_compat_bits = 16

fs.suid_dumpable = 0
kernel.core_pattern = |/bin/false

kernel.perf_event_paranoid = 3
kernel.kexec_load_disabled = 1
dev.tty.ldisc_autoload = 0
kernel.sysrq = 0

net.core.bpf_jit_harden = 2
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

kernel.modules_disabled = 0
EOF

sysctl -p /etc/sysctl.d/99-max-hardening.conf 2>/dev/null || true

echo "* hard core 0" >> /etc/security/limits.conf
echo "* soft core 0" >> /etc/security/limits.conf

Сначала я подключил репозиторий bookworm-backports и установил самое свежее стабильное ядро. Затем поставил пакет hardening-runtime, который добавляет дополнительные runtime-защиты.

В файле 99-max-hardening.conf я собрал как мне кажеться самые важные параметры безопасности для live системы.
Например, параметры kernel.kptr_restrict и kernel.dmesg_restrict запрещают обычным пользователям и программам читать адреса ядра и сообщения из dmesg.
Я также включил полный ASLR (kernel.randomize_va_space = 2). Благодаря этому адресное пространство каждого процесса каждый раз размещается в памяти случайным образом. Из за этой настройки злоумышленнику становится намного сложнее угадать, где находятся нужные ему данные.
Ещё я добавил параметры vm.init_on_alloc = 1 и vm.init_on_free = 1. Они заставляют ядро сразу очищать память при её выделении и освобождении. Даже в Tails есть похожий механизм. Это нужно для того, чтобы при резком извлечении флешки с нашей live в памяти почти ничего не осталось от предыдущей сессии.
Так же я запретил создание дампов памяти процессов. Так что если программа упадёт, система не будет сохранять файл с содержимым её памяти. Всё потому что в таком дампе могут оказаться пароли, ключи или другие важные данные. И если вдруг злоумышленник получит доступ к компьютеру, то так ему будет гораздо сложнее вытащить полезную информацию.
Кроме того, я отключил несколько опасных функций. Вроде Magic SysRq. Это пейальная  комбинация клавиш, которая позволяет выполнять команды даже при зависшей системе. Или запретил загрузку другого ядра без нормальной перезагрузки.
Я также усилил защиту сети. К примеру включил rp_filter. Это такая обратная проверка маршрута,  для защиты от IP-спуфинга. Или откоючил accept_redirects для IPv4 и IPv6 тоже для защиты от фальшивых перенаправлений маршрута.

В конце моего хука я добавил строки в файл /etc/security/limits.conf, которые полностью запрещают создание core-файлов для всех пользователей.
Это важно по двум причинам. Во-первых, core-файл может содержать чувствительную информацию. Во-вторых, если злоумышленник получит доступ к компьютеру, он не сможет использовать эти дампы, чтобы вытащить полезные данные. По сути, это похоже на randomize_va_space = 2, но вместе с ним заметно усиливает защиту.

Проверяем установились ли правила ядра:
Не удалось прогрузить медиа



Защита RAM
Если ты думал, что на этом всё закончилось, то ошибся. Я не забыл и про защиту от cold boot атак. 
Дело в том, даже после выключения питания какая-то информация иногда сохраняется в модулях памяти на несколько секунд или даже минут. Чтобы этого точно не происходило, я сделал так, чтобы оперативная память надёжно и тщательно очищалась при каждом shutdown и reboot.

Для этого я создал хук config/hooks/normal/3150-memory-protection.hook.chroot:
Bash:
#!/bin/sh
set -e

apt-get install -y secure-delete || true

apt-get purge -y dracut || true

cat > /etc/sysctl.d/99-memory-hardening.conf << EOF
vm.init_on_alloc = 1
vm.init_on_free = 1
vm.page_poison = 1
vm.mmap_min_addr = 65536
kernel.randomize_va_space = 2

vm.swappiness = 10
vm.vfs_cache_pressure = 50
EOF

cat > /etc/systemd/system/ram-wipe.service << 'EOF'
[Unit]
Description=Wipe RAM on shutdown (cold boot protection)
DefaultDependencies=no
Before=shutdown.target umount.target final.target

[Service]
Type=oneshot
ExecStart=/usr/bin/sdmem -vll
RemainAfterExit=yes
TimeoutStartSec=0
Nice=19
IOSchedulingClass=idle

[Install]
WantedBy=shutdown.target reboot.target
EOF

cat > /etc/systemd/system/swap-wipe.service << 'EOF'
[Unit]
Description=Disable and wipe swap on shutdown
DefaultDependencies=no
Before=shutdown.target

[Service]
Type=oneshot
ExecStart=/sbin/swapoff -a
RemainAfterExit=yes
Nice=19

[Install]
WantedBy=shutdown.target
EOF

mkdir -p /etc/systemd/system/shutdown.target.wants \
         /etc/systemd/system/reboot.target.wants

ln -sf /etc/systemd/system/ram-wipe.service  /etc/systemd/system/shutdown.target.wants/ram-wipe.service
ln -sf /etc/systemd/system/ram-wipe.service  /etc/systemd/system/reboot.target.wants/ram-wipe.service
ln -sf /etc/systemd/system/swap-wipe.service /etc/systemd/system/shutdown.target.wants/swap-wipe.service

cat > /etc/systemd/system/disable-swap.service << 'EOF'
[Unit]
Description=Disable swap in live session
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/sbin/swapoff -a
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

ln -sf /etc/systemd/system/disable-swap.service /etc/systemd/system/multi-user.target.wants/disable-swap.service

Сначала я установил пакет secure-delete, который содержит утилиту sdmem. Эта утилита нужна, чтобы надёжно затирать оперативную память нулями и случайными данными при выключении компьютера.

Дальше я добавил дополнительные параметры безопасности памяти в файл /etc/sysctl.d/99-memory-hardening.conf. Например, параметры vm.init_on_alloc и vm.init_on_free заставляют ядро сразу очищать память при её выделении и освобождении. Хотя это уже есть в современном ядре, я включил их явно для дополнительной уверенности. Дополнительно параметр vm.page_poison = 1 "отравляет" освобождённые страницы памяти, делая любые остатки данных в них бесполезными для злоумышленника. А vm.swappiness = 10 сильно уменьшает использование swap, чтобы система реже записывала данные на диск. При том как vm.vfs_cache_pressure = 50 меняет приоритет кэширования в пользу освобождения памяти вместо кэша дисковых операций.

Затем я создал два systemd-сервиса. Первый я назвал ram-wipe.service. При выключении или перезагрузке он запускает команду sdmem -vll. Эта команда затирает память несколькими проходами и делает это особенно тщательно. Второй сервис называется swap-wipe.service. Он отключает и очищает swap-раздел перед выключением. Кроме того, я добавил сервис disable-swap.service, который сразу после загрузки системы полностью отключает swap. В live-окружении нам swap не нужен, поэтому лучше его отключить заранее, чтобы система вообще не использовала диск для временных данных.
Но зачем тогда все остальные параметры, можешь спросить ты? Отвечу: на всякий случай. Если вдруг отключение swap по какой-то причине сработает не полностью, дополнительные настройки ядра всё равно обеспечат защиту памяти.

Проверяем работают ли сервисы и есть ли нужные правила в системе:
Не удалось прогрузить медиа



Добавление фона
И под конец сборки идёт моё любимое украшательство
. А именно я с помощью нейросети, фотошопа и ловких рук сделал прикольный фон для Ermine, а также красивое лого пользователя на экране входа. Решил рассказать, как я это добавил в систему. По безопасности тут уже ничего особо важного нет, но если ты собираешь свою live-ОС, у тебя наверника тоже может возникнуть желание поставить свой фон и свои иконки.

Поэтому разберу всё подробнее. Сначала я подготовил картинку для фона. Я назвал её ermine-wallpaper.jpg и добавил по пути includes.chroot/usr/share/backgrounds/my-ermine/.

Я выбрал именно этот путь, потому что в XFCE системные обои принято хранить в папке /usr/share/backgrounds/. Создав внутри свою отдельную папку my-ermine, я сделал всё аккуратно и не стал мешать стандартным обоям системы.

Дальше нужно было добавить этот фон в настройки XFCE. На самом деле способов сделать это существует несколько. 

Первый способ это через настройки xfconf. 
Это инструмент, с помощью которого можно менять параметры XFCE. Он работает, но довольно неудобен, потому что требует запускать множество команд, а настройки иногда применяются нестабильно.

Второй способ это прямое редактирование конфигурационных файлов. XFCE хранит настройки пользователя в папке ~/.config/xfce4/xfconf/xfce-perchannel-xml/. Можно было бы отредактировать файл xfce4-desktop.xml вручную, но этот метод тоже не очень надёжный при сборке системы, потому что настройки должны применяться автоматически для нового пользователя ermine, а не только для root.

Потому я выбрал третий способ это создание своего XML-файла с описанием фона. Он тоже работает через механизм xfce-perchannel-xml, но отличается от второго. Дело в том, что если положить файл с именем xfce4-desktop.xml в домашнюю папку пользователя, то он будет применяться только к этому конкретному пользователю. А если создать такой же файл в системной папке /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/, то настройки будут действовать по умолчанию для всех пользователей системы, включая вновь создаваемого ermine.

Для реализации этого метода я создал хук config/hooks/normal/3050-wallpaper.hook.chroot.
Вот его код:
XML:
#!/bin/bash

mkdir -p /etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml
cp /etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml /root/.config/xfce4/xfconf/xfce-perchannel-xml/ 2>/dev/null || true

includes.chroot/etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xfce4-desktop" version="1.0">
  <property name="backdrop" type="empty">
    <property name="screen0" type="empty">
      <property name="monitor0" type="empty">
        <property name="image-path" type="string" value="/usr/share/backgrounds/my-ermine/ermine-wallpaper.jpg"/>
        <property name="last-image" type="string" value="/usr/share/backgrounds/my-ermine/ermine-wallpaper.jpg"/>
        <property name="last-single-image" type="string" value="/usr/share/backgrounds/my-ermine/ermine-wallpaper.jpg"/>
        <property name="image-style" type="int" value="5"/>   <!-- 5 = scaled -->
        <property name="image-show" type="bool" value="true"/>
      </property>
    </property>
  </property>
</channel>

Хук создаёт стандартную папку для настроек XFCE внутри /etc/skel/. Всё, что лежит в папке /etc/skel/, автоматически копируется в домашнюю папку нового пользователя при его создании. Поскольку пользователь ermine создаётся позже во время сборки, этот способ позволяет задать фон по умолчанию именно для него. Самое важное здесь это файл xfce4-desktop.xml. Давай разберём подробнее, что означают его параметры.
Сначала идут свойства, связанные с путём к обоям: image-path, last-image и last-single-image. Все три параметра нужны, чтобы XFCE правильно запомнил и применил выбранный фон. Например image-path указывает текущий фон, last-image сохраняет последний использованный фон, а last-single-image отвечает за одиночный режим отображения.
Дальше идёт параметр image-style со значением 5. Он отвечает за режим отображения обоев на рабочем столе. Значение 5 означает scaled. В таком режиме обои автоматически подстраиваются под текущее разрешение экрана, при этом сохраняя пропорции.
И последний, но не менее важный параметр это image-show со значением true. Он просто включает показ обоев. Если поставить false, то фон будет отключён.

Вот как выглядит фон:
Не удалось прогрузить медиа

С фоном вышла интересная история. Рисовать я умею, поэтому решил попросить помощи у нейросетей. Но была одна проблема: у меня не было платных API для специализированных ИИ вроде Flux, Midjourney, Leonardo и подобных. Пришлось использовать GPT и Grok с платной подпиской. Наверное, именно поэтому, сколько я ни старался и ни переписывал промпты, результат получался, мягко говоря, не очень.

После примерно тридцати попыток до меня дошло: зачем просить нейросеть генерировать всю картинку целиком, если можно собрать её по частям? В итоге я сначала попросил сгенерировать огонь снизу (то, что ты сейчас видишь внизу), а потом начал мучиться с головой горностая в центре.

В итоге получился более-менее приемлемый результат. Но когда я поставил его на фон своего основного ПК (где я тестировал, чтобы постоянно не перезагружать ermine), стало понятно, что фон выглядит слишком светлым, а у головы горностая есть несколько неприятных артефактов, что очень бросаються в глаза.

Поэтому пришлось дорабатывать фон в Photoshop. Сначала я скорректировал цвет заднего фона и огня, изначально у нейросети всё было в светло-голубых оттенках, а мне хотелось более тёмных тонов. После этого я занялся головой горностая: убрал заметные артефакты. Стало лучше, но, если честно, мне кажеться голова всё ещё не идеальна. Но дальше сильно дорабатывать мне уже не захотелось, так как фон целиком и так выглядел вполне неплохим.


Кастомизация приветственного экрана
Когда фон был готов, пришло время заняться следующей красивой частью - кастомизацией экрана входа в систему.

Для начала я сделал иконку пользователя. 
Это довольно просто: нужно обычное изображение, но строго размером 64×64 пикселя. Я подготовил картинку и изменил её размер на сайте https://www.imgonline.com.ua/resize-image.php.

Когда иконка была готова, осталось только добавить её в систему. Кроме иконки я также захотел сделать тёмную тему на экране входа, чтобы всё выглядело более стильно и цельно.

Всю эту красоту я делал через LightDM.
LightDM - 
это программа, которая отвечает за экран приветствия: она показывает окно ввода логина и пароля, переключение пользователей, выбор сессии и так далее. Именно LightDM появляется сразу после загрузки системы, ещё до того, как запускается рабочий стол XFCE.
Поскольку LightDM отвечает за весь визуальный облик экрана входа, через него удобно настраивать иконку пользователя, фон, тему оформления и другие элементы.

Иконку пользователя я назвал ermine.png и положил её по пути includes.chroot/usr/share/pixmaps/. Это стандартная системная папка в Linux, где хранятся иконки приложений и пользователей. Сюда LightDM и другие компоненты системы автоматически смотрят при поиске картинок.

После этого я приступил к правкам конфигурации LightDM.
Сначала отредактировал основной конфиг по пути includes.chroot/etc/lightdm/lightdm.conf:
Code:
[Seat:*]
autologin-user=ermine
autologin-user-timeout=0
Эти строки делают так, что система автоматически входит под пользователем ermine сразу после загрузки, без необходимости вводить логин. Параметр autologin-user-timeout=0 убирает задержку перед автологином.

Дальше я настроил внешний вид экрана входа в файле includes.chroot/etc/lightdm/lightdm-gtk-greeter.conf:
Code:
[greeter]
background=#131524

default-user-image=/usr/share/pixmaps/ermine.png

theme-name=Adwaita-dark
icon-theme-name=gnome
font-name=Sans 10

Здесь я задал тёмный цвет фона и тёмную тему оформления Adwaita-dark. Указал путь к своей иконке пользователя, которая будет отображаться рядом с полем ввода пароля. И указал обычный шрифт Sans.

Вот как выглядит панель логина:
Не удалось прогрузить медиа




Вывод
Не удалось прогрузить медиа

И вот мы с тобой подошли к концу долгого пути создания своего дистрибутива и в целом этой статьи. На самом деле она получилась намного объёмнее, чем я изначально планировал.


Мнение про "приватные live"
В этой статье я протестировал достаточно много live-систем, которые подходили под определение "live с орентированная на приватность". 
Особенно подробно я разобрался с Tails, что логично, ведь он самый популярный среди таких систем. Ну и вторая ОС по размеру обзора это Cyrethium. Но Cyrethium, если честно, просто плохая ОС, и я немного жалею, что потратил на неё столько времени. Впрочем, зато у тебя теперь будет хороший пример того, как точно делать не надо.

В любом случае, после всех этих обзоров разных "приватных live" я понял одну важную вещь: из-за почти полного отсутствия конкуренции в сфере таких live-дистрибутивов на сегодняшний день единственным хоть сколько-то приемлемым вариантом остаётся только Tails. Но даже они немного расслабились например, имеет предустановленными совсем небезопасные программы вроде LibreOffice. Впрочем подробнее мою критику ты можешь почитать в соответствующем разделе.


Мнение про создание дистрибутива
Поэтому я и решил, что создание своего собственного live-дистрибутива - хоть и не для каждого, но очень хорошая идея. 
Особенно если у тебя есть узкие или специфические задачи, под которые стандартные решения не подходят.

Если честно, когда я только начинал создавать свой дистрибутив, то думал, что управлюсь за пару дней. Ага, как же... В итоге всё растянулось на долгие недели с кучей головной боли, бесконечными правками, исправлением ошибок и багов. Но я абсолютно ни о чём не жалею.
Это был очень интересный и полезный опыт. Я узнал много нового, разобрался в интересных вещах, да ещё и сделал прикольный проект, который хоть и не идеален, но мне понравился.

Больше всего мне запомнилось, как я делал kill-switch через Tor. Особенно тяжело далась работа с правилами iptables. Возможно в статье всё выглядело просто, а на практике пришлось очень долго биться, чтобы всё заработало стабильно.

Ещё мне показалось интересной задачей всё что было связано с Tor Browser. Например настроить два отдельных браузера для Tor и i2p. Или писать свой собственный плагин для подмены отпечатка, а потом глубоко копаться в конфигах браузера.

Как ни странно, проще всего у меня получилось с ядром и защитой памяти. Там с первого/второго раза удалось сделать довольно безопасно и стабильно. Также относительно легко далась автоматическая смена MAC-адреса. Но это наверное потому, что я уже делал подобное раньше. Политики AppArmor тоже пошли довольно гладко, хотя с Cake Wallet пришлось несколько раз повозиться, так как из-за того, что он не мог прочитать шрифты, кошельк просто отказывался запускаться.

А вот с мелкими вещами, такими как смена hostname или установка фона, иногда возникали неожиданные проблемы. С тем же фоном я сначала пытался настроить его через ~/.config/xfce4/xfconf/, и он упорно не применялся.

Кто-то может сказать: "Вот ты сам говоришь, как было трудно и долго делать дистрибутив. Как ты можешь кому-то это советовать?"
Но тут я вынужден не согласиться. Если бы над проектом работал не я один, а хотя бы пара человек, всё вышло бы значительно быстрее. Да и я сделал не просто минималистичную среду со скриптами, собранными с GitHub, а самостоятельно настроил и написал довольно много уникальных вещей. Потому, как по мне, итоговый "профит" сильно превышает затраченные усилия. Но в любом случае делать дистрибутив самому или брать готовый - решать только тебе. В этой статье я лишь хотел показать разные варианты и подходы.


Что дальше?
На этом всё. Спасибо всем, кто дочитал этот довольно длинный гайд до конца. 
Думаю, я и дальше буду постепенно добавлять новые фичи в Ermine, потому что проект мне действительно очень понравился. Но скорее всего это будет происходить не очень быстро, так как у меня есть и множество других дел. В любом случае, если хочешь предложить идеи по Ermine или просто обсудить что-то пиши в комментарии или в лс. Я всегда открыт к новым мыслям и предложениям.

А ещё дам небольшой спойлер. Во время тестирования Tails я наткнулся на одну довольно необычную вещь, о которой, скорее всего, начну писать отдельную статью. Впрочем, это пока только наброски и идеи.

Маленькая сноска про исходники:
Я изначально хотел загрузить zip-архив с полным конфигом ermine и его iso, но на сайте можно загружать только txt-файлы и фотки в качестве прикреплённых медиа. Поэтому я просто загрузил самые важные скрипты: kill-switch и конфиги Tor Browser.  Остальное, в принципе, было видно в статье, и большая часть файлов полного размера, так что при желании сборку можно легко повторить.

Надеюсь, тебе было интересно и полезно! До новых встреч в следующих моих статьях =)
👍62 ❤️12 🤔14 😢11
гений
Ответhipeople

Рад всех приветствовать! Перед началом статьи задам один вопрос: ты используешь live-системы в духе Tails OS, Whonix Live или подобных? Если да, то наверняка сталкивался с проблемами. Вроде того что образ загружается…

По итогу у меня два вопроса

1. Чем это лучше чем Tails?
2. Почему нельзя было просто отредактировать Tails у нее же код открыт
👍5 🔥1
Ответcybergangster

По итогу у меня два вопроса 1. Чем это лучше чем Tails? 2. Почему нельзя было просто отредактировать Tails у нее же код открыт

В своем live нет кучи ненужного предустановленного софта, который нужно было бы выпиливать в тейлс. + меньше кода и неизвестно сколько бы заняла времени выпилка программы и доработка в исходниках Tails(код там давнольно большой, и разобраться и доработать это потребовало бы гораздо больше времени чем создание собственного минимального дистрибутива). К тому же можно сделать дистрибутив конкретно под свои нужды и точно быть уверенным в нем.
Как я писал в статье Tails пытается угодить сразу всем типам юзеров, от этого имеет множество программ, часть из которых вообще сильно уставшие и ненужные. И плодит поверхность атак
👍3
а у меня кроме этих двух еще один.

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

Встречный вопрос - а как быть с общением? Безопасным? или трухакерам оно и не нужно?)
👍1
Ответhipeople

Как я писал в статье Tails пытается угодить сразу всем типам юзеров, от этого имеет множество программ, часть из которых вообще сильно уставшие и ненужные. И плодит поверхность атак

поверхность атак с охлаждением RAM?

с присутствием посторонних за ПК?
👍2
Ответlisa99

а у меня кроме этих двух еще один. Получается логика такая - давайте сделаем свою приватную ОС без месенджеров. Они опасны по своей природе. Встречный вопрос - а как быть с общением? Безопасным? или трухакерам оно и не…

Я не говорил что общение не нужно. Просто моя ос нужна конкретно для крипто транзакций и серфинга интернета, и в ней вполне можно общается на различных форумах. В статье я добавил что если нужно защищённое общение, а не написать кому то на форуме, сделать транзакцию и выйти, то можно сделать другую реализацию ОС конкретно под такие цели. А конце, концов в этом и плюс своего live дострибутва, что можно собрать под конкретно необходимые цели, не добавляя ненужных программ и делая необходимый уровень защиты.
👍5 ❤️1 🔥1
Ответlisa99

поверхность атак с охлаждением RAM? с присутствием посторонних за ПК?

Это совсем другого класса атаки, в Tails как я и писал есть неплохая защита от охлаждения рам.
👍3
Ответhipeople

Как я писал в статье Tails пытается угодить сразу всем типам юзеров, от этого имеет множество программ, часть из которых вообще сильно уставшие и ненужные. И плодит поверхность атак

Отлично, что вы решили продемонстрировать как сделать свою live os. Но вопрос в том что Tails проверен многими исследователями, почему бы не взять условный killswitch или сетевые настройки оттуда зачем свое писать с 0 когда можно на основе tails сделать?) Пользоваться тем что код открыт и собрать свое по кусочкам.
👍2
Ответcybergangster

Отлично, что вы решили продемонстрировать как сделать свою live os. Но вопрос в том что Tails проверен многими исследователями, почему бы не взять условный killswitch или сетевые настройки оттуда зачем свое писать с 0…

Там не все так просто, я изначально хотел так сделать, но потратил около недели и отказался от этой идеи. Если просто взять чисто механизм настройки сети ferm, скрипты в NetworkManager, то Killswitch не будет работать. Как я понял нужно брать все связанные systemd сервисы, tails-create-netns и ряд других скриптов, которые тесно связаны с архитектурой тейлс и частично переписывать и переносить к себе. Конечно так механизм будет более хорошим, но это сложнее и дальше. Потому я решил сделать собственный механизм. Но думаю если сеть желание и время вполне можно и перенести из Tails.
Я считаю, что этот гайдлайн суммарно можно назвать даже безупречным. Автор объясняет все нюансы и детали, мелочи, начиная от сетевого стека, заканчивая изоляцией и софтом. Новичкам предоставлено наглядное сравнение с плюсами и минусами.. но я все же останусь поклонником Whonix или своей маленькой альпинки, поднятой для прогонки трафика через Tor-сеть.

Отличная статья! Будем ждать от вас новых материалов. Удачи в дальнейшем творчестве!
ОтветleakinN_nname

Я считаю, что этот гайдлайн суммарно можно назвать даже безупречным. Автор объясняет все нюансы и детали, мелочи, начиная от сетевого стека, заканчивая изоляцией и софтом. Новичкам предоставлено наглядное сравнение с…

Спасибо большое! Очень рад что статья оказалась вам полезна. По поводу Alpine с трафиком через Tor это тоже хороший выбор для приватности.
👍1

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.