Pull to refresh
128K+
10
Джек Бендеров@jbenderov

Пишу ИБ-продукты и рассказываю, как они устроены

254,2
Rating
16
Subscribers
Send message

Спасибо за комментарий! Здесь не говорится, что это самый популярный вектор, он скорее подан с посылом для тех, кто сейчас или когда-то в будущем будет строить процессы безопасной работы с кодом (чтобы учитывали, что такие кейсы бывают). Я вижу это как интеграцию в CI, когда при пролитии кода запускается статический анализатор, который помимо проблемных моментов (наличие уязвимостей, алерты линтеров и пр.) подсвечивает ещё подобные кейсы. Кмк проверка может оказаться весьма полезной

Спасибо, что проверили. Пустой каталог означает, что подключением управляет не keyfile-плагин NetworkManager, и пароль надо искать в другом месте.

Самый короткий способ узнать, где именно:

nmcli -f NAME,TYPE,FILENAME connection show

Команда печатает путь к файлу для каждого профиля. Если список пуст, NetworkManager этим подключением не занимается вовсе.

Дальше по частым вариантам:

— Ubuntu внутри WSL. Своего Wi-Fi-интерфейса в Linux тогда нет, сеть проброшена из Windows, и пароль лежит в профиле Windows. Проверяется по uname -r: в WSL в версии ядра есть слово microsoft.

— netplan, обычная история для серверной установки: файлы .yaml в /etc/netplan, пароль там открытым текстом или хешем.

— wpa_supplicant напрямую: конфиги в /etc/wpa_supplicant/.

— iwd вместо wpa_supplicant: файлы .psk в /var/lib/iwd/.

— подключение не сохранено, а поднято на время сессии: /run/NetworkManager/system-connections/.

Отдельно про сам grep: если файлы профилей в каталоге есть, а psk= в них не находится, значит пароль сохранён в связке ключей. В профиле тогда стоит psk-flags=1, а само значение хранит gnome-keyring. В статье этот случай оговорён, но по выводу grep он выглядит так же, как отсутствие пароля.

Пароль от WIFI - это легкозаменяемая и технически решаемая мелочь. Она приведена здесь не потому, что это главная угроза, а потому что это быстрый и дешёвый выигрыш в безопасности, которым многие пренебрегают: перейти на WPA2-Enterprise или привязать MAC-адреса — проще, чем менять графики работы сотрудников после каждого увольнения.

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

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

Минуса по сути нет, вариант рабочий — это как раз одна из тех развязок, о которых речь в статье («развести слушателей»). Вы вынесли разбор обоих стеков на nginx, а бэкенд общается с ним по чистому IPv4 через 127.0.0.1 и mapped-адрес не увидит вовсе. Хороший подход, мне нравится.

Проблема при этом никуда не девается, просто стягивается в одну точку — в сам nginx. Пока listen раздельные, как у вас (443 и конкретный [2001:…]), всё чисто. Но стоит где-то появиться listen [::]:443 без ipv6only=on — и в логах самого nginx $remote_addr поедет в форме ::ffff:…, теперь уже на уровне прокси.

И второе: реальный адрес клиента теперь приезжает в приложение не из сокета, а из X-Forwarded-For, который вы прокидываете. Если перед nginx окажется ещё один прокси на дуал-стек сокете, mapped-форма может прилететь и в этот заголовок — а его обычно разбирают руками. Так что приём отличный, просто точка, где держать нормализацию адреса, смещается с сокета приложения на границу прокси.

Отличный разбор, редко кто доводит цепочку рассуждений оптимизатора до конца так наглядно. Вдобавок к -fwrapv и санитайзерам хочу подкинуть ещё один удобный инструмент из этой же оперы — checked-арифметику, она хорошо ложится рядом.

В GCC и Clang есть __builtin_add_overflow(a, b, &res) и его собратья __builtin_sub_overflow и __builtin_mul_overflow. Каждый выполняет операцию, кладёт результат по указателю и возвращает флаг переполнения, а компилируется в аппаратную проверку соответствующего флага процессора — быстро и без UB. Приятно тем, что классическое if (a + b < a) для знаковых, которое оптимизатор и выкидывает, тут просто не нужно: неопределённого поведения в builtin нет, проверять нечего.

В C23 это же завезли в стандарт — заголовок <stdckdint.h> и ckd_add(&res, a, b), уже переносимо, без привязки к конкретному компилятору.

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

То, что вы описали, в ML называется concept drift, а «выключатель по трейлинг-Sharpe» — это детектор дрейфа по выходу. У него встроенный лаг: скользящий Sharpe на окне в тысячу баров реагирует, когда просадка уже случилась, — вы сами закрываете это гистерезисом против дёрганья. Размен фундаментальный: короткое окно ловит шум, длинное реагирует поздно, середины нет.

