Комментарии 139
С тех пор пароли везде отключены, все движения и привелегии только по RSA-ключам и сайтики на PHP после кого-бы-то-нибыло ни за какие деньги не берем в обслуживание, особенно на каких-то сомнительных админках. Да и с 2013-го в работе только Ruby/Rails используем, через дефолтный деплой-паттерн по deploy-ключам, так что руками никто никуда не влезает вообще. На особо важных серверах доступ руту к ssh вообще заблокирован, только через отдельного пользователя по ключам.
А если быть честным — никогда нельзя быть ни от чего застрахованным и произойти может что угодно. На любую меру безопасности есть контр-мера, вопрос только в том чтобы найти оптимальный уровень удобный для работы но при этом относительно безопасный.
Я не хочу никого обидеть лично, но к сожалению многие PHP-проекты работающие в интернете до сих пор, работают без СКВ на сомнительных виртуальных хостингах и на непонятных CMS разного розлива. Да, к тому времени как стали появляться современные фреймворки на PHP уже были написаны миллионы говносайтов.
Я не утверждаю что один язык лучше другого, я говорю лишь о том что не все кошки — львы, но все львы — кошки.
А теперь главный вопрос: как же защититься от возможной атаки?* Для «анонимов» делать отдельную учетную запись, в убунте есть «гостевая сессия».
* Если подключение через ssh — авторизоваться заново сразу в рута ключами (т.е. без использования sudo).
А теперь вопрос: А можно ли держать все тоже, что и в ~/.bashrc, но с другим именем файла, чтобы изменения в нем не срабатывали?
Собственно понятно, что имя файла задается в ~/.bash_profile, но вот и его изменить.
В исходниках bash`а путь к .bashrc захардкожен, поэтому единственный способ изменить его — пересобрать bash из исходников.
http://git.savannah.gnu.org/cgit/bash.git/tree/config-top.h
/* Default interactive shell startup file. */
#define DEFAULT_BASHRC "~/.bashrc"
Или здесь описан способ подмены .bashrc в собственном хомяке? Но какой в этом смысл?
alias'ом
Мы работаем только с .bashrc текущего пользователя. Смысл в том, что если пользователь находится в группе sudo и мы получим его пароль, то мы становимся root`ом на сервере. Так что наша задача получить пароль текущего пользователя и повысить права.
Окей, а в случае с сервером — как мы попадем в шелл пользователя, не зная его пароль?
Через дырку в сайте я попал в пользователя с неограниченным судо? То есть веб-сервер работает от пользака с крутыми правами на судо? Вы серьезно?
Статья говорит нам о том, что очень небезопасно даже выполнять команды по полному пути, т.к. кто-то уже мог зайти под вами. Ну ок, тогда надо еще написать статью, что очень небезопасно работать на сервере, если вы разместили рутовый ssh-ключ и айпишник сервера на всех форумах Интернета. Тот же смысл…
Как админ компа, к которому я предоставляю ssh-доступ другим людям, я не знаю как они хранять свой закрытый ключ, с паролем или без пароля, на токене с тройной аутентификацией или на публичной файловой шаре. Пароль sudo — последний уровень защиты, доступный каждому.
Дополнительная возможность защитить паролем ssh ключ — это как опция, которая в моей практике встречалась наверное раза 2 на пару тысяч.
Авторизация (а точнее аутентификация) по ключам — замена парольной, а не дополнительный слой. В чём-то лучше, в чём-то хуже и по удобству, и по безопасности.
Дополнительный слой защиты ключа по паролю, доступный, как правило, только самому пользователю (я не слышал что атуентифицирующая сторона может отклонить запрос, если ключ без пароля — у неё просто нет информации об этом) вводится на усмотрение пользователя, на его личный баланс между удобством и безопасностью.
Статья рассказывает про один вектор атаки с одной целью при заданных исходных условиях. Откуда эти условия взялись — это за рамками статьи. Вы ж не спрашиваете в задачке про землекопов откуда они взяли лопаты, и почему там не экскаватор.
Можно использовать уязвимости ПО, можно соц. инженерить. Не рассматривали этот вариант?
И это не имеет никакого отношения к тому, что вы хотите развести дискуссию про ssh ключи, о чем вам уже говорят прямым текстом.
P.S. Хоите пообсуждать — напишите статью, что вы считаете, создавая ssh ключи нужно всегда защищать их паролем, и пообсуждайте это в комментарийх к вашей статье.
Пример использования данной уязвимости уже приводились в комментариях, в том числе и мной. В основном в виде обсфукации. А вот кидаться в крайности — это не хорошо.
Нет, этот вектор атаки прежде всего против владельцев/администраторов серверов, которые дают 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 злоумышленником, намеревавшимся собрать хороший “урожай” паролей.
И права в sudo настраиваются гибко, вполне можно давать права к конкретной команде, а не вообще.
Можно и passwd подменить — и sudo будет не причем.
А можно подменить файл устройства, который как раз часто указывают с полным путем.
В общем сейчас спор ни о чем.
Далеко не факт, что пренебрегает именно атакуемый (владелец сервера), а не кто-то из тех, кому он дал доступ. Ну и вариант, что сперли закрытый ключ вместе с паролем тоже не исключен.
То есть ещё и похищенный приватный ключ должен быть без парольной защиты, что ли?
Да, или как вариант ключ спёрли вместе с паролем.
Что, есть такие люди, серьёзно?
Да туева хуча просто.
Минусаторы, это же вы не закрываете свой приватный ключ паролем, да?
Вопрос не ко мне.
Для удобства, да?
Да.
Не все осиливают в ssh-agent
/gpg-agent
/pageant
.
Ну и вполне валидный вариант, когда ключ используется без пароля — автоматизированные системы, но это, кагбэ, и не локалхост разработчика.
Не каждый sudoer прописан с NOPASSWD. Можно получить шелл пользователя, но не иметь возможность выполнить sudo.
Уязвимость.
Например, был какой-то shellshock, который позволял выполнять произвольный код.
помогите, пожалуйста исправить такую программу:
cat «test… test… test...» | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|` (...)'
— не печатает
:)
Смысл в том, чтобы узнать пароль пользователя, в которого вы совершили вход без пароля (по какой-либо причине). А пароль нужен, чтобы выполнять команды от root через sudo.
0day RCE в любом IM-клиенте.
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2008-1805
Не на линуксе, прадва… Но неужели вы сомневаетесь в том, что при таком множестве создаваемых "на коленке" клиентов однажды попадется уязвимый?
А функция, которая подменяет собой запуск файла с указанием прямого пути — штука, которую не каждый самостоятельно найдет даже за много лет. Просто потому что мысль нетривиальная, при этом все так просто…
В общем серьезной уязвимости в этом нет, но фича нестандартная — это и вызывает удивление.
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 сработают уже при следующем открытие терминала.
к сожалению, сменить владельца не поможет. Пользователь имеет право запись на папку ~/
$ 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 и контексты на файлы.
chown root:root .bash_profile .bashrc .profile
cp .bashrc .bashrc.old
rm .bashrc
mv .bashrc.old .bashrc
В *nix право удаления файла(хардлинка) определяется правами на папку в которой он лежит.
Можно даже прямо пулл реквестом, с примером злоупотребления.
На мой взгляд, проблема в 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 на нашу, и больше ничего не надо! пароли, ключи доступа, внешние устройства авторизации — все идет лесом!
p.s. существуют ли готовые решения (внешние устройства или хотя бы приложения android) которые на любое превышение полномочий sudo и авторизацию, запрашивают доступ с подтверждением на это внешнее устройство (не просто да/нет а с подробным описанием что именно)?
Какими готовыми инструментами можно настроить передачу и отображение необходимой информации на android устройстве?!
Мне недостаточно автоматического подтверждения (когда android устройство само передаст необходимую информацию или проведет авторизацию самостоятельно) и недостаточно безликого окошка принять/отказать, я хочу знать кто и зачем требует права! именно это позволит защититься от атак, использующих уязвимость, описанную в статье.
Сомневаюсь, что в Линуксе есть готовые решения подобного рода.
А вы что думали?
Конкретно сейчас я бы не отказался просто от того что писал в предыдущем комментарии, развитие системы до корпоративной системы безопасности можно отложить на потом.
мне не нужно меня же ограничивать, ограничения не работают когда мне НУЖЕН доступ, мне нужен простой контроль над тем что происходит в системе и парольный менеджер (точнее менеджер доступа) ВНЕ компьютера, в моем сотовом как вариант (или android-часы, идеальный юзкейс).
сейчас я использую keepass но от паролей хочу уйти, мало того хранилище ключей тоже хочу на сотовом, а вот реальных готовых инструментов для этого НЕТ или я плохо ищу.
У меня на телефоне парольный менеджер, я туда бы еще положил хранилище приватных ключей и в идеале завязал бы на него их использование. Сейчас я переношу пароль на машину руками (но чаще конечно с использованием локальной установки 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" ; }
Все операции на сервере только по сертификату, который есть только у юзера на удаленной машине? С другой стороны при компроментации сертификата очень большие проблемы.
Спасает 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
можно сгенерировать прямо на лету: после того, как пользователь нажал ввод, но до того, как что‐то реально выполнилось.
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 завис, дай мне право его перезапускать — нет и еще раз нет. Есть администратор сервера, который полностью отвечает за него, все остальные идут лесом.
\su
\kinit
можно вообще писать «s»u
Alias substitution
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03_01
При том, что прокидывание ключа само по себе не очень хорошая идея, получающаяся конструкция всё-таки более устойчива к краже креденшиалов, чем при использовании паролей. Злоумышленник может что-то сделать от имени пользователя, но только в то время, когда ключ доступен.
Можно переименовать или удалить 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, первое по‐умолчанию разрешено.
Таким образом, предполагая, что
- Злоумышленник может писать в любое место, куда может писать пользователь.
- ~/.ssh/rc разрешено, а ~/.ssh/environment нет.
- Злоумышленник ещё не подменил оболочку (если есть куда положить исполняемый файл и chsh работает, то никаких способов избежать использования подменённой оболочки нет — даже sshfs запускает оболочку пользователя).
- ~/.ssh/rc настроено так, чтобы подменять файлы настроек и запускать chsh.
- Используется оболочка, не читающая какие‐либо пользовательские файлы при неинтерактивном запуске.
то способ как‐то избежать проблемы будет
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 в качестве оной), то беспокоиться не о чём. Но проверить, не подменили ли вам оболочку в общем случае вы не сможете.
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
тоже может быть функцией.
$ 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
А на счёт 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 читать не будет.
Так ли безопасно использование абсолютного пути в *nix системах, как мы привыкли считать?