Pull to refresh

Comments 139

С одной стороны ничего принципиально нового, но с другой стороны — правда, все так и есть и мало кто об этом задумывается. Как правило в случае утечки рутовых доступов лучше сносить контейнер вообще нафиг, перед этим постаравшись забэкапить что возможно. У нас однажды году в 2012-м через один PHP-сайтик доставшийся в наследство от прошлых разработчиков ломали сервак сделав нечто подобное, залив код спионеривания пароля.
С тех пор пароли везде отключены, все движения и привелегии только по RSA-ключам и сайтики на PHP после кого-бы-то-нибыло ни за какие деньги не берем в обслуживание, особенно на каких-то сомнительных админках. Да и с 2013-го в работе только Ruby/Rails используем, через дефолтный деплой-паттерн по deploy-ключам, так что руками никто никуда не влезает вообще. На особо важных серверах доступ руту к ssh вообще заблокирован, только через отдельного пользователя по ключам.
А если быть честным — никогда нельзя быть ни от чего застрахованным и произойти может что угодно. На любую меру безопасности есть контр-мера, вопрос только в том чтобы найти оптимальный уровень удобный для работы но при этом относительно безопасный.
Господа минусующие, напоминаю что на хабре существуют комментарии. Было бы крайне интересно послушать в чем я не прав и возможно сделать какие-то выводы.
Рискну предположить, что это связано с высказанной вами слишком слабой или даже ложной корреляцией языка программирования и дырявости сайта. Плюс, возможно, связано с тем, что вы поставили крест на языке программирования, толком не разобравшись в современных инструментах деплоя его (языка) экосистемы.
Спасибо. Понятное дело что сейчас есть и современные инструменты деплоя, но к сожалению сайтики которые достаются «на доработку» после горе-фрилансеров чаще всего бывают написаны на какой-нибудь джумле, симпле, старом изувеченном вордпрессе или спионеренном битриксе, временами со всякой вирусней. Ничего предвзятого — личная статистика. В период с 2008-го по 2013-й год с просьбами «спасите помогите» по разным причинам нам передали порядка 12 сайтов с разными проблемами, из них 3 на Ruby/Rails и 9 на PHP(разные CMS). Так вот, рельсовые были просто написаны тяп-ляп но вполне пригодны к обслуживанию(как минимум вся история коммитов была у каждого, т.к. это часть инфраструктуры), а вот PHP-братья практически все (кроме одного, который делали относительно адекватные люди) были с полным букетом всевозможных гадостей начиная от вирусни которая почему-то случайным образом поудаляла строки из каждого третьего скрипта, и заканчивая невыпиленными якобы-nulled модулями которые по своей сути являлись троянцами, где-то были обфусцированные виртуальные шеллы. В общем — зоопарк да и только. У нас даже сервер отдельный был для этого дела, с говорящим именем kenny.
Я не хочу никого обидеть лично, но к сожалению многие PHP-проекты работающие в интернете до сих пор, работают без СКВ на сомнительных виртуальных хостингах и на непонятных CMS разного розлива. Да, к тому времени как стали появляться современные фреймворки на PHP уже были написаны миллионы говносайтов.
Я не утверждаю что один язык лучше другого, я говорю лишь о том что не все кошки — львы, но все львы — кошки.
А теперь главный вопрос: как же защититься от возможной атаки?
* Для «анонимов» делать отдельную учетную запись, в убунте есть «гостевая сессия».
* Если подключение через ssh — авторизоваться заново сразу в рута ключами (т.е. без использования sudo).
Круто, спасибо за ещё один метод. Однако функции можно объявлять и прямо в оболочке, так что проверка конфига не спасёт:

функция продержится только для этой сессии и скорее всего незаметной не останется.
Да верно. После закрытия терминала она исчезнет. Но на невнимательных пользователях может сработать. Тем более, если предварительно очистить историю и перетереть буфер команд в терминале
Историю можно не очищать, если перед function вставить пробел.
если добавлять пробел перед командой, то в историю она не попадет
Команда не попадет в историю если в переменную HISTCONTROL записать ignorespace
Не задумывался о такой возможности, спасибо за инфу.
А теперь вопрос: А можно ли держать все тоже, что и в ~/.bashrc, но с другим именем файла, чтобы изменения в нем не срабатывали?
Собственно понятно, что имя файла задается в ~/.bash_profile, но вот и его изменить.
Спасибо!
Что-то подобное предполагал.
% function /usr/bin/sudo() {
        echo PWNED
}
% \/usr/bin/sudo            
PWNED

zsh

$ ///////////////////////usr////bin//sudo
:)
% function preexec() {
  function $1 {
    echo PWNED
  }
}
% ///////////////////////usr////bin//sudo
PWNED

zsh

