В 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

Теперь контейнер, на который поставим веб-сервер. На нем будет располагаться WordPress.

$ docker run -it --rm -p80:80 --name=wpdel --hostname=wpdel --link=mysql debian /bin/bash

Установим все нужные пакеты и расширения PHP.

$ apt-get update && apt-get install -y apache2 php php7.0-mysqli php-gd nano wget

Уязвима версия 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-data:www-data /var/www/html/

Запускаем сервис apache2.

$ service apache2 start

Теперь устанавливаем WordPress, используем наш MySQL-сервер в качестве БД.

Инсталляция WordPress 4.9.6
Инсталляция WordPress 4.9.6

Уязвим механизм удаления загруженных файлов, поэтому для успешной эксплуатации юзер должен иметь привилегии на удаление медиа. Создадим такого пользователя.

Создание пользователя с привилегиями добавления медиафайлов в WordPress 4.9.6
Создание пользователя с привилегиями добавления медиафайлов в WordPress 4.9.6
 

Анализ уязвимости

В WordPress, как и в любой уважающей себя CMS, можно загружать произвольные файлы и встраивать их в публикуемые посты. Самый очевидный способ применения — это добавление фотографий. Если файл загруженной картинки больше установленных в настройках размеров, то для него создаются миниатюры (thumbnails). Самую мелкую из них можно увидеть при нажатии на кнопку редактирования картинки (в закладке медиа в разделе Thumbnail Settings).

Редактирование загруженной картинки в WordPress
Редактирование загруженной картинки в 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, которая расположилась чуть ниже в этом же файле.

Продолжение доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все материалы на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи один материал

Заинтересовала информация, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для материалов, опубликованных более двух месяцев назад.


Оставить мнение

Check Also

Пишем стилер. Как вытащить пароли Chrome и Firefox своими руками

Ты наверняка слышал о таком классе зловредных приложений, как стилеры. Их задача — вытащит…