В WordPress, самой популярной в мире системе публикации, была обнаружена серьезная уязвимость. Она позволяет в пару запросов удалить любой файл, доступный для записи пользователю, от которого работает PHP, а затем получить контроль над сайтом. В этой статье мы разберемся с причинами и посмотрим, как работает эксплуатация.
Баг был обнаружен еще 20 ноября 2017 года исследователем Славко Михайльоски Slavco Mihajloski из RIPS Tech, но вплоть до версии 4.9.7, которая вышла 5 июня 2018 года, проблема оставалась незапатченной. То есть на протяжении семи месяцев она представляла серьезную угрозу для безопасности на огромном количестве сайтов по всему миру и на многих из них продолжает представлять.
Стенд
Чтобы разобрать уязвимость, нам сначала понадобится уязвимый WordPress. Первым делом ставим контейнер с базой данных.
Теперь устанавливаем WordPress, используем наш MySQL-сервер в качестве БД.
Инсталляция WordPress 4.9.6
Уязвим механизм удаления загруженных файлов, поэтому для успешной эксплуатации юзер должен иметь привилегии на удаление медиа. Создадим такого пользователя.
Создание пользователя с привилегиями добавления медиафайлов в WordPress 4.9.6
Анализ уязвимости
В WordPress, как и в любой уважающей себя CMS, можно загружать произвольные файлы и встраивать их в публикуемые посты. Самый очевидный способ применения — это добавление фотографий. Если файл загруженной картинки больше установленных в настройках размеров, то для него создаются миниатюры (thumbnails). Самую мелкую из них можно увидеть при нажатии на кнопку редактирования картинки (в закладке медиа в разделе Thumbnail Settings).
Редактирование загруженной картинки в WordPress
Заглянем в файл post.php, где находится кусок кода, ответственный за редактирование любой записи в системе. Да, аттачи тоже считаются записями.
В переменной $action находится действие из запроса, которое нужно выполнить. Оператор switch перенаправляет выполнение скрипта в нужную часть кода. Вот, к примеру, запрос на редактирование конкретной записи.
GET /wp-admin/post.php?post=25&action=edit HTTP/1.1
Host: wpdel.visualhack
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,bg;q=0.6,uk;q=0.5,hu;q=0.4
При его обработке исполняется следующий кусок кода:
Погуляв немного по этой ветке кода, можно обнаружить довольно любопытный экшен.
178: case 'editattachment':
179:
check_admin_referer('update-post_' . $post_id);
180:
181:
// Don’t let these be changed
182:
unset($_POST['guid']);
183:
$_POST['post_type'] = 'attachment';
184:
185:
// Update the thumbnail filename
186:
$newmeta = wp_get_attachment_metadata( $post_id, true );
187:
$newmeta['thumb'] = $_POST['thumb'];
188:
189:
wp_update_attachment_metadata( $post_id, $newmeta );
Особенно интересен раздел Update the thumbnail filename. Переменная $newmeta содержит метаданные записи с указанным id. Ключ thumb содержит путь до миниатюры, и его значение можно изменить с помощью параметра thumb в POST-запросе. Эти данные уходят в функцию wp_update_attachment_metadata, которая расположилась чуть ниже в этом же файле.