Я не понял, как мы можем подложить наш .bashrc другому пользователю в хомяк, если у нас туда нет прав?
Или здесь описан способ подмены .bashrc в собственном хомяке? Но какой в этом смысл?
Про подмену речи и не шло.
alias'ом
Все равно не понимаю: как мы заставим другого пользователя использовать наш алиас?

Мы работаем только с .bashrc текущего пользователя. Смысл в том, что если пользователь находится в группе sudo и мы получим его пароль, то мы становимся root`ом на сервере. Так что наша задача получить пароль текущего пользователя и повысить права.

Это типа если пользак от компа отошел и экран не залочил? ))
Окей, а в случае с сервером — как мы попадем в шелл пользователя, не зная его пароль?
Так речь не про получение доступа к пользователю, а про повышение полномочий до рута.
Статья описывает как угнать пароль у самого себя. Это, несомненно, полезно, но где здесь повышение привилегий до рута, я все равно не понимаю?
Статья о том, как получить пароль от пользователя, к которому уже есть доступ. Например, вы сперли ssh-ключ пользователя или имеете веб-шелл через дырку в сайте. Но чтоб сделать что-то серьезное нужен рут. Если пользователь судоер, то его пароль даст вам эту возможность.
Спер ssh-ключ пользователя — отлично, зачем мне теперь пароль?
Через дырку в сайте я попал в пользователя с неограниченным судо? То есть веб-сервер работает от пользака с крутыми правами на судо? Вы серьезно?
Статья говорит нам о том, что очень небезопасно даже выполнять команды по полному пути, т.к. кто-то уже мог зайти под вами. Ну ок, тогда надо еще написать статью, что очень небезопасно работать на сервере, если вы разместили рутовый ssh-ключ и айпишник сервера на всех форумах Интернета. Тот же смысл…
Один ключ от нерутового пользователя в группе sudo/adm не даст вам обычно выполнить команду sudo — нужен ещё пароль пользователя.
В продакшене пароль на sudo в основном запрашивается, но все таки может и не запрашиваться…
UFO just landed and posted this here
Не в качестве «эксперта», а скорее в качестве КО, выступающего в качестве набюдателя :) — многие юзают ключи только для того, чтобы не вводить пароль для доступа к удалённому серверу, а ввод passphrase для них — это почти то же, от чего они хотят избавиться :)
UFO just landed and posted this here

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

UFO just landed and posted this here

Прогнозирую, поэтому ставлю пароль на судо.

UFO just landed and posted this here
UFO just landed and posted this here
В большинстве случаев, ssh ключи создают для того, чтобы авторизация проходила автоматически, то есть без ввода пароля вручную.

Дополнительная возможность защитить паролем ssh ключ — это как опция, которая в моей практике встречалась наверное раза 2 на пару тысяч.
UFO just landed and posted this here

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


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

Блин, да статья вообще не про ключ и не про статистику использования passphrase.
Статья рассказывает про один вектор атаки с одной целью при заданных исходных условиях. Откуда эти условия взялись — это за рамками статьи. Вы ж не спрашиваете в задачке про землекопов откуда они взяли лопаты, и почему там не экскаватор.
UFO just landed and posted this here
Доступ к шеллу пользователя можно иметь не только через незакрытый ключ.
Можно использовать уязвимости ПО, можно соц. инженерить. Не рассматривали этот вариант?
UFO just landed and posted this here
UFO just landed and posted this here
Суть в том, что данная статья про то, что запуск приложения по абсолютному пути можно подделать созданием функции. И это еще один вектор атаки.

И это не имеет никакого отношения к тому, что вы хотите развести дискуссию про ssh ключи, о чем вам уже говорят прямым текстом.
P.S. Хоите пообсуждать — напишите статью, что вы считаете, создавая ssh ключи нужно всегда защищать их паролем, и пообсуждайте это в комментарийх к вашей статье.
UFO just landed and posted this here
Приведите пожалуйста пример, каким образом приватные ключи относятся к выполнению программы по абсолютному пути?

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

Нет, этот вектор атаки прежде всего против владельцев/администраторов серверов, которые дают sudo права пользователям. В общем случае владелец/администратор сервера не может проконтролировать запароленный или нет ключ, используемый пользователем. Вот наши админы дают доступ на сервера мне, контролируемому мною пользователю CI/CD и не могут знать, есть ли у меня пароль на закрытом ключе. Или может я храню ключ и пароль в паблике, в той же репе запушил для удобства. Но если ключ и пароль (в случае запароленного ключа) у меня уведут, то атаковать будут не меня (у меня на серверах ничего и нет толком), а сервер за работу которого они отвечают. И последняя защита от такой атаки — пароль на sudo, который можно пхитить описанным в посте способом.

Узнать есть ли пароль на закрытом ключе вообще несложно. Другое дело, уже узнать этот пароль.

У самого sudo нет отдельного пароля, это тот же пароль пользователя. И если у вас есть рутовые права, то зачем вам игры с алиасами и функциями, если вы можете просто подменить executable, что гораздо более надежно.

Как узнать на ssh-сервере, если ли у ssh-клиента пароль на закрытый ключ, с помощью которого он подписал запрос на соединение? Какой-то особый флаг в протоколе?


Последняя защита от такой атаки — требовать пароль пользователя при запуске sudo, не использовать NO_PASSWD или как-там его в sudoers — так понятней?


Нет рутовых прав у взлоимщика, есть права пользователя, который есть в sudoers без NO_PASSWD. Цель атаки — получить пароль этого пользователя на этой машине, чтобы получить рутовые (в общем случае) привилегии.

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

Если вы админ сервера, НА который ходят юзера, обычно у вас и так есть доступ ко всем сервисам на этом сервере.

А если вы уже смогли зайти под указанным пользователем, проще PATH подправить. Я вот не помню, чтобы когда-либо писал sudo с абсолютным путем.

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

Ну это же просто пример использования, а не суть уязвимости. Я уже несколько раз говорил, что дело не в su/sudo.

И права в sudo настраиваются гибко, вполне можно давать права к конкретной команде, а не вообще.

Можно и passwd подменить — и sudo будет не причем.

А можно подменить файл устройства, который как раз часто указывают с полным путем.

В общем сейчас спор ни о чем.

Далеко не факт, что пренебрегает именно атакуемый (владелец сервера), а не кто-то из тех, кому он дал доступ. Ну и вариант, что сперли закрытый ключ вместе с паролем тоже не исключен.

UFO just landed and posted this here
UFO just landed and posted this here
В систему вы от пользователя зашли, но для выполнения sudo нужен пароль. Подменяем sudo и ждём пока пользователь воспользуется и введёт пароль для вас.
UFO just landed and posted this here
UFO just landed and posted this here
То есть ещё и похищенный приватный ключ должен быть без парольной защиты, что ли?

Да, или как вариант ключ спёрли вместе с паролем.

Что, есть такие люди, серьёзно?

Да туева хуча просто.

Минусаторы, это же вы не закрываете свой приватный ключ паролем, да?

Вопрос не ко мне.

Для удобства, да?

Да.

Не все осиливают в ssh-agent/gpg-agent/pageant.


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

Не каждый sudoer прописан с NOPASSWD. Можно получить шелл пользователя, но не иметь возможность выполнить sudo.

UFO just landed and posted this here

Уязвимость.
Например, был какой-то shellshock, который позволял выполнять произвольный код.

Ну например
помогите, пожалуйста исправить такую программу:

cat «test… test… test...» | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|` (...)'

