Избавляемся от Email Injection
Проблема спама - одна из наиболее актуальных для обитателей всемирной паутины на сегодняшний день. Бесчисленное количество людей постоянно пытаются создать уникальные фильтры для прочистки почтового трафика, однако злые спамеры продолжают активно атаковать наши ящики каждый день предложениями купить что-нибудь или воспользоваться их услугами. Надоедает удалять весь этот ненужный контент, не так ли? Вот я и задумался, что же позволяет многим спамерам активно бомбить наши e-mail. Как оказалось, все довольно банально. Огромное количество злоумышленников используют так называемую E-mail-инъекцию, которая присутствует практически на любом сайте с формой обратной связи или возможностью посоветовать материал другу на e-mail. О ней и поговорим.
E-mail Injection - уязвимость веб-сайтов, эксплуатируемая в целях отправки большому числу адресатов почтовых писем, естественно, не с поздравлениями с Днем рождения ;). 95% сайтов в Сети обязательно содержат форму обратной связи или предлагают пользователю отправить ссылку на эту страничку другу на электронную почту. Очень редко информация, введенная пользователем, поддается какой-нибудь проверке со стороны скрипта отправки письма (обычно это код на PHP), за исключением самого текста письма, да и то только на наличие HTML тегов. Ну а цель спамера какая? Правильно, не попытка XSS-атаки на сайт, а донести какую-то информацию до почтовых ящиков пользователей. Инъекции поддается вводимая пользователем информация. Данный фактор позволяет без каких-либо препятствий рассылать нежелательную корреспонденцию. Причем, IP-адрес отправителя будет адресом сайта, с которого производится рассылка, а не самого злоумышленника. Это позволяет защититься от фильтров по blaklist'у, а заодно и делает спамера анонимным.
Техника e-mail-инъекции заключается в использовании особенностей MIME-формата (подробнее о нем можно почитать в Википедии: ru.wikipedia.org/wiki/MIME), в частности, добавление дополнительного списка получателей. MIME формат использует так называемый "возврат каретки", что позволяет ему отделять информацию друг от друга. Так вот, этот "возврат каретки" или символ переноса строк используется спамером для отделения и добавления большого числа адресатов и отправки им сообщения за один проход. Чтобы иметь представление об этой уязвимости, рассмотрим для начала устройства самого почтового сообщения.
Ковыряем "внутренности"
письма
Итак, что собой представляет обычное электронное письмо? Во-первых, это обычный текст. Простой набор строк с ключевыми словами (заголовками), благодаря которым программа-отправитель имеет представление об адресате, отправителе, теме письма и прочей информации. При отправке письма изначально идут заголовки с их значениями, а потом уже сам текст. Зная их предназначение, можно даже самому "читать" письмо, причем видеть его таким, какое оно есть на самом деле, а не таким, каким его показывает почтовая программа или сайт. Если рассматривать письмо с отображением его заголовков в почтовом клиенте, например, в TheBat, то оно будет выглядеть следующим образом:
Текст, выделенный жирным шрифтом, - это и есть заголовки сообщения, после которых идет текст письма. Заголовки, начинающиеся с X, необязательные. Они используются для разнообразной служебной информации, такой, как имя почтового клиента-отправителя или результат проверки на спам. Все достаточно просто.
E-mail injection в действии
Техника e-mail-инъекции, как я писал ранее, построена на особенности обработки этих заголовков. В рамках этой статьи мы рассмотрим три способа проведения атаки: при помощи манипуляции с полем "отправитель", при помощи манипуляции с полем "получатель" и при помощи подмены текста письма. Все они будут производиться из формы обратной связи и с использованием стандартной для PHP функции mail(). Заглянув в любой справочник, можно увидеть следующее описание данной функции:
Bool mail([RECIPIENT],[SUBJECT],[MESSAGE],[EXTRAHEADERS],[EXTRAPARAMS])
В качестве RECIPIENT выступает ящик, куда будет отправлено письмо; SUBJECT - тема письма; MESSAGE - текст сообщения; EXTRAHEADERS - дополнительные заголовки; EXTRAPARAMS - дополнительные параметры вроде флагов для командной строки программы-отправителя почты. Теперь можно приступить к рассмотрению примеров.
Манипуляции с отправителем
На сайте присутствует форма с полями "ФИО", "Обратный E-mail" и "Текст сообщения". Код отправки письма выглядит следующим образом:
<?php if($_POST['submit']) { $title = htmlspecialchars($_POST['title']); $mess = htmlspecialchars($_POST['message']); mail('[email protected]', $title, $mess, 'From:'.$_POST['email']); echo 'Сообщение отправлено.'; } ?> <form action="" method=post> <div align="center">ФИО<br> <input type="text" name="from" size="40"><br>Обратный e-mail<br> <input type="text" name="title" size="40"><br>Сообщение<br> <textarea name="message" rows="10" cols="40"></textarea><br> <input type="submit" value="Отправить" name="submit"></div> </form>
Функция htmlspecialchars используется для преобразования специальных символов в HTML сущности, что позволяет защитить от простейших атак. Для отправки сообщенияприменяется рассмотренная выше функция mail. "Мыльная" инъекция в таком случае производится путем подстановки специально сформированных данных в параметр EXTRAHEADERS вышеуказанной функции. Подставить можно, например, такие данные:
CC: [email protected], [email protected], [email protected]
Функция mail() без всяких запросов вставит данный текст как заголовок в наше письмо. А почтовый агент при отсылке письма отправит его копию всем указанным в CC (Carbon Copy) адресатам, тем самым помогая спамеру делать его грязное дело. Все просто как дважды два.
Манипуляции с получателем
Второй случай реализации инъекции доступен только тогда, когда разработчик web-сайта конкретно обезумел, и код отправки письма у него выглядит следующим образом:
<?php if($_POST['submit']) { $title = htmlspecialchars($_POST['title']); $to = htmlspecialchars($_POST[' to']); $mess = htmlspecialchars($_POST['message']); mail($to, $title, $mess, 'From:'.$_POST['email']); echo 'Сообщение отправлено.'; } ?>
В этом случае любой желающий может нагло и явно подставлять любое количество адресатов. В качестве $to можно подставить такие данные:
[email protected]%0ACC:[email protected]%0ABCC:[email protected],[email protected]%0Ato:[email protected]
Из такого запроса письмо отправится четырем пользователям из заголовков TO, CC и BCC. Они разделены между собой символом переноса "\n" в шестнадцатеричном виде (0x0A).
Манипуляции с текстом письма
Ранее я уже упоминал про MIME-формат. Он имеет один замечательный заголовок, Content type, который позволяет отправлять любые вложения в электронном письме. А еще он может быть использован для проведения e-mail-инъекции. В качестве значения Content type можно использовать multipart/mixed (или multipart/alternative или multipart/related), тем самым разделяя письмо на части. Эти части отделяются друг от друга некоторым набором символов (boundary). Пример письма с использованием заголовка Content-Type выглядит следующим образом:
To: [email protected] Subject: Test Injection From: [email protected] Content-Type: multipart/mixed; boundary="part1"; Скрытый текст - part1 Content-Type: plain/text;
Производим проверку на инъекцию
- part1- Еще один скрытый текст
Все заголовки до Content-Type мы уже рассматривали. Далее можно видеть boundary, значением которой служит "part1". Это и есть тот набор символов, который будет разделять наше письмо. Затем идет текст "Скрытый текст" - он не будет виден в почтовом клиенте, так как расположен до первого обозначения начала письма, которое идет следом за ним. Следующий текст будет виден как текст сообщения, заканчиваться он будет строкой "- part1-", указывающей на конец текста письма. А за ним идет второй скрытый текст, который также не будет виден большинством email-клиентов.
Чтобы организовать такое письмо, достаточно в качестве отправителя указать следующие данные:
[email protected]%0AContent-Type:multipart/mixed;%20boundary="part1"; %0A-part1%0AContent-Type:text/html%0A%0AТестовый%20Текст.%0A--part1-
Из такого запроса мы получим следующее сообщение:
Subject: Тест инъекции
From: [email protected]
Content-Type:multipart/mixed; boundary="part1";
-part1
Content-Type:text/html
Тестовый текст
-part1-
Привет, твой сайт очень классный!
Полученное письмо будет содержать только текст "Тестовый текст" (формат письма будет HTML, как видно из заголовка Content-Type:text/html), а "Привет, твой сайт очень классный!" останется незамеченным. Такой метод инъекции подходит для сайтов, в которых есть функция "Поделиться с другом". Чаще всего она не позволяет редактировать текст письма, но позволяет указать отправителя. В этом случае достаточно применить вышеуказанный способ, тогда вместо оригинального текста, подставленного авторами сайта, будет любой, указанный спамером. А оригинал будет смещен в конец сообщения, как это сделано в нашем примере выше.
В сочетании со вторым рассмотренным примером e-mail инъекции, можно разослать таким хитрым способом любые сообщения большому количеству народа. Для этого достаточно подкорректировать ранее рассмотренный пример таким образом:
[email protected]%0ASubject:Testing%0ABCC:[email protected]%0A Content-Type:multipart/mixed;%20boundary="part1";%0A-part1%0A Content-Type:text/html%0A%0AТестовый%20Текст.%0A--part1-
Письмо будет сформировано таким же образом, как и в примере выше. Однако оно будет отправлено еще одному получателю, указанному в заголовке BCC - [email protected]. А их может быть указано очень много.
Вот так довольно-таки легко можно воспользоваться брешью в защите web-сайта в своих целях. Что и делают нехорошие люди, о чем свидетельствуют, например, письма, приходящие мне на почту. Анализ заголовков показал, что это и есть та самая E-mail Injection. Собственно, поэтому я и решил написать эту статью. Чем меньше будет уязвимых сайтов, тем меньше будет поток спама. Поэтому предлагаю рассмотреть способы защиты web-сайта от инъекций подобного рода.
Четыре эшелона обороны
Способов защититься от подобной атаки довольно много, некоторые из них очень даже просты в реализации. Но, несмотря на это, мало кто заботится о безопасности. Я рассмотрю несколько самых актуальных и действующих алгоритмов. Советую защитить свой сайт одним из них, если у вас есть форма обратной связи, или что-нибудь, позволяющее отправлять письмо.
Задача защиты от e-mail injection сводится к фильтрации введенных данных ("золотое правило" безопасности), а точнее - проверке на присутствие переносов строк (\r\n). Реализовать это можно по-разному:
1) С помощью регулярных выражений (Regex). Код проверки очень прост:
<?php $from = $_POST["sender"]; if (eregi("(\r|\n)", $from)) { die("Неверно заполнены поля формы!"); } ?>
Проверять таким способом надо все поля: тема, отправитель и прочие.
2) С помощью специальных классов для PHP. Это Zend_Mail, PEAR Mail и Swift Mailer. Все они в обязательном порядке проверяют указанные данные на попытку произвести инъекцию. Найти их в Интернете не составит труда, поэтому ссылки я приводить не буду.
3) Установить mod_security на сервер. Для проверки и защиты от инъекции потребуется настроить его на фильтрацию фраз "bcc", "to" и "cc" в POST и GET запросах. Для этого надо создать следующее правило в настройках mod_security:
SecFilterSelective ARGS_VALUES "\n[[:space:]]*(to|bcc|cc)[[:space:]]*:.*@"
4) Давать возможность заполнить только текст письма. Это самый простой способ и один из самых эффективных. Где же указать email для обратной связи с отправителем? Ну пусть укажет его в теле письма. Все гениальное - просто :).
Заключение
Вот мы и обогатили наш багаж знаний еще одной уязвимостью современных web-проектов. Не забывайте проверять все входящие данные, будь то SQL-запрос или данные об отправителе письма на предмет посторонних символов. На этом я закончу свою статью, а вам пожелаю удачи и поменьше спама.
Никита БУЛАЙ,
[email protected],
SASecurity gr.
Горячие темы