Рядом стоит поставить детекторы дрейфа не по результату, а по входу. Page-Hinkley, DDM, ADWIN следят за статистикой потока — распределением признаков и ошибкой предсказания — и сигналят о смене распределения раньше, чем она доедет до кривой капитала. Логика простая: режим меняется во входных данных, а P&L — уже следствие, с задержкой.

Оговорка, без которой это в трейдинге не работает: feature drift и P&L drift связаны не жёстко. Рынок может сменить распределение, а стратегия останется прибыльной, и наоборот. Так что входной детектор — это ранний сигнал «пора присмотреться и, может, ужать риск», а не готовая команда переключиться. Ваш выходной выключатель как финальный арбитр всё равно нужен, но входной даёт фору по времени, которой у чисто выходного нет.

К разделу про приоритизацию — CVSS отвечает на «насколько страшно, если проэксплуатируют», но не на «проэксплуатируют ли вообще». Для хранилища артефактов это важно: реальный риск сильно зависит от того, доступен сервис снаружи или живёт внутри периметра.

Рядом с CVSS стоит смотреть ещё две вещи.

EPSS от FIRST — оценка вероятности, что для уязвимости в ближайший месяц появится или уже есть работающий эксплойт. Она разводит критичные по CVSS, но «спящие» баги и те, по которым эксплойты уже летают. Нередко CVE с CVSS 9 и EPSS в пару процентов может подождать дольше, чем 8.6 с EPSS под полсотни.

CISA KEV — список того, что эксплуатируется в реальности прямо сейчас. Если CVE там, вопрос приоритета закрыт: патчить в первую очередь, независимо от баллов.

И третий фактор, которого в CVSS нет вообще, — экспозиция. Nexus, доступный только из внутренней сети, и Nexus, торчащий в интернет, — это разный риск при одной и той же уязвимости. Перед тем как гнать обновление по всему парку, установки стоит развести по этому признаку и начать с наружных.

Длина промпта тут вряд ли при чём — она влияет на время одного вызова модели, а это секунды, не часы. Многочасовые паузы у автономных агентов обычно от другого.

Самое частое — упор в rate limit того же API модели. Агент за прогон делает вызовов на порядок больше человека, выбирает квоту и дальше просто ждёт окна. Снаружи выглядит как «завис на полдня», хотя он всё это время стоит в очереди.

Второе — ожидание долгой внешней операции. Запустил скан, сборку или перебор, ждёт результата, прежде чем планировать следующий шаг — время идёт, видимой активности нет.

Третье — циклы перепланирования: перечитывает уже собранное, гоняет цепочки рассуждений, откатывается и пробует заново. Без внешнего таймбокса это тянется долго.

Так что сутки здесь — не обязательно след ручного вмешательства. У длинных агентных прогонов время нелинейное: большая часть уходит на ожидание, а не на сами действия.

Спасибо, что выложили список CT-логов открыто — теперь можно проверять, а не верить на слово.

Заметил вещь, которую в статье стоило бы проговорить. Логи, которым доверяет Яндекс Браузер, и логи из программы Chrome не пересекаются вообще: у Chrome это Google, Cloudflare, DigiCert, Sectigo, Let’s Encrypt и ещё пара операторов, у вас — Yandex, VK и Минцифры. Ни одного общего.

Для того, кто мониторит выпуск сертификатов на свои домены, это ловушка. Привычные crt.sh и Cert Spotter собирают данные с логов из экосистемы Chrome, а в ваш набор не заглядывают. То есть сертификат, выданный отечественным УЦ и попавший только в Agate или в лог Минцифры, ни в одном из этих мониторингов не всплывёт.

На практике это значит, что после перехода на отечественный УЦ следить за выпуском приходится уже по двум непересекающимся наборам логов вместо одного. Пропустишь второй — и фишинговый или ошибочно выданный на твой домен сертификат, залогированный только в российском CT, проедет мимо оповещений. Ровно то, ради чего Certificate Transparency и затевался, перестаёт работать в слепой зоне.

Отсюда вопрос: планируете ли публичный веб-поиск по вашим логам, как crt.sh? Через API проверять можно, но глазами по-быстрому посмотреть, что выпущено на домен, куда удобнее.

Я лично знаю один сервис для покупки билетов на рейсовые автобусы, который присылает пароль на почту при регистрации. Также ранее попадались такие кейсы в сервисах связанных с ЖКХ и сервисами по подключению к общедомовым камерам. Согласен, что крупные сервисы подобные практики не используют (что логично), но мелких частников с такими проблемами встретить вполне реально.

--

Исследование проведено у меня на ноутбуке)) Все полученные результаты взяты из реального вывода команд

