Закрыть периметр правилами iptables и не остаться при этом за дверью вместе с атакующим.
Посмотреть, что слушает наружу
Даёт порт, состояние и процесс:
Найти, кто держит больше всего соединений
Нюанс: в шпаргалках этот однострочник идёт без
Закрыть вход по умолчанию
Нюанс: в подборках порядок обратный — сначала
Заодно
Ограничить SSH подсетью и числом сессий
Оба правила встали. Полезная деталь:
Отправить подсеть в никуда без файрвола
Нюанс: это не тихий дроп. Локальные попытки получают отлуп сразу —
И общее: всё это живёт до перезагрузки.
А вы вредоносные IP баните iptables напрямую или отдаёте это CrowdSec и fail2ban?
#Linux #Security #iptables #Networking #DevOps
Посмотреть, что слушает наружу
ss -tulpn
Даёт порт, состояние и процесс:
0.0.0.0:8099 users:(("python3",pid=3545,fd=3)). Первое, с чего начинается любой аудит — половина находок обычно в том, что сервис слушает 0.0.0.0 вместо 127.0.0.1.Найти, кто держит больше всего соединений
ss -Hntu | awk '{print $5}' |
sed 's/:[^:]*$//' | sort | uniq -c | sort -rn
Нюанс: в шпаргалках этот однострочник идёт без
-H и с cut -d: -f1. Оба места ломаются. Без -H в подсчёт попадает строка заголовка, и в топе появляется несуществующий адрес Local. А cut по первому двоеточию режет IPv6: адрес [2001:db8::2]:54321 превращается в [2001. Отсечение через sed берёт только порт с конца.Закрыть вход по умолчанию
iptables -A INPUT -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
Нюанс: в подборках порядок обратный — сначала
-F, потом -P INPUT DROP, а разрешающие правила ниже. Между этими двумя строками сессия уже мертва, и до правил вы не дойдёте. Политика ставится последней, всегда.Заодно
-m state там устаревший, актуален -m conntrack --ctstate.Ограничить SSH подсетью и числом сессий
iptables -A INPUT -p tcp --dport 22 \
! -s 10.0.0.0/24 -j DROP
iptables -A INPUT -p tcp --dport 22 \
-m connlimit --connlimit-above 3 -j REJECT
Оба правила встали. Полезная деталь:
iptables -S показывает, что модуль сам дописал --connlimit-mask 32 --connlimit-saddr — лимит считается по одному адресу, а не по подсети. Если нужен другой охват, маску задавайте явно.Отправить подсеть в никуда без файрвола
ip route add blackhole 192.168.10.0/24
Нюанс: это не тихий дроп. Локальные попытки получают отлуп сразу —
ping вернул connect: Invalid argument, curl завершился с кодом 7. Для исходящего трафика это плюс, ошибка приходит мгновенно вместо таймаута, но маскировки не ждите.И общее: всё это живёт до перезагрузки.
netfilter-persistent для правил, ip route — в конфигурацию сети, иначе следующий ребут откроет всё обратно.А вы вредоносные IP баните iptables напрямую или отдаёте это CrowdSec и fail2ban?
#Linux #Security #iptables #Networking #DevOps
👍6
Разобрать строку штатным <regex.h> и не получить молчаливое «нет совпадения».
Проверял на glibc, gcc 13.3, Ubuntu 24.04. Все фрагменты ниже собраны в одну программу и скомпилированы с
Скомпилировать шаблон
Понять, почему не скомпилировалось
Буфер обязан быть массивом. На незакрытой скобке
Сопоставить и достать группы
Не забыть освободить
Замерил: 100 тысяч компиляций в цикле без
Где POSIX молчит вместо ошибки
Самое неприятное не в том, чего API не умеет, а в том, как он об этом сообщает:
Просмотры и именованные группы падают на компиляции — это честно. А вот
А вы в C-утилитах держитесь
#Linux #C #POSIX #regex #DevOps
Проверял на glibc, gcc 13.3, Ubuntu 24.04. Все фрагменты ниже собраны в одну программу и скомпилированы с
-Wall -Wextra без единого предупреждения.Скомпилировать шаблон
regex_t re;
int rc = regcomp(&re, "^([a-z]+)=([0-9]+)$",
REG_EXTENDED);
REG_EXTENDED включает ERE: скобки и + работают без обратных слешей. Без флага получите BRE, где группа пишется как \(...\).Понять, почему не скомпилировалось
char err[256];
if (rc != 0) {
regerror(rc, &re, err, sizeof err);
fprintf(stderr, "regcomp: %s\n", err);
}
Буфер обязан быть массивом. На незакрытой скобке
[a-z получите Unmatched [, [^, [:, [., or [=. Нюанс: regfree вызывайте только после успешного regcomp, для неудачной компиляции освобождать нечего.Сопоставить и достать группы
regmatch_t m[3];
const char *s = "app=100";
if (regexec(&re, s, 3, m, 0) == 0)
printf("%.*s\n", (int)(m[1].rm_eo - m[1].rm_so),
s + m[1].rm_so);
m[0] — всё совпадение, m[1] и дальше — группы по порядку. На app=100 вышло app в первой группе и 100 во второй. Нюанс: смещения в байтах, не в символах. В строке ключ=42 вторая группа начинается с байта 9, хотя символов перед ней пять. И если компилировали с REG_NOSUB, массив m не заполняется вовсе.Не забыть освободить
regfree(&re);
Замерил: 100 тысяч компиляций в цикле без
regfree раздули процесс до 1.4 ГБ, с ним — 1.8 МБ. В демоне, который компилирует шаблон на каждый запрос, это вопрос часов.Где POSIX молчит вместо ошибки
Самое неприятное не в том, чего API не умеет, а в том, как он об этом сообщает:
\d+ на "abc 123" -> No match
<.*?> на "<a><b>" -> <a><b>
(?<=x)y -> Invalid preceding regular expression
Просмотры и именованные группы падают на компиляции — это честно. А вот
\d компилируется и тихо ничего не находит, вместо него нужен [0-9]. И .*? не ошибка, а просто жадный .*: вернул всю строку вместо <a>. Привычки из PCRE здесь ломают логику молча.А вы в C-утилитах держитесь
<regex.h> или сразу тянете PCRE2?#Linux #C #POSIX #regex #DevOps
🔥 Знаешь только ip a? 10 неочевидных команд ip для Linux
Большинство админов знают про ip ровно две команды —
1️⃣ Вся сеть одним экраном, в цвете:
Интерфейс, состояние и адреса — по строке на каждый.
2️⃣ Куда реально уйдёт пакет:
Покажет интерфейс, шлюз и source-адрес. Незаменимо, когда маршрутов много и непонятно, какой победил.
3️⃣ Маршруты, которых нет в
ВАЖНО:
4️⃣ Сменить шлюз без риска потерять сервер:
Атомарно: нет окна без маршрута, как между
5️⃣ Дропы и ошибки на интерфейсе:
Растут errors или dropped — копай в кабель, драйвер или буферы, а не в приложение.
6️⃣ Жив ли шлюз на L2:
7️⃣ Сеть в прямом эфире:
Каждое изменение с меткой времени: упал линк, DHCP или VPN переписали маршрут. Оставь в tmux и лови, кто ломает сеть по ночам.
8️⃣ Отрезать IP без фаервола:
Ответы на этот адрес уходят в никуда, TCP-сессия с ним не установится.
9️⃣ IP интерфейса в скрипте без awk-акробатики:
🔟 Процесс без сети за две команды:
В новом namespace только выключенный
Всё, что меняешь через ip, живёт до перезагрузки. Постоянные настройки — в netplan, NetworkManager или systemd-networkd.
А какую из десяти ты уже держишь в алиасах?
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Networking #iproute2 #CheatSheet #SysAdmin #DevOps
Большинство админов знают про ip ровно две команды —
ip a и ip r, а дальше ifconfig по старой памяти. Держи 10 команд, которые покажут то, чего не видно в ip a: скрытые маршруты VPN, дропы на интерфейсе и мёртвый шлюз. Проверил на iproute2 6.1.1️⃣ Вся сеть одним экраном, в цвете:
ip -br -c a
Интерфейс, состояние и адреса — по строке на каждый.
-br работает и с link.2️⃣ Куда реально уйдёт пакет:
ip route get 8.8.8.8
# какая запись в таблице сработала
ip route get fibmatch 8.8.8.8
Покажет интерфейс, шлюз и source-адрес. Незаменимо, когда маршрутов много и непонятно, какой победил.
3️⃣ Маршруты, которых нет в
ip route:
ip rule
ip route show table all
ВАЖНО:
ip route показывает только таблицу main. wg-quick с AllowedIPs = 0.0.0.0/0 уводит дефолт в таблицу 51820, а ip route делает вид, что всё как раньше.4️⃣ Сменить шлюз без риска потерять сервер:
sudo ip route replace default via <gw>
Атомарно: нет окна без маршрута, как между
del и add. Упадёт с ошибкой — старый маршрут останется на месте.5️⃣ Дропы и ошибки на интерфейсе:
ip -s link show <iface>
# двойной -s — ошибки с разбивкой: crc, frame, fifo
ip -s -s link show <iface>
Растут errors или dropped — копай в кабель, драйвер или буферы, а не в приложение.
6️⃣ Жив ли шлюз на L2:
ip neigh show dev <iface>
REACHABLE и STALE — норма. Шлюз висит в FAILED или INCOMPLETE — он не отвечает на ARP, и пинговать дальше бесполезно.7️⃣ Сеть в прямом эфире:
ip -ts monitor link route
Каждое изменение с меткой времени: упал линк, DHCP или VPN переписали маршрут. Оставь в tmux и лови, кто ломает сеть по ночам.
8️⃣ Отрезать IP без фаервола:
sudo ip route add blackhole 203.0.113.5/32
# проверить и убрать
ip route show type blackhole
sudo ip route del blackhole 203.0.113.5/32
Ответы на этот адрес уходят в никуда, TCP-сессия с ним не установится.
ip route get по нему вернёт Invalid argument — так ядро отвечает на blackhole, это не ошибка.9️⃣ IP интерфейса в скрипте без awk-акробатики:
ip -j -4 addr show dev <iface> \
| jq -r '.[0].addr_info[0].local'
-j отдаёт JSON: парсинг не сломается, когда поменяется формат вывода. Нужен пакет jq.🔟 Процесс без сети за две команды:
sudo ip netns add lab
sudo ip netns exec lab <command>
# убрать за собой
sudo ip netns del lab
В новом namespace только выключенный
lo. Удобно проверить, как приложение переживёт падение сети, не трогая хост.Всё, что меняешь через ip, живёт до перезагрузки. Постоянные настройки — в netplan, NetworkManager или systemd-networkd.
А какую из десяти ты уже держишь в алиасах?
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Networking #iproute2 #CheatSheet #SysAdmin #DevOps
👍19🔥2
💀 CPU под 100%, а в top пусто? Ловим невидимые процессы через eBPF
Сервер греется, в шапке top
Ловим каждый запуск
Один и тот же PPID и новые процессы каждые 50 мс — вот он, виновник.
Кто плодит больше всех
Почему не strace -f
Проверил:
ВАЖНО: bcc-версия
Вместо «CPU горит, а кто — непонятно» получаешь имя процесса, аргументы и PID родителя. Дальше дело техники: поправить крон или скрипт.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #bpftrace #Troubleshooting #SysAdmin #DevOps
Сервер греется, в шапке top
us под 90%, а в списке процессов — никого. Классика: кто-то плодит процессы, которые живут 10–50 мс, а top опрашивает /proc раз в 3 секунды и их просто не застаёт. Показываю, как поймать виновника, не роняя прод.Ловим каждый запуск
# 1. В Ubuntu утилита идёт в пакете bpftrace
sudo apt install bpftrace
# Каждый execve() в реальном времени:
# время, PID и PPID родителя.
sudo execsnoop.bt
TIME PID PPID ARGS
16:55:42.684175 1112 1097 /bin/true
16:55:42.685129 1113 1097 curl --version
16:55:42.691294 1114 1097 sleep 0.05
Один и тот же PPID и новые процессы каждые 50 мс — вот он, виновник.
Кто плодит больше всех
# 2. Считаем запуски по родителю за 10 секунд.
# Подсчёт идёт ПРЯМО в ядре, без потока событий.
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_execve
{ @[comm, curtask->real_parent->tgid] = count(); }
interval:s:10 { exit(); }'
# Вывод: @[bash, 1097]: 525
# bash с PID 1097 за 10 секунд породил 525 процессов.
# 3. Смотрим, кто это и откуда он взялся
pstree -sp \<PPID>
ps -o pid,etime,cmd -p \<PPID>
Почему не strace -f
Проверил:
dd с bs=1 под strace работает в ~47 раз медленнее. И в ~37 раз — даже если трассировать только accept(), которого dd вообще не вызывает: ptrace останавливает процесс на КАЖДОМ системном вызове. eBPF процесс не останавливает и считает события в ядре.ВАЖНО: bcc-версия
execsnoop-bpfcc компилирует программу на лету и без linux-headers-$(uname -r) падает с «Unable to find kernel headers». execsnoop.bt работает через BTF, заголовки ему не нужны. Есть ли BTF в ядре: ls /sys/kernel/btf/vmlinux.Вместо «CPU горит, а кто — непонятно» получаешь имя процесса, аргументы и PID родителя. Дальше дело техники: поправить крон или скрипт.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #bpftrace #Troubleshooting #SysAdmin #DevOps
👍6🔥5
📊 Диск тормозит, а iostat показывает норму? Ищем хвост задержек
Приложение подвисает на записи, в логах таймауты к БД, а
Что на самом деле показывает iostat
ВАЖНО:
Гистограмма вместо среднего
Проверил на тестовой нагрузке (столбики убрал, чтобы влезло в экран): iostat в тот же момент показывал
Чей I/O висит
Видишь
Среднее говорит «всё хорошо», гистограмма показывает хвост, а третья команда — чей он. Дальше — по месту: вынести бэкап, развести нагрузку или идти к провайдеру с цифрами.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #Storage #Troubleshooting #SysAdmin #DevOps
Приложение подвисает на записи, в логах таймауты к БД, а
iostat рисует w_await в пару миллисекунд. Подвох в том, что iostat показывает среднее: 990 запросов по 0.1 мс и 10 по 200 мс дают в среднем 2 мс. Показываю, как достать хвост, который тонет в среднем.Что на самом деле показывает iostat
# 1. -x — расширенные колонки, раз в секунду
iostat -x 1
# r_await и w_await — СРЕДНЕЕ за интервал:
# редкие зависшие запросы в нём растворяются
ВАЖНО:
%util под 100% на SSD, NVMe и RAID не значит, что диск упёрся: они обслуживают запросы параллельно. Это прямо написано в man iostat.Гистограмма вместо среднего
# 2. В Ubuntu утилита идёт в пакете bpftrace.
# Ctrl+C — и получаешь распределение задержек.
sudo biolatency.bt
@usecs:
[16, 32) 426043
[32, 64) 15436
[64, 128) 527
...
[1K, 2K) 24
[2K, 4K) 17
[4K, 8K) 13
Проверил на тестовой нагрузке (столбики убрал, чтобы влезло в экран): iostat в тот же момент показывал
w_await 0.02 мс, а в хвосте висели запросы по 4–8 мс — в сотни раз дольше среднего.Чей I/O висит
# 3. Каждый запрос дольше 10 мс — с процессом.
# Порог подстрой: для HDD 10 мс — норма.
# На tracepoint'ах: не сломается с новым ядром.
sudo bpftrace -e '
t:block:block_bio_queue {
@ts[args->sector] = nsecs;
@who[args->sector] = comm;
}
t:block:block_rq_complete /@ts[args->sector]/ {
$ms = (nsecs - @ts[args->sector]) / 1000000;
if ($ms >= 10) {
printf("%s %d ms\n", @who[args->sector], $ms);
}
delete(@ts[args->sector]);
delete(@who[args->sector]);
}
END { clear(@ts); clear(@who); }'
Видишь
kworker или jbd2 вместо своего процесса — это отложенная запись из page cache. Настоящего писателя покажет pidstat -d 1.Среднее говорит «всё хорошо», гистограмма показывает хвост, а третья команда — чей он. Дальше — по месту: вынести бэкап, развести нагрузку или идти к провайдеру с цифрами.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #Storage #Troubleshooting #SysAdmin #DevOps
👍8
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
GitOps-практики: развёртываем сервис через ArgoCD
Классический CI/CD запускает деплой. Но как сделать так, чтобы состояние Kubernetes после него соответствовало конфигурации в Git? На вебинаре разберём принципы GitOps и посмотрим, как ArgoCD помогает управлять изменениями в кластере.
7 октября в 20:00 МСК на открытом вебинаре OTUS развернём сервис в Kubernetes с помощью ArgoCD и покажет работу подхода на практике.
На практике рассмотрим:
— чем GitOps отличается от классического CI/CD и когда его применять;
— как устроен ArgoCD и какие есть варианты реализации GitOps;
— как развернуть сервис в Kubernetes через ArgoCD;
— что произойдёт при изменении конфигурации напрямую в кластере;
— какие подходы к работе с ArgoCD полезны в проектах.
После вебинара вы поймёте принципы GitOps, познакомитесь с возможностями ArgoCD и увидите полный процесс развёртывания сервиса. Полученные подходы сможете применить при работе со своими Kubernetes-кластерами.
Урок проходит в преддверии старта курса «DevOps. Экспертный уровень».
👉 Регистрируйтесь: https://otus.pw/wyNA/
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Классический CI/CD запускает деплой. Но как сделать так, чтобы состояние Kubernetes после него соответствовало конфигурации в Git? На вебинаре разберём принципы GitOps и посмотрим, как ArgoCD помогает управлять изменениями в кластере.
7 октября в 20:00 МСК на открытом вебинаре OTUS развернём сервис в Kubernetes с помощью ArgoCD и покажет работу подхода на практике.
На практике рассмотрим:
— чем GitOps отличается от классического CI/CD и когда его применять;
— как устроен ArgoCD и какие есть варианты реализации GitOps;
— как развернуть сервис в Kubernetes через ArgoCD;
— что произойдёт при изменении конфигурации напрямую в кластере;
— какие подходы к работе с ArgoCD полезны в проектах.
После вебинара вы поймёте принципы GitOps, познакомитесь с возможностями ArgoCD и увидите полный процесс развёртывания сервиса. Полученные подходы сможете применить при работе со своими Kubernetes-кластерами.
Урок проходит в преддверии старта курса «DevOps. Экспертный уровень».
👉 Регистрируйтесь: https://otus.pw/wyNA/
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
👎1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
💀 df показывает 100%, а du молчит? 5 шагов спасения прода
Сервисы падают с «No space left on device»,
Шаг 1. Что именно кончилось
При 100% в
Шаг 2. Ищем удалённые, но открытые файлы
Шаг 3. PID и номер дескриптора
Шаг 4. Обнуляем файл без рестарта
Проверил на тестовой ФС: 141 МБ вернулись мгновенно, процесс продолжил писать. Только для логов и мусора — усечёшь файл данных БД, потеряешь данные.
Подвох: если сервис пишет без
Шаг 5. Аварийный запас на ext4
После уборки верни
Чтобы не повторилось — logrotate с
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Troubleshooting #Storage #SysAdmin #DevOps
Сервисы падают с «No space left on device»,
df -h рисует 100%, а du -sh /* насчитывает куда меньше. Классика: кто-то удалил гигантский лог, а процесс держит его открытым — файла уже нет, а блоки заняты. Показываю, как вернуть место без рестарта сервиса.Шаг 1. Что именно кончилось
df -h /var
# Место есть, а пишет «No space left»? Кончились inode:
df -i /var
При 100% в
df сервисы от root ещё пишут в резерв ext4, а остальные уже падают.Шаг 2. Ищем удалённые, но открытые файлы
# +L1 — файлы без единой ссылки в ФС.
# Точка монтирования в конце = только эта ФС.
sudo lsof -nP +L1 \<mountpoint>
COMMAND PID FD SIZE/OFF NAME
python3 690 3w 73400887 /mnt/t/app.log (deleted)
Шаг 3. PID и номер дескриптора
3w в колонке FD — дескриптор 3, открыт на запись. Проверка:sudo ls -l /proc/\<PID>/fd/\<FD>
# ... -> /mnt/t/app.log (deleted)
Шаг 4. Обнуляем файл без рестарта
# ВАЖНО: sudo : > файл НЕ сработает —
# перенаправление делает твой шелл, а не sudo.
sudo truncate -s 0 /proc/\<PID>/fd/\<FD>
Проверил на тестовой ФС: 141 МБ вернулись мгновенно, процесс продолжил писать. Только для логов и мусора — усечёшь файл данных БД, потеряешь данные.
Подвох: если сервис пишет без
O_APPEND (например, запущен как app > file.log), он продолжит с прежнего смещения. Размер снова покажет 70 МБ, хотя на диске файл занимает 4 КБ: он станет разреженным, и мониторинг по размеру будет врать.Шаг 5. Аварийный запас на ext4
# Резерв под root, по умолчанию 5%
sudo tune2fs -l /dev/\<disk> | grep -i "reserved block"
# Временно отдать 4% — работает на лету
sudo tune2fs -m 1 /dev/\<disk>
После уборки верни
-m 5: резерв нужен, чтобы root мог чинить систему на полном диске. Только ext2/3/4, на XFS не сработает.lsof +L1 пуст, а расхождение осталось? Файлы могут прятаться под точкой монтирования: смонтируй корень через mount --bind в пустую папку и запусти du там.Чтобы не повторилось — logrotate с
postrotate, который просит сервис переоткрыть лог, вместо ручного rm.❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Troubleshooting #Storage #SysAdmin #DevOps
👍9
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9👀1
🚨 Сервер под подозрением? 8 шагов аудита прав и SUID-бэкдоров
Кажется, что кто-то получил лишние привилегии, а с чего начать проверку — непонятно. Держи чек-лист на первые минуты: ищем скрытые пути к root — SUID, capabilities, PAM и sudo. Команды с SELinux проверены по документации, остальное прогнано на Ubuntu 24.04.
🔴 Шаг 1. SELinux: снять маску dontaudit
ВАЖНО: без
🔑 Шаг 2. SUID и SGID
Сравни список с чистой системой. Свежая дата у файла в
🎭 Шаг 3. Capabilities: SUID, который find не видит
ВАЖНО:
🚪 Шаг 4. PAM: вход мимо пароля
👤 Шаги 5–6. Скрытый root и sudo-лазейки
🔐 Шаги 7–8. Чужие ключи и входы
Порядок: dontaudit и AVC → SUID и capabilities → PAM → root и sudo → ключи. Нашёл подозрительное — не «чисти», а снимай образ: подчищенный сервер невозможно расследовать. И держи эталонный список SUID и
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #SkillHunter@LinuxSkill
#Linux #Security #SELinux #Forensics #Hardening #SysAdmin
Кажется, что кто-то получил лишние привилегии, а с чего начать проверку — непонятно. Держи чек-лист на первые минуты: ищем скрытые пути к root — SUID, capabilities, PAM и sudo. Команды с SELinux проверены по документации, остальное прогнано на Ubuntu 24.04.
🔴 Шаг 1. SELinux: снять маску dontaudit
# Правила dontaudit глушат часть отказов —
# атака может не попасть в лог AVC.
# Временно снимаем глушилку:
sudo semodule -DB
sudo ausearch -m avc -ts today
# Вернуть как было:
sudo semodule -B
ВАЖНО: без
semodule -DB часть заблокированных попыток доступа в журнал AVC просто не пишется. -DB держи включённым только на время аудита.🔑 Шаг 2. SUID и SGID
# Бинарники с SUID/SGID, по дате изменения
sudo find / -xdev -type f -perm -4000 \
-printf '%TY-%Tm-%Td %p\n' 2>/dev/null | sort
Сравни список с чистой системой. Свежая дата у файла в
/tmp, /dev/shm или /var/tmp — почти наверняка бэкдор.🎭 Шаг 3. Capabilities: SUID, который find не видит
# Права root без бита SUID
getcap -r / 2>/dev/null
ВАЖНО:
cap_setuid даёт тот же root, что и SUID, но в поиске -perm -4000 НЕ появится. Проверил: файл с cap_setuid+ep дал обычному юзеру uid 0, а find -perm -4000 его не нашёл. Опасные: cap_setuid, cap_setgid, cap_dac_override, cap_sys_admin, cap_sys_ptrace.🚪 Шаг 4. PAM: вход мимо пароля
# Модули, дающие проход: pam_permit,
# pam_rootok не на месте, чужой pam_exec
grep -rnE "pam_permit|pam_exec|pam_rootok" \
/etc/pam.d/
sufficient pam_permit.so в common-auth — открытая дверь. pam_permit там штатно идёт только как required в хвосте стека.👤 Шаги 5–6. Скрытый root и sudo-лазейки
# Второй UID 0 — сразу к делу
awk -F: '$3==0 {print $1}' /etc/passwd
# NOPASSWD, добавленный в обход
sudo grep -rEn "NOPASSWD" /etc/sudoers /etc/sudoers.d/
🔐 Шаги 7–8. Чужие ключи и входы
# Ключи SSH у всех, кто есть
sudo cat /root/.ssh/authorized_keys \
/home/*/.ssh/authorized_keys 2>/dev/null
# Неудачные входы — брутфорс перед взломом
sudo lastb -Fai | head
Порядок: dontaudit и AVC → SUID и capabilities → PAM → root и sudo → ключи. Нашёл подозрительное — не «чисти», а снимай образ: подчищенный сервер невозможно расследовать. И держи эталонный список SUID и
getcap заранее — сравнивать будет с чем.❗️ Нравится формат? Ставь 👍
👉 Рубрика: #SkillHunter@LinuxSkill
#Linux #Security #SELinux #Forensics #Hardening #SysAdmin
👍3