— не печатает

:)

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

Это очевидно, поэтому я порезал эту строку в конце, чтобы она не работала, не надеясь на всякие предупреждения. "(...)" — это не перл-код…

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

UFO just landed and posted this here
UFO just landed and posted this here
Да суть не в этом. В основном прикол в том, шелл — вещь старая, проверенная, и поведение команд в нем предсказуемое.
А функция, которая подменяет собой запуск файла с указанием прямого пути — штука, которую не каждый самостоятельно найдет даже за много лет. Просто потому что мысль нетривиальная, при этом все так просто…

В общем серьезной уязвимости в этом нет, но фича нестандартная — это и вызывает удивление.
[sarcasm] alias sudo='sudo rm -rf /root_mountpoint' [/sarcasm]

bash --restricted не спасет нас от нашего сервера (к слову уже скомпрометированного)?

Restricted bash интересный вариант, но при редактирование .bashrc он не поможет. В restricted режиме bash перестаёт воспринимать команды по абсолютным путям и не даёт править PATH, однако мы можем свободно править PATH через .bashrc. Например:


PATH=~/.local/:$PATH

После этого создаём в папке ~/.local/ файл sudo со своим содержимым. Profit ;)

ОК, тогда это лечится:
chown root:root .bash_profile .bashrc .profile

дефолтные права 0644 можно оставить.

PS:
Может тогда сразу .bash_profile править? ;-)
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH


Изменение владельца файла самый действенный способ в данном случае. По крайней мере он значительно безопаснее и удобнее остальных ;)


По поводу .bash_profile или .bashrc — разница не велика, просто в случае .bash_profile придётся ждать, пока пользователь перезайдёт в систему, а изменения от .bashrc сработают уже при следующем открытие терминала.

$ sudo chown root:root .bashrc

к сожалению, сменить владельца не поможет. Пользователь имеет право запись на папку ~/
$ mv .bashrc .trololo
$ cat .trololo > .bashrc
Отставить панику! :-)