Чего не хватает в выводах — взгляда со стороны тех, кто потом будет это ловить.

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

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

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

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

Короткоживущие токены с отзывом на стороне выдающего. «Возможность оперативно остановить работу» на практике означает не «убить процесс» — к этому моменту агент мог положить полученные данные куда угодно, — а отозвать выданное.

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

Про арифметику в разделе о сборе: «с каждых 1920 байт картинки получаем 64 байта энтропии» — это размер хеша, а не количество энтропии. SHA-512 энтропию не создаёт, он её только перемешивает: на выходе её не может быть больше, чем было на входе. Если в куске кадра было двадцать бит непредсказуемости, то и в 512-битном хеше будет двадцать бит, просто размазанных по всей длине. Отсюда и «один бит энтропии на каждые 30 бит картинки» — это соотношение объёмов, а не оценка источника.

Второй момент — про проверку. Тест сжатием и статистические паки, применённые после хеширования, про источник не говорят ничего. Проверяется это за пару минут: берём счётчик 0, 1, 2, … — энтропия ровно ноль — и прогоняем через SHA-512 с накоплением, как у вас. Поток не сжимается, распределение байтов ровное, статистические тесты проходят. Хеш маскирует любую предсказуемость входа, поэтому по его выходу аквариум от счётчика не отличить в принципе.

Как это принято делать: NIST SP 800-90B требует оценивать min-entropy на сыром выходе шумового источника, до всякого кондиционирования, и именно min-entropy, а не Шеннона — интересен наихудший случай, а не средний. Для камеры это значит считать по несжатым сэмплам и с поправкой на то, что соседние пиксели и соседние кадры сильно скоррелированы: статичный фон, автоэкспозиция и внутрикамерный шумодав съедают заметную часть того, что на глаз выглядит хаосом.

Про Fortuna всё написано верно, и вывод «навредить не может» тоже верен — слабый источник в пуле действительно не портит остальные. Вопрос только в том, сколько бит аквариум добавляет на самом деле, и ответ даёт оценка входа, а не тесты выхода.

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

Зависит от конкретной реализации на сервере. Но как вариант:

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

  • При выдаче токена он записывает туда текущую версию (v1).

  • При нажатии «выйти везде» он просто увеличивает счётчик до v2.

  • При каждом запросе сервер делает одну очень лёгкую операцию: читает из БД (или кэша) текущую версию для этого пользователя и сравнивает с версией, зашитой в токен.

Разница в том, что:

  • При обычной работе (когда кнопку не нажимают) нагрузка минимальна — сервер просто проверяет подпись, без обращения к БД.

  • При сбросе нагрузка вырастает, но это редкое событие (в этом случае, да, нагрузка как и в старых реализациях).

Кнопка «выйти везде» — это сброс доверия к конкретному токену.

Технически это выглядит так:

  • Сервер заводит чёрный список (или увеличивает счётчик версии токенов) для этого пользователя.

  • При каждом следующем запросе сервер теперь обязан проверить: а не в этом ли чёрном списке токен.

Опять же, все зависит от реализации конкретного сервиса, но из того с чем я сталкивался - там было так

Раньше сессии хранили на сервере — меняешь пароль, сервер их чистит. Сейчас сессии — это токены на устройствах, сервер их не хранит и про них не знает (он хранит секретный ключ, которым эти токены подписывает). Смена пароля даёт новый ключ, а старые токены продолжают работать, пока не протухнут. Так сделали, потому что иначе серверы не вывезли бы нагрузку. Поэтому сейчас нужна кнопка «выйти везде» — это ручной принудительный сброс.

1) Спасибо, поправил.
2) Главное - хранить ключ вне базы данных. Например: в системе управления секретами / KMS / клиентском хранилище. Плюс у него должен быть отдельный цикл бэкапирования и строгий аудит доступа (чтобы другие пайплайны случайно не получали к нему доступ).

Под «такой же» я имею в виду принципиально ту же информацию (домены), а не тот же инструмент.

Если вы включили точку доступа на телефоне — вы не видите доменов соседей. Чтобы их увидеть, вам нужно установить специальное ПО (на Android — без root, через VPN-API) или раздать интернет с ноутбука, где вы запустите Wireshark. Но технически трафик содержит эти домены в открытом виде — вопрос только в том, есть ли у вас инструмент, чтобы их оттуда достать. С точки зрения угрозы это значит: любой, кто физически или программно получит доступ к каналу, увидит этот список.

1

Information

Rating
9-th
Location
Беларусь
Registered
Activity

Specialization

Фулстек разработчик, Системный инженер
Ведущий
Git
SQL
PostgreSQL
CI/CD
Redis
Kubernetes
Linux
Python
Английский язык
MySQL