CVE-2022-1177 (published 2022-03-30T11:15Z)

Accounting User Can Download Patient Reports in openemr in GitHub repository openemr/openemr prior to 6.1.0.

Severity: MEDIUM
CVSS v2 base score: 4.0 (AV:N/AC:L/Au:S/C:P/I:N/A:N)
CVSS v3 base score: 4.3, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N)

Weakness information:
cwe_id: CWE-863
cwe_name: Incorrect Authorization
description: The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. This allows attackers to bypass intended access restrictions.
extended_description: 
            Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
            When access control checks are incorrectly applied, users are able to access data or perform actions that they should not be allowed to perform. This can lead to a wide range of problems, including information exposures, denial of service, and arbitrary code execution.
         
         

Fix information:
repo_url: https://github.com/openemr/openemr
commit_details: repo_url: https://github.com/openemr/openemr
author: stephen waite
author_date: 2022-02-14 10:25:10-05:00
msg: limit access to reports for front and back office (#4893)

* add acl report check to custom report

* remove report and notes access for accountants and front office on install

* revert change to administrators

* adjust install and upgrade

* reorder case in shiftAcl

* add alter acls to template

* review fixes, thanks Brady!

* more review fixes
repository: repo_url: https://github.com/openemr/openemr
repo_name: openemr/openemr
description: The most popular open source electronic health records and medical practice management solution.
repo_language: PHP
owner: openemr
file_changes: filename: acl_upgrade.php
change_type: ModificationType.MODIFY
diff: @@ -816,13 +816,48 @@ if ($acl_version < $upgrade_acl) {
     $acl_version = $upgrade_acl;
 }
 
-
-/* This is a template for a new revision, when needed
 // Upgrade for acl_version 12
 $upgrade_acl = 12;
 if ($acl_version < $upgrade_acl) {
     echo "<B>UPGRADING ACCESS CONTROLS TO VERSION " . $upgrade_acl . ":</B></BR>";
 
+    //Collect the ACL ID numbers.
+    echo "<B>Checking to ensure all the proper ACL(access control list) are present:</B></BR>";
+    $accounting_view = AclExtended::getAclIdNumber('Accounting', 'view');
+    $frontoffice_view = AclExtended::getAclIdNumber('Front Office', 'view');
+    $frontoffice_write = AclExtended::getAclIdNumber('Front Office', 'write');
+
+    //Add new object Sections
+    echo "<BR/><B>Adding new object sections</B><BR/>";
+
+    //Add new Objects
+    echo "<BR/><B>Adding new objects</B><BR/>";
+
+    //Update already existing Objects
+    echo "<BR/><B>Upgrading objects</B><BR/>";
+
+    //Add new ACLs here (will return the ACL ID of newly created or already existant ACL)
+    // (will also place in the appropriate group and CREATE a new group if needed)
+    echo "<BR/><B>Adding ACLs(Access Control Lists) and groups</B><BR/>";
+
+    //Update the ACLs
+    echo "<BR/><B>Updating the ACLs(Access Control Lists)</B><BR/>";
+    AclExtended::shiftAcl($accounting_view, 'Accounting', 'patients', 'Patients', 'pat_rep', 'Patient Report', 'view');
+    AclExtended::shiftAcl($frontoffice_view, 'Front Office', 'patients', 'Patients', 'pat_rep', 'Patient Report', 'view');
+    AclExtended::shiftAcl($frontoffice_write, 'Front Office', 'patients', 'Patients', 'trans', 'Transactions (write,wsome optional)', 'write');
+    AclExtended::shiftAcl($frontoffice_write, 'Front Office', 'patients', 'Patients', 'notes', 'Patient Notes (write,wsome optional)', 'write');
+
+
+    //DONE with upgrading to this version
+    $acl_version = $upgrade_acl;
+}
+
+/* This is a template for a new revision, when needed
+// Upgrade for acl_version 13
+$upgrade_acl = 13;
+if ($acl_version < $upgrade_acl) {
+    echo "<B>UPGRADING ACCESS CONTROLS TO VERSION " . $upgrade_acl . ":</B></BR>";
+
     //Collect the ACL ID numbers.
     echo "<B>Checking to ensure all the proper ACL(access control list) are present:</B></BR>";
 

programming_language: PHP
filename: custom_report.php
change_type: ModificationType.MODIFY
diff: @@ -34,6 +34,10 @@ use OpenEMR\Core\Header;
 use OpenEMR\MedicalDevice\MedicalDevice;
 use OpenEMR\Services\FacilityService;
 
+if (!AclMain::aclCheckCore('patients', 'pat_rep')) {
+    die(xlt('Not authorized'));
+}
+
 $facilityService = new FacilityService();
 
 $staged_docs = array();

programming_language: PHP
filename: Installer.class.php
change_type: ModificationType.MODIFY
diff: @@ -975,7 +975,7 @@ $config = 1; /////////////
         //
         $gacl->add_acl(
             array(
-                'patients' => array('alert','pat_rep')
+                'patients' => array('alert')
             ),
             null,
             array($front),
@@ -1017,7 +1017,7 @@ $config = 1; /////////////
         // xl('Things that front office can read and partly modify')
         $gacl->add_acl(
             array(
-                'patients' => array('appt', 'demo', 'trans', 'notes'),
+                'patients' => array('appt', 'demo'),
                 'groups' => array('gcalendar')
             ),
             null,
@@ -1035,7 +1035,7 @@ $config = 1; /////////////
         //
         $gacl->add_acl(
             array(
-                'patients' => array('alert','pat_rep')
+                'patients' => array('alert')
             ),
             null,
             array($back),

programming_language: PHP
filename: AclExtended.php
change_type: ModificationType.MODIFY
diff: @@ -1019,6 +1019,43 @@ class AclExtended
         return;
     }
 
+
+    /**
+     * Shift the ACL, opposite of updateAcl()
+     * Tries to remove the object from a specific ACL if only one is found.
+     *
+     * @param  array   $array_acl_id_number   Array containing hopefully one element, which is an integer, and is identifier of acl to be updated.
+     * @param  string  $group_title           Title of group.
+     * @param  string  $object_section_name   Identifier of section
+     * @param  string  $object_section_title  Title of section
+     * @param  string  $object_name           Identifier of object
+     * @param  string  $object_title          Title of object
+     * @param  string  $acl_return_value      What the acl returns (string), usually 'write', 'addonly', 'wsome' or 'view'
+     */
+    public static function shiftAcl($array_acl_id_number, $group_title, $section_name, $section_title, $object_name, $object_title, $return_value)
+    {
+        $gacl = self::collectGaclApiObject();
+        $tmp_array = $gacl->search_acl($section_name, $object_name, false, false, $group_title, false, false, false, $return_value);
+        switch (count($tmp_array)) {
+            case 0:
+                echo "The '$object_title' object of the '$section_title' section is not found in the '$group_title' group '$return_value' ACL.</BR>";
+                break;
+            case 1:
+                $tmp_boolean = @$gacl->shift_acl($array_acl_id_number[0], null, null, null, null, array($section_name => array($object_name)));
+                if ($tmp_boolean) {
+                    echo "Successfully removed the '$object_title' object of the '$section_title' section into the '$group_title' group '$return_value' ACL.</BR>";
+                } else {
+                    echo "<B>ERROR</B>,unable to remove the '$object_title' object of the '$section_title' section into the '$group_title' group '$return_value' ACL.</BR>";
+                }
+                break;
+            default:
+                echo "<B>ERROR</B>, Multiple '$group_title' group '$return_value' ACLs with the '$object_title' object of the '$section_title' section are present.</BR>";
+                break;
+        }
+
+        return;
+    }
+
     /**
      * Update the provided array of ACOs that the designated group has permission for.
      * This is an array keyed on ACO section ID with values that are arrays keyed on ACO ID

programming_language: PHP
filename: GaclApi.php
change_type: ModificationType.MODIFY
diff: @@ -404,8 +404,9 @@ class GaclApi extends Gacl {
 			return false;
 		}
 
-		//Grab ACL data.
-		$acl_array = &$this->get_acl($acl_id);
+        //Grab ACL data.
+        $get_acl = $this->get_acl($acl_id);
+        $acl_array = &$get_acl;
 
 		//Append each object type seperately.
 		if (is_array($aro_array) AND count($aro_array) > 0) {
@@ -524,8 +525,9 @@ class GaclApi extends Gacl {
 			return false;
 		}
 
-		//Grab ACL data.
-		$acl_array = &$this->get_acl($acl_id);
+        //Grab ACL data.
+        $get_acl = $this->get_acl($acl_id);
+        $acl_array = &$get_acl;
 
 		//showarray($acl_array);
 		//Remove each object type seperately.
@@ -612,7 +614,7 @@ class GaclApi extends Gacl {
 			foreach ($aco_array as $aco_section_value => $aco_value_array) {
 				foreach ($aco_value_array as $aco_value) {
 					$this->debug_text("shift_acl(): ACO Section Value: $aco_section_value ACO VALUE: $aco_value");
-					$aco_key = array_search($aco_value, $acl_array['aco'][$aco_section_value]);
+					$aco_key = array_search($aco_value, ($acl_array['aco'][$aco_section_value] ?? []));
 
 					if ($aco_key !== FALSE) {
 						$this->debug_text("shift_acl(): Removing ACO. ($aco_key)");

programming_language: PHP
filename: version.php
change_type: ModificationType.MODIFY
diff: @@ -36,7 +36,7 @@ $v_database = 435;
 // controls is (subsequently the acl_upgrade.php script then is used to
 // upgrade and track this value)
 //
-$v_acl = 11;
+$v_acl = 12;
 
 // Version for JavaScript and stylesheet includes. Increment whenever a .js or .css file changes.
 // Also whenever you change a .js or .css file, make sure that all URLs referencing it

programming_language: PHP