[root@test1 int2]# chown root:root .bashrc ; chattr +i .bashrc
[root@test1 int2]# su - int2
boom
[int2@test1 ~]$ ls -la .bashrc
-rw-r--r-- 1 root root 135 Feb 22 17:38 .bashrc
[int2@test1 ~]$ mv .bashrc 1
mv: cannot move `.bashrc' to `1': Operation not permitted
[int2@test1 ~]$


И это я еще не вспомнил про selinux и контексты на файлы.
Не знал что атрибуты могут помочь. Спасибо за идею.

А вот selinux далеко не у всех задействован. Плюс к этому, правильная его «готовка»… это уже высший пилотаж который мне не доступен.
Сделать restorecon на файл или «открыть» лишний порт… ok… но не более.
А как на reiserfs? Там ведь нет immutable…
chown root:root .bash_profile .bashrc .profile

cp .bashrc .bashrc.old
rm .bashrc
mv .bashrc.old .bashrc


В *nix право удаления файла(хардлинка) определяется правами на папку в которой он лежит.

По сути, нужно запретить использование слешей в именах функций.

Можно даже прямо пулл реквестом, с примером злоупотребления.
UFO just landed and posted this here
Я думаю, это решение не с той стороны, шеллов много, все со своими особенностями.
На мой взгляд, проблема в sudo.
Почему оно никак не сигнализирует, что пароль получен через перенаправление ввода/вывода?
Хотя бы можно быстро поменять пароль постфактум.

Интересно, есть ли механизм чтобы ввод от пользователя получать максимально напрямую?
Дело явно не в sudo. Кто мешает написать что-то типа:

read -p "[sudo] password for $LOGNAME: " -s password
echo $password > \data\kekeke.lst
echo "Password error, please try again"
sudo

Нету, не через ssh. Максимум вы можете проверить, что ввод идёт с терминала, но сделать stdin терминалом и всё равно отправить туда украденный пароль несложно: такое позволяет, к примеру, скрипт expect на tcl, есть много портов на другие языки.

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

А как вы создадите пользователя без sudo?

А! Ну да. Видимо, перетрудился — не подумал

Символы / в имени идентификатора функции это что то за гранью, я в шоке!

Я считаю эту 'фичу' практически уязвимостью повышения привелегий.

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

p.s. существуют ли готовые решения (внешние устройства или хотя бы приложения android) которые на любое превышение полномочий sudo и авторизацию, запрашивают доступ с подтверждением на это внешнее устройство (не просто да/нет а с подробным описанием что именно)?
sudo по дефолту использует PAM-аутентификацию, а значит любые устройства, работающие с PAM, могут быть использованы для sudo. Например, Google Authenticator, который есть для Андроид.
Двухфакторная авторизация по таймкодам хороша но не подходит под требование — я должен знать что за операция требует повышение привилегий или доступ к какому серверу ssh требуется и т.п.!

Какими готовыми инструментами можно настроить передачу и отображение необходимой информации на android устройстве?!
Мне недостаточно автоматического подтверждения (когда android устройство само передаст необходимую информацию или проведет авторизацию самостоятельно) и недостаточно безликого окошка принять/отказать, я хочу знать кто и зачем требует права! именно это позволит защититься от атак, использующих уязвимость, описанную в статье.
То есть пользователь вводит команду и ждет аппрува от вас? Тогда наверное лучше оформить запрос в виде служебной записки с подробным объяснением, что и зачем требуется, и обязательно с подписью начальника отдела. Тогда это гарантировано не пройдет мимо вас :)
Сомневаюсь, что в Линуксе есть готовые решения подобного рода.
Именно, с электронной подписью и логированием, а там где необходимо, внешнее устройство должно хранить приватные ключи и отвечать за шифрование! Еще уровни и зоны ответственности вводить, разные люди (устройства авторизации) отвечают за разные типы действий!

А вы что думали?

Конкретно сейчас я бы не отказался просто от того что писал в предыдущем комментарии, развитие системы до корпоративной системы безопасности можно отложить на потом.
Вас спасет SElinux. В нем даже будучи реальным рутом, ты можешь иметь очень ограниченные права в зависимости от своей роли. То бишь все пользаки могут быть рутами, но роль может быть у всех разная. Но готовых политик на этот счет нет, придется все писать самому.
вы похоже не понимаете проблемы?

мне не нужно меня же ограничивать, ограничения не работают когда мне НУЖЕН доступ, мне нужен простой контроль над тем что происходит в системе и парольный менеджер (точнее менеджер доступа) ВНЕ компьютера, в моем сотовом как вариант (или android-часы, идеальный юзкейс).

