CVE-2014-5017: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: SQL injection vulnerability in CPDB in application/controllers/admin/participantsaction.php in LimeSurvey 2.05+ Build 140618 allows remote attackers to execute arbitrary SQL commands via the sidx parameter in a JSON request to admin/participants/sa/getParticipants_json, related to a search parameter.
CWE description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
Published: 2014-07-21T14:55Z
Repository: https://github.com/LimeSurvey/LimeSurvey
Language: PHP
Files changed: application/controllers/admin/participantsaction.php
Commit date: 2014-07-02 15:35:53 +0200
Commit message: Fixed issue: Search parameter vulnerability in CPDB

Diff: diff --git a/application/controllers/admin/participantsaction.php b/application/controllers/admin/participantsaction.php
index a679d70af..e6cef23fe 100644
--- a/application/controllers/admin/participantsaction.php
+++ b/application/controllers/admin/participantsaction.php
@@ -761,25 +761,26 @@ class participantsaction extends Survey_Common_Action
     /*
        * Sends the data in JSON format extracted from the database to be displayed using the jqGrid
     */
     function getParticipants_json($search = null)
     {
-        $page = Yii::app()->request->getPost('page');
-        $limit = Yii::app()->request->getPost('rows');
-        $limit = isset($limit) ? $limit : 50; //Stop division by zero errors
+        $page = (int) Yii::app()->request->getPost('page');
+        $limit = (int) Yii::app()->request->getPost('rows');
+        $limit = empty($limit) ? $limit : 50; //Stop division by zero errors
 
         $attid = ParticipantAttributeName::model()->getVisibleAttributes();
         $participantfields = array('participant_id', 'can_edit', 'firstname', 'lastname', 'email', 'blacklisted', 'survey', 'language', 'owner_uid');
         foreach ($attid as $key => $value)
         {
             array_push($participantfields, $value['attribute_id']);
         }
         $sidx = Yii::app()->request->getPost('sidx');
-        $sidx = !empty($sidx) ? $sidx : "lastname";
+        $sidx = in_array($sidx,$participantfields) ? $sidx : "lastname";
         $sord = Yii::app()->request->getPost('sord');
-        $sord = !empty($sord) ? $sord : "asc";
+        $sord = ($sord=='desc') ? 'desc' : 'asc';
         $order = $sidx. " ". $sord;
+                                                 
         
         $aData = new stdClass;
         
         //If super admin all the participants will be visible
         if (Permission::model()->hasGlobalPermission('superadmin','read'))

Vulnerable code:         $page = Yii::app()->request->getPost('page');
        $limit = Yii::app()->request->getPost('rows');
        $limit = isset($limit) ? $limit : 50; //Stop division by zero errors
        $sidx = !empty($sidx) ? $sidx : "lastname";
        $sord = !empty($sord) ? $sord : "asc";
Fixed code:         $page = (int) Yii::app()->request->getPost('page');
        $limit = (int) Yii::app()->request->getPost('rows');
        $limit = empty($limit) ? $limit : 50; //Stop division by zero errors
        $sidx = in_array($sidx,$participantfields) ? $sidx : "lastname";
        $sord = ($sord=='desc') ? 'desc' : 'asc';