CVE-2021-29436 (published 2021-04-13T20:15Z)

Anuko Time Tracker is an open source, web-based time tracking application written in PHP. In Time Tracker before version 1.19.27.5431 a Cross site request forgery (CSRF) vulnerability existed. The nature of CSRF is that a logged on user may be tricked by social engineering to click on an attacker-provided form that executes an unintended action such as changing user password. The vulnerability is fixed in Time Tracker version 1.19.27.5431. Upgrade is recommended. If upgrade is not practical, introduce ttMitigateCSRF() function in /WEB-INF/lib/common.php.lib using the latest available code and call it from ttAccessAllowed().

Severity: MEDIUM
CVSS v2 base score: 5.8 (AV:N/AC:M/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 8.1, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/anuko/timetracker
commit_details: repo_url: https://github.com/anuko/timetracker
author: Nik Okuntseff
author_date: 2021-04-11 21:57:58+00:00
msg: An attempt to mitigate cross site request forgery vulnerability.
repository: repo_url: https://github.com/anuko/timetracker
repo_name: anuko/timetracker
description: Simple, easy to use, open source time tracking system.
repo_language: PHP
owner: anuko
file_changes: filename: config.php.dist
change_type: ModificationType.MODIFY
diff: @@ -163,6 +163,11 @@ define('AUTH_MODULE', 'db');
 // define('DEBUG', false); // Note: enabling DEBUG breaks redirects as debug output is printed before setting redirect header. Do not enable on production systems.
 
 
+// HTTP_TARGET - defines http target for cross site request forgery protection.
+// It can be used when you access the application via a proxy.
+// define('HTTP_TARGET', 'localhost');
+
+
 // Group managers can set monthly work hour quota for years between the following  values.
 // define('MONTHLY_QUOTA_YEAR_START', 2010); // If nothing is specified, it falls back to 2015.
 // define('MONTHLY_QUOTA_YEAR_END', 2025);   // If nothing is specified, it falls back to 2030.

programming_language: PHP
filename: common.lib.php
change_type: ModificationType.MODIFY
diff: @@ -363,6 +363,10 @@ function ttAccessAllowed($required_right)
     exit();
   }
 
+  // Protection against cross site request forgery.
+  if (!ttMitigateCSRF())
+    return false;
+
   // Check IP restriction, if set.
   if ($user->allow_ip && !$user->can('override_allow_ip')) {
     $access_allowed = false;
@@ -388,6 +392,41 @@ function ttAccessAllowed($required_right)
   return false;
 }
 
+// ttMitigateCSRF verifies request headers in an attempt to block cross site request forgery.
+function ttMitigateCSRF() {
+  // No need to do anything for get requests.
+  global $request;
+  if ($request->isGet())
+    return true;
+
+  $origin = $_SERVER['HTTP_ORIGIN'];
+  if ($origin) {
+    $pos = strpos($origin, '//');
+    $origin = substr($origin, $pos+2); // Strip protocol.
+  }
+  if (!$origin) {
+    // Try using referer.
+    $origin = $_SERVER['HTTP_REFERER'];
+    if ($origin) {
+      $pos = strpos($origin, '//');
+      $origin = substr($origin, $pos+2); // Strip protocol.
+      $pos = strpos($origin, '/');
+      $origin = substr($origin, 0, $pos); // Leave host only.
+    }
+  }
+  error_log("origin: ".$origin);
+  $target = defined('HTTP_TARGET') ? HTTP_TARGET : $_SERVER['HTTP_HOST'];
+  error_log("target: ".$target);
+  if (strcmp($origin, $target)) {
+    error_log("Potential cross site request forgery. Origin: '$origin' does not match target: '$target'.");
+    return false; // Origin and target do not match,
+  }
+
+  // TODO: review and improve this function for custom ports.
+  return true;
+}
+
+
 // ttStartsWith functions checks if a string starts with a given substring.
 function ttStartsWith($string, $startString)
 {

programming_language: PHP
filename: initialize.php
change_type: ModificationType.MODIFY
diff: @@ -13,7 +13,7 @@ error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT); // & ~E_DEPRECATED);
 ini_set('display_errors', 'Off');
 
 // require_once('init_auth.php');
-define("APP_VERSION", "1.19.26.5430");
+define("APP_VERSION", "1.19.27.5431");
 define("APP_DIR", dirname(__FILE__));
 define("LIBRARY_DIR", APP_DIR."/WEB-INF/lib");
 define("TEMPLATE_DIR", APP_DIR."/WEB-INF/templates");

programming_language: PHP
repo_url: https://github.com/anuko/timetracker
commit_details: repo_url: https://github.com/anuko/timetracker
author: Nik Okuntseff
author_date: 2021-04-12 17:14:30+00:00
msg: Tested CSRF fix for custom ports - it's working, also removed unnecessary logging.
repository: repo_url: https://github.com/anuko/timetracker
repo_name: anuko/timetracker
description: Simple, easy to use, open source time tracking system.
repo_language: PHP
owner: anuko
file_changes: filename: config.php.dist
change_type: ModificationType.MODIFY
diff: @@ -165,7 +165,7 @@ define('AUTH_MODULE', 'db');
 
 // HTTP_TARGET - defines http target for cross site request forgery protection.
 // It can be used when you access the application via a proxy.
-// define('HTTP_TARGET', 'localhost');
+// define('HTTP_TARGET', 'localhost:8080');
 
 
 // Group managers can set monthly work hour quota for years between the following  values.

programming_language: PHP
filename: common.lib.php
change_type: ModificationType.MODIFY
diff: @@ -414,15 +414,12 @@ function ttMitigateCSRF() {
       $origin = substr($origin, 0, $pos); // Leave host only.
     }
   }
-  error_log("origin: ".$origin);
   $target = defined('HTTP_TARGET') ? HTTP_TARGET : $_SERVER['HTTP_HOST'];
-  error_log("target: ".$target);
   if (strcmp($origin, $target)) {
     error_log("Potential cross site request forgery. Origin: '$origin' does not match target: '$target'.");
-    return false; // Origin and target do not match,
+    return false; // Origin and target do not match.
   }
 
-  // TODO: review and improve this function for custom ports.
   return true;
 }
 

programming_language: PHP
filename: initialize.php
change_type: ModificationType.MODIFY
diff: @@ -13,7 +13,7 @@ error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT); // & ~E_DEPRECATED);
 ini_set('display_errors', 'Off');
 
 // require_once('init_auth.php');
-define("APP_VERSION", "1.19.27.5431");
+define("APP_VERSION", "1.19.27.5432");
 define("APP_DIR", dirname(__FILE__));
 define("LIBRARY_DIR", APP_DIR."/WEB-INF/lib");
 define("TEMPLATE_DIR", APP_DIR."/WEB-INF/templates");

programming_language: PHP