сейчас я использую keepass но от паролей хочу уйти, мало того хранилище ключей тоже хочу на сотовом, а вот реальных готовых инструментов для этого НЕТ или я плохо ищу.
Отправлять security-лог на телефон? Вы уверены, что этого и правда хотите? Готовы получать сотни сообщений в день? Тогда можно сделать так, чтобы security-лог отправлялся, например, в Slack или Telegram. Это, в принципе, не сложно.
Пожалуйста, не нужно за меня придумывать что я хочу, я же очень внятно описал еще три сообщения назад!

У меня на телефоне парольный менеджер, я туда бы еще положил хранилище приватных ключей и в идеале завязал бы на него их использование. Сейчас я переношу пароль на машину руками (но чаще конечно с использованием локальной установки keepass, что мне ОЧЕНЬ не нравится) — хочется исключить из этого фазу ввода пароля руками но при этом не отдавать на откуп полной автоматизации передачу этих паролей на локальную машину, потому как она может внезапно стать скомпроментированной! Просто напросто в тех случаях в которых я сейчас пишу пароли руками, я хочу видеть соответствующее сообщение на телефоне и одним касанием принимать решение — разрешить или отклонить действие.

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

А так получится? Разве sudo будет видеть определённую в bash функцию?

А кто сказал «на функцию»? Сохраняете куда‐то скрипт, используете sudo bash myscript.sh "$@", myscript.sh выполнит с привилегиями и работу для злоумышленника, и запрос пользователя, переданный через $@. И bash myscript.sh "$@" всё ещё подпадает под определение «команда».

Обратите внимание на заголовок статьи. Вся изюминка в имени функции.
обратите внимание на статью, внимательно!
sudo bash myscript.sh в предыдущем комментарии успешно подменяется функцию /usr/sbin/sudo и для надеждности еще и просто sudo

?! В статье sudo подменяется на что‐то, что сохраняет пароль и использует настоящий sudo дважды, но скармливая пароль через stdin. Автор комментария, на который ответили комментарием, на который ответил я, предлагал не заморачиваться с сохранением паролей (получая проблемы, если используется не только пароль), а просто подменить команду на свою. Имя функции тут ни разу не причём, обсуждалось её содержимое.


Кстати, помимо двухфакторной аутнефикации с кодом из статьи есть ещё куча проблем: во‐первых, мало того что eval там ни разу не нужен, так код составлен так, что нельзя нормально использовать какие‐либо команды, содержащие в аргументах специальные символы любого рода — даже пробел всё сломает. Во‐вторых, echo нельзя использовать для чего‐либо сложнее helloworld. Особенно, если это пароль: если пользователь использует спецсимволы, то вы вполне можете увидеть пароль, начинающийся с - и содержащий \n. Мой bash это переваривает (если только пароль не выглядит как -e: хоть и из двух символов, но в словарях мелькать не должен), но я не скажу за любой bash. Другие мои оболочки вроде posh и zsh не переварят нормально. В‐третьих, интерактивные команды идут лесом, тот же sudo vi вы так не запустите (точнее запустите, но он вам пожалуется на ввод не с терминала). Конечно, это не суть статьи, но обойти третью проблему будет сложнее, чем просто использовать свою команду для sudo. Особенно, если нужен не просто ввод пользователя (здесь вроде cat <(printf '%s\n' "$password") /dev/stdin | sudo … должно помочь), а полноценный терминал.

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

А sudo тут вообще не причем, это частный случай.

P.S. Вдобавок можно немного играться с социальной инженерией, например так:
$ cat /etc/passwd | /dev/null
kekeke

Сходу, просматривая длинный чужой скрипт и не поймешь что не так в выполняемой команде, а там всего лишь и "|" вместо ">" и функция
function /dev/null { cat >> data ; echo "kekeke" ; }


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

На самом деле, если у злоумышленника есть полный доступ к аккаунту пользователя в wheel, то это скорее всего основной пользователь в системе. А это значит, что переживать по поводу sudo в алиасах — умеренно бессмысленно. При полном доступе к аккаунту, прикрутить кейлоггер вообще не проблема, хотя для иксов, хоть для шелла. Да и утечка ключей/личных данных/секретных документов — возможно бóльшая проблема, чем потенциальный рутовый доступ.

Спасает auditd который сразу пейджит при активности. У вас не должно быть причин активно работать на продакшене из-под рута (или любого привелигированного в sudo пользователя). Приучайтесь к полностью автоматизированным цепочкам.

Что-то мне кажется, это не последний сюрприз из мира юниксов.

Если у вас есть такой доступ, чтобы добавить пользователю что‐то в конфиг, то пользователя не спасёт почти ничего: для начала, если есть куда положить исполняемый файл, то можно подменять системные вызовы через LD_PRELOAD. Никакой абсолютный путь не спасает.


