Содержание статьи
WARNING
Вся информация носит только ознакомительный характер. Ни автор, ни редакция не несут ответственности за ее ненадлежащее использование.
Уязвима на этот раз лишь одна версия WordPress — 4.6. Многие владельцы сайтов включают автоматическое обновление, что уменьшает масштабы проблемы до уровня единичных инсталляций. Плюс, несмотря на заверения Давида, что эксплоит работает без каких-либо телодвижений и на дефолтном конфиге Apache 2, это не так. По крайней мере, у меня не получилось повторить этого ни на Ubuntu, ни на CentOS, ни на Debian.
Дело тут в особенностях эксплуатации, которая подразумевает нехилые манипуляции с заголовком Host. Они включают в себя использование пробелов, скобок и прочих спецсимволов. Дефолтные конфигурации Apache, которые я протестировал (то есть те, что ставятся из репозиториев командой apt-get
или yum
), не разрешают этого делать и тут же ругаются ошибкой 400.
Немного покопавшись в документации индейца, я обнаружил опцию HttpProtocolOptions. Она отвечает за соответствие запросов различным RFC-спецификациям и по умолчанию работает в режиме Strict
, то есть «ругаться на все неподходящие запросы». Поэтому для продолжения наших манипуляций изменим ее значение на Unsafe
и пойдем дальше.
Моя прошлая статья про эксплуатацию уязвимости PHPMailer касалась непосредственно агента sendmail. Однако наткнуться в реальном мире на систему, где он используется как почтовый демон по умолчанию, довольно непросто. Почти во всех последних версиях современных дистрибутивов Linux (Ubuntu, Debian, CentOS) используются альтернативы вроде Exim и Postfix. И об эксплуатации Exim мы сегодня и поговорим.
Причины уязвимости
Начнем с причины уязвимости. Заглянем в pluggable.php
.
324: if ( !isset( $from_email ) ) {
325: // Get the site domain and get rid of www.
326: $sitename = strtolower( $_SERVER['SERVER_NAME'] );
327: if ( substr( $sitename, 0, 4 ) == 'www.' ) {
328: $sitename = substr( $sitename, 4 );
329: }
330:
331: $from_email = 'wordpress@' . $sitename;
332: }
...
352: $phpmailer->setFrom( $from_email, $from_name );
Как видишь, данные из переменной $_SERVER['SERVER_NAME']
используются для указания домена (строка 331) в адресе возврата письма (Return-Path
, ключ -f
).
/wp-includes/class-phpmailer.php
81: /**
82: * The Sender email (Return-Path) of the message.
83: * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
84: * @var string
85: */
86: public $Sender = '';
...
934: public function setFrom($address, $name = '', $auto = true)
935: {
...
952: if ($auto) {
953: if (empty($this->Sender)) {
954: $this->Sender = $address;
955: }
956: }
Сама переменная SERVER_NAME
берется из запроса, а точнее — из заголовка Host. Поэтому можно попытаться управлять аргументами, которые будут отправлены бинарнику sendmail вместе с ключом -f
.
/wp-includes/class-phpmailer.php
1344: protected function mailSend($header, $body)
...
1352: if (empty($this->Sender)) {
1353: $params = ' ';
1354: } else {
1355: $params = sprintf('-f%s', $this->Sender);
1356: }
...
1368: $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
/wp-includes/class-phpmailer.php
666: private function mailPassthru($to, $subject, $body, $header, $params)
667: {
...
677: $result = @mail($to, $subject, $body, $header, $params);
И тут мы сталкиваемся с первой проблемой — невозможностью использовать пробел для отделения параметров друг от друга. Причина в том, что перед отправкой функция validateAddress()
из библиотеки PHPMailer проверяет получившийся email на соответствие стандарту RFC 2822, а он, разумеется, запрещает использование символа пробела в доменном имени.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»