✔Удаленное удаление. Как захватить контроль над WordPress, заставив его стереть файл - «Новости»
Содержание статьи
В WordPress, самой популярной в мире системе публикации, была обнаружена серьезная уязвимость. Она позволяет в пару запросов удалить любой файл, доступный для записи пользователю, от которого работает PHP, а затем получить контроль над сайтом. В этой статье мы разберемся с причинами и посмотрим, как работает эксплуатация.Баг был обнаружен еще 20 ноября 2017 года исследователем Славко Михайльоски Slavco Mihajloski из RIPS Tech, но вплоть до версии 4.9.7, которая вышла 5 июня 2018 года, проблема оставалась незапатченной. То есть на протяжении семи месяцев она представляла серьезную угрозу для безопасности на огромном количестве сайтов по всему миру и на многих из них продолжает представлять.
Стенд
Чтобы разобрать уязвимость, нам сначала понадобится уязвимый WordPress. Первым делом ставим контейнер с базой данных.
$ docker run -d --rm -e MYSQL_USER="wpdel" -e MYSQL_PASSWORD="4hicmMRyUq" -e MYSQL_DATABASE="wpdel" --name=mysql --hostname=mysql mysql/mysql-server
[/code]
Теперь контейнер, на который поставим веб-сервер. На нем будет располагаться WordPress.
$ docker run -it --rm -p80:80 --name=wpdel --hostname=wpdel --link=mysql debian /bin/bash
[/code]
Установим все нужные пакеты и расширения PHP.
$ apt-get update && apt-get install -y apache2 php php7.0-mysqli php-gd nano wget
[/code]
Уязвима версия CMS под номером 4.9.6, ее и скачаем.
$ cd /tmp && wget https://wordpress.org/wordpress-4.9.6.tar.gz
$ tar xzf wordpress-4.9.6.tar.gz
$ rm -rf /var/www/html/* && mv wordpress/* /var/www/html/
$ chown -R www-dаta:www-data /var/www/html/
[/code]
Запускаем сервис apache2.
$ service apache2 start
[/code]
Теперь устанавливаем WordPress, используем наш MySQL-сервер в качестве БД.
Инсталляция WordPress 4.9.6
Уязвим механизм удаления загруженных файлов, поэтому для успешной эксплуатации юзер должен иметь привилегии на удаление медиа. Создадим такого пользователя.
Создание пользователя с привилегиями добавления медиафайлов в WordPress 4.9.6
Анализ уязвимости
В WordPress, как и в любой уважающей себя CMS, можно загружать произвольные файлы и встраивать их в публикуемые посты. Самый очевидный способ применения — это добавление фотографий. Если файл загруженной картинки больше установленных в настройках размеров, то для него создаются миниатюры (thumbnails). Самую мелкую из них можно увидеть при нажатии на кнопку редактирования картинки (в закладке медиа в разделе Thumbnail Settings).
Редактирование загруженной картинки в WordPress
Заглянем в файл
post.php
, где находится кусок кода, ответственный за редактирование любой записи в системе. Да, аттачи тоже считаются записями.
/wordpress/wp-admin/post.php
33: if ( $post_id )
34:
$post = get_post( $post_id );
...
62: switch($action) {
В переменной
$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
При его обработке исполняется следующий кусок кода:
062: switch($action) {
...
098: case 'edit':
099:
$editing = true;
...
122:
if ( ! empty( $_GET['get-post-lock'] ) ) {
123:
check_admin_referer( 'lock-post_' . $post_id );
124:
wp_set_post_lock( $post_id );
125:
wp_redirect( get_edit_post_link( $post_id, 'url' ) );
126:
exit();
127:
128:
129:
$post_type = $post->post_type;
130:
if ( 'post' == $post_type ) {
131:
$parent_file = "edit.php";
132:
$submenu_file = "edit.php";
133:
$post_new_file = "post-new.php";
134:
elseif ( 'attachment' == $post_type ) {
135:
$parent_file = 'upload.php';
136:
$submenu_file = 'upload.php';
137:
$post_new_file = 'media-new.php';
138:
else {
139:
if ( isset( $post_type_object ) && $post_type_object->show_in_menu && $post_type_object->show_in_menu !== true )
140:
$parent_file = $post_type_object->show_in_menu;
141:
else
142:
$parent_file = "edit.php?post_type=$post_type";
143:
$submenu_file = "edit.php?post_type=$post_type";
144:
$post_new_file = "post-new.php?post_type=$post_type";
145:
146:
...
174:
include( ABSPATH . 'wp-admin/edit-form-advanced.php' );
175:
176:
break;
Погуляв немного по этой ветке кода, можно обнаружить довольно любопытный экшен.
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
, которая расположилась чуть ниже в этом же файле.
Источник новости - google.com