Но даже если исполняемый файл положить негде (везде ro или noexec), то есть другой относительно простой хак: в bashrc пишем exec strace -e read -o >(process-reads.sh) bash (не забываем предотвращать бесконечную рекурсию) и мы можем читать всё, что пользователь пишет в bash. Если нет strace, то нужно как‐то создавать pty и подставлять её на вход bash, а самим читать из оригинальной и дублировать туда, но вроде тоже ничего невыполнимого. Я использую что‐то подобное, чтобы всегда запускать zsh внутри dtach и hilite (первое против случайных закрытий эмулятора терминала, второе подсвечивает stderr красным (чтобы отличался от stdout) и провоцирует странное поведение у некоторых программ).


В zsh намного проще: есть куча виджетов для zle, ту же функцию ////usr//bin///////sudo можно сгенерировать прямо на лету: после того, как пользователь нажал ввод, но до того, как что‐то реально выполнилось.

Про LD_PRELOAD тоже хотел написать, но вы меня опередили.

P.S. На самом деле векторов атаки на сервер при наличии ssh очень много, да и без ssh много, нужно следовать простому правилу — не давать sudo всем кому попадя, а если и давать, то ограничивать вход по IP и использовать rsa ключи + обязательный мониторинг активности и аудит.

Кстате говоря, админы, простой вопрос:
1. Вы монтируете /tmp и /var/tmp с nosuid и noexec? 100% нет, вот вам вектор атаки.
2. Вы мониторите задачи в cron? Вы ограничиваете использование утилиты at и cron через /etc/at.deny и /etc/cron.deny? 100% нет, вот вам и еще один вектор атаки.
3.…
и таких векторов много, конечно цель их не в получении прав root, а в простом превращении вашего сервера в часть ботнета.
нужно следовать простому правилу — не давать sudo всем кому попадя, а если и давать, то ограничивать вход по IP и использовать rsa ключи + обязательный мониторинг активности и аудит

Я бы добавил к этому правилу ограничение на исполняемые пользователем команды.
каждому пользователю должно быть позволено запускать от рута не более того, что ему реально требуется для работы. Т.е по возможности никаких ALL в конфиге sudo.

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


Это само собой разумеется, но вообще я не сторонник в принципе давать кому-то «урезаные» привилегии использовать sudo — в частности например дать кому-то право перезапускать apache или nginx, под соусом типа вот тебя нет на рабочем месте, а apache завис, дай мне право его перезапускать — нет и еще раз нет. Есть администратор сервера, который полностью отвечает за него, все остальные идут лесом.

Что делать с учетными записями систем провижна и деплоя приложений?

на суидные бинарники LD_PRELOAD не работает, увы.

А я и не предполагал это для sudo. Достаточно перехватывать execve bash’а и запускать скрипт из статьи вместо sudo. Bash‐то ни разу не suid.

достаточно заэкранировать первый символ
\su
\kinit
можно вообще писать «s»u

Alias substitution
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03_01
У нас на серверах используется pam_ssh_agent, который проверяет SSH-ключ пользователя перед тем, как дать судо.

При том, что прокидывание ключа само по себе не очень хорошая идея, получающаяся конструкция всё-таки более устойчива к краже креденшиалов, чем при использовании паролей. Злоумышленник может что-то сделать от имени пользователя, но только в то время, когда ключ доступен.
Госсподи, ну и бредятина, давненько я такого не читал. Куда катится хабр? Люди на всю готовы ради кармы. Не удивлюсь скорому появлению какого-нибудь флагшток-куна на хабре.
Госсподи, откуда у людей столько желчи и злобы?
Например, для меня этот вид вектора атаки является откровением, хотя считал себя чуть продвинутым пользователем!
да о чём вы говорите вообще, если у пользователя уже есть права sudo??? и если для тебя это откровение, ну что ж, у меня для тебя плохие новости

Нет у него прав sudo пока нет пароля.

в чем тут атака, поясните? кто-то как-то пробрался к вашему bashrc?

Кто-то как-то пробрался — это условие атаки. Атака заключается в получении вашего пароля для повышения привилегий.

Какие есть способы обойти проблему, если есть подозрение, что аккаунт скомпрометирован (bashrc подменили).
Можно переименовать или удалить bashrc, но ведь и эти команды могут быть подменены на функции…
Пока вижу только запустить mc и в нём посмотреть bashrc. Правда, ведь и в mc можно какие-нибудь настройки сделать злонамеренные.

Никак. Если получен доступ к аккаунту пользователя, то нужно воспользоваться другим: ssh, во‐первых, всегда использует оболочку для исполнения любой команды (а оболочка читает некоторые настройки даже в неинтерактивном режиме), во‐вторых, исполняет ~/.ssh/rc. Оба этих варианта могут быть использованы для того, чтобы подделать произвольную программу в окружении, хотя и разными способами (второй проще всего сводить к первому: восстанавливать заражённые настройки). Т.е. если, к примеру, вы запустили ssh machine -- echo '1 2', то вы получите следующие execve вызовы:


