CVE-2022-31890: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') (CWE-89)
value: SQL Injection vulnerability in audit/class.audit.php in osTicket osTicket-plugins before commit a7842d494889fd5533d13deb3c6a7789768795ae via the order parameter to the getOrder function.
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.
CVSS v3 base score: 9.8
Published: 2023-04-05T22:15Z
Repository: https://github.com/osTicket/osTicket-plugins
Language: PHP
Files changed: audit/class.audit.php
Commit date: 2022-04-21 18:52:18 +0000
Commit message: security: Audit Log Injection

This mitigates a vulnerability discovered by the AppSec Research Team at
Checkmarx where it's possible to perform injection via Audit Log plugin.
This is due to passing the `order` URL param directly to the select query.
This refactors the `getOrder()` method to only return predefined sort orders
to prevent using user-input.

Diff: diff --git a/audit/class.audit.php b/audit/class.audit.php
index 3b0c221..f6ca66d 100644
--- a/audit/class.audit.php
+++ b/audit/class.audit.php
@@ -461,26 +461,30 @@ class AuditEntry extends VerySimpleModel {
 
       return $qwhere;
     }
 
     static function getOrder($order) {
-        if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) {
-            $order=$orderWays[strtoupper($_REQUEST['order'])];
-        }
-        $order=$order?$order:'DESC';
+        $or = null;
+        $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
+
+        if ($order && $orderWays[strtoupper($order)])
+            $or = $orderWays[strtoupper($order)];
+        elseif($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
+            $or = $orderWays[strtoupper($_REQUEST['order'])];
+
+        $or = $or ? $or : 'DESC';
 
-        return $order;
+        return $or;
     }
 
     static function getQuery($qs, $objectId, $pageNav, $export, $type='') {
       $qselect = 'SELECT audit.* ';
       $qfrom=' FROM '.AUDIT_TABLE.' audit ';
       $qwhere =self::getQwhere($objectId, false, $type);
 
       $sortOptions=array('id'=>'audit.id', 'object_id'=>'audit.object_id', 'state'=>'audit.state','type'=>'audit.object_type','ip'=>'audit.ip'
                           ,'timestamp'=>'audit.timestamp');
-      $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
       $sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'timestamp';
       //Sorting options...
       if($sort && $sortOptions[$sort]) {
           $order_column =$sortOptions[$sort];
       }

Vulnerable code:         if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) {
            $order=$orderWays[strtoupper($_REQUEST['order'])];
        }
        $order=$order?$order:'DESC';
        return $order;
      $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
Fixed code:         $or = null;
        $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');

        if ($order && $orderWays[strtoupper($order)])
            $or = $orderWays[strtoupper($order)];
        elseif($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
            $or = $orderWays[strtoupper($_REQUEST['order'])];

        $or = $or ? $or : 'DESC';
        return $or;