/bin/sh -c '$SHELL -c "/bin/sh .ssh/rc"'
  $SHELL -c '/bin/sh .ssh/rc'
    /bin/sh .ssh/rc
    # Кто вообще придумал такой странный способ работы с .ssh/rc?!
$SHELL -c 'echo 1 2'
# Да, ssh благополучно выбросил информацию о разделении на аргументы.

С zsh всё уже плохо: он читает файлы вроде ~/.zshenv даже в неинтерактивном режиме. Bash не читает в неинтерактивном режиме никаких файлов настроек… если только вы не определили переменную BASH_ENV (или bash запущен в неинтерактивном режиме и с именем /bin/sh, тогда вообще никаких файлов никогда не читается). А определить данную переменную можно в ~/.ssh/environment, если только оно не запрещено (по умолчанию запрещено).


Кроме того, chsh вроде работает без sudo и без требований пароля, так что ~/.ssh/rc поможет с «не той» оболочкой (работать начнёт со следующего запуска ssh, первый запуск с неизменённой оболочкой). Если, конечно, администратор не запретил.


Впрочем, sshd можно запретить использовать как ~/.ssh/rc, так и ~/.ssh/environment, первое по‐умолчанию разрешено.


Таким образом, предполагая, что


  1. Злоумышленник может писать в любое место, куда может писать пользователь.
  2. ~/.ssh/rc разрешено, а ~/.ssh/environment нет.
  3. Злоумышленник ещё не подменил оболочку (если есть куда положить исполняемый файл и chsh работает, то никаких способов избежать использования подменённой оболочки нет — даже sshfs запускает оболочку пользователя).
  4. ~/.ssh/rc настроено так, чтобы подменять файлы настроек и запускать chsh.
  5. Используется оболочка, не читающая какие‐либо пользовательские файлы при неинтерактивном запуске.

то способ как‐то избежать проблемы будет


ssh remote -- 'chsh -s /bin/sh ; cat suspicious-file' | less
# Просмотр подозрительного файла: нафига вам mc? Просто гоните файл по сети.
ssh remote -- 'chsh -s /bin/sh ; rm -f suspicious-file' | less
# Удаление подозрительного файла.

(Уберите chsh, если подменять ей оболочку без пароля/sudo нельзя.)


Но если что‐то из условий не выполняется, то бегите к кому‐то с бо́льшими привилегиями либо физическим доступом.

В общем, есть подозрения — не используйте сложные программы с настройками. cat и rm не имеют никаких файлов настроек, если вам как‐то не подменили $PATH или оболочку (и вы не используете zsh в качестве оной), то беспокоиться не о чём. Но проверить, не подменили ли вам оболочку в общем случае вы не сможете.

Не всё так страшно на самом деле. Если хочется быть уверенным в комманде, которую запускаешь или цель написать скрипт, устойчивый к подобного рода ситуациям, то в BASH есть built-in комманда command:

command [-pVv] command [arg ...]
Run command with args suppressing the normal shell function lookup. Only builtin commands or commands found in the PATH are executed. If the -p option is given, the search for command is performed using a default value for PATH that is guaranteed to find all of the standard utilities.

и в добавок builtin, для запуска только таковых комманд

builtin shell-builtin [arguments]
Execute the specified shell builtin, passing it arguments, and return its exit status. This is useful when defining a function whose name is the same as a shell builtin, retaining the functionality of the builtin within the function.

И вот как это работает для приведённого выше примера.
Можно игнорировать одноимённые функции при помощи 'command sudo' или даже 'command -p sudo'.
Если же кто-то попытается установить alias для command, тогда можно усилить решение через 'builtin command -p sudo'. Но если кто-то пойдёт ещё дальше, и установит alias для builtin, то можно в начале скрипта запустить команду 'unalias builtin' и потом все критичеки важные комманды запускать при помощи последнего варианта. А чтобы не делать это решение сильно усложнённым, можно начинать скрипт как

#!/bin/bash
unalias builtin
function run() { builtin command -p "$@"; }
run sudo

Ещё не плохо было бы переопределять всегда PATH в начале скрипта на что-то, что вы ожидаете там увидеть.

Итого:

$ /usr/bin/sudo -V
Sudo version 1.8.18p1
Sudoers policy plugin version 1.8.18p1
Sudoers file grammar version 45
Sudoers I/O plugin version 1.8.18p1

$ alias sudo=«echo SuD0»
$ function /usr/bin/sudo() { echo 'Truly '; }
$ alias command=«echo 'Really '»
$ alias builtin=«echo 'Eventually '»

$ /usr/bin/sudo -V
Truly

$ sudo -V
SuD0 -V

$ command sudo -V
Really sudo -V

$ command /usr/bin/sudo -V
Really /usr/bin/sudo -V

$ builtin command sudo -V
Eventually command sudo -V

$ unalias builtin
$ builtin command sudo -V
Sudo version 1.8.18p1
Sudoers policy plugin version 1.8.18p1
Sudoers file grammar version 45
Sudoers I/O plugin version 1.8.18p1

$ function run() { builtin command -p "$@"; }
$ run sudo -V
Sudo version 1.8.18p1
Sudoers policy plugin version 1.8.18p1
Sudoers file grammar version 45
Sudoers I/O plugin version 1.8.18p1

Писать unalias в скрипте абсолютно бесполезно: это интерактивная возможность. Скрипты вообще обычно запускаются без того, чтобы bash загружал какие‐то файлы (но даже если он их загружает через BASH_ENV, а вы указали именно #!/bin/bash или написали bash script.sh, то именно alias’ы использоваться не будут, в отличие от функций). К тому же, все ваши методы из похаканного bash абсолютно бесполезны: и unalias, и unset, и builtin, и command — всё может быть переопределено как функции. Как функции не могут быть переопределены только синтаксические конструкты вроде if или function (точнее, можно определить функции if и function, просто bash не будет их использовать, если только вы не напишете что‐то вроде 'if' funcarg1).

Кстати, alias unalias='echo FOO' тоже работает. Но адекватный злоумышленник не будет использовать alias в принципе: достаточно написать \unalias unalias и alias уберётся. С функциями у вас ничего такого не выйдет, они уберутся только от unset -f, но unset тоже может быть функцией.

По крайней мере, именно эту проблему, --posix параметр решает, не беря во внимание особенностей работы bash в этом режиме

$ cat a.sh
#!/bin/bash --posix

function builtin() { echo new_builtin; }
function command() { echo new_command; }
function echo() { :; }

unset -f builtin
builtin command echo Hello World

$ ./a.sh
Hello World
Да, с alias в скриптах, справедливо ;)

А на счёт unset как новая функция, есть ещё параметр --posix и он то не даст переопределить unset, а значит и 'unset -f builtin' в начале скрипта должен сработать.

$ bash --posix -c 'function unset() { echo new-unset; }'
bash: `unset': is a special builtin

А кто будет это posix подставлять? Напоминаю, статья вообще‐то об интерактивной оболочке. ssh ничем подобным не занимается по‐умолчанию. И не по‐умолчанию вы ничего подобного делать не захотите: с --posix вам нужно как‐то извратиться и определить переменную ENV, иначе никаких bashrc bash читать не будет. И файл по $ENV будет также уязвим, как и любой другой ваш файл настроек. В том числе он может перезапустить bash уже без --posix. А использование ssh в ключе ssh remote 'chsh -s /bin/sh ; cat ~/.bashrc' (как я предлагал здесь) ровно настолько же имунно к изменениям в файловой системе в $HOME, насколько имунны скрипты.


Самый простой способ избежать атаки, описанной в статье: создавать файлы настроек из‐под этого самого sudo, пароль к которому предлагается уводить. Тогда злоумышленнику понадобится больше, нежели возможность редактировать ФС с правами непривилегированного пользователя. Собственно, автор приводит этот вариант в последнем абзаце как оптимальный.


Вот если же предполагается какой‐то доступ к переменным среды (т.е. то, что предполагается в цитате из руководства), причём не ограниченный $PATH, то всё плохо: я не раз упоминал здесь про $BASH_ENV, правда он испортит вам только скрипты и bash -c (а вот --posix + $ENV испортит только интерактивную оболочку). Зато $PROMPT_COMMAND, если не переопределяется в bashrc, испортит интерактивную оболочку (в т.ч. с --posix). Плюс bash с настройками по‐умолчанию позволяет определять функции в переменных окружения (хотя не все способы определить эти переменные тут сработают, т.к. обычно считается, что знака % в имени такой переменной быть не может, а он нужен): к примеру, с


env BASH_FUNC_unset%%='() { echo vulnerable } bash

вы будете иметь переопределённую функцию unset, или DOS‐атаку, если попытаетесь использовать --posix (bash не даст переопределить unset, равно как не даст и выполнить что‐либо). Причём, замечу, скрипты тоже уязвимы, а файлов настроек, в которых можно было бы запретить экспорт функций bash читать не будет.

UFO just landed and posted this here
Все действительно работает как написано. Только эту технику можно использовать для другого взлома: например директор отошел от своего компа и забыл его локнуть, а ты сел в его кресло и эту бяку настучал. На другой день переписал пароль на бумажку и подтер следы!
Sign up to leave a comment.