CVE-2018-12420: Use of a Broken or Risky Cryptographic Algorithm (CWE-327)
value: IceHrm before 23.0.1.OS has a risky usage of a hashed password in a request.
CWE description: The product uses a broken or risky cryptographic algorithm or protocol.
CVSS v3 base score: 7.5
Published: 2018-06-14T21:29Z
Repository: https://github.com/gamonoid/icehrm
Language: PHP
Files changed: core/header.php, core/login.php, core/src/Utils/SessionUtils.php
Commit date: 2018-06-14 03:40:21 +0200
Commit message: Critical security issue - fix password hash

Diff: diff --git a/core/header.php b/core/header.php
index d2ded4d4..64dbf4fc 100644
--- a/core/header.php
+++ b/core/header.php
@@ -23,13 +23,13 @@ Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilin
 if (!defined('MODULE_NAME')) {
     define('MODULE_NAME', $moduleName);
 }
 include 'includes.inc.php';
 
-if(empty($user)){
-    $actualLink = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
-    header("Location:".CLIENT_BASE_URL."login.php?next=".\Base64Url\Base64Url::encode($actualLink));
+if(empty($user) || empty($user->email)){
+    $actualLinkArray = explode('/',$_SERVER['REQUEST_URI']);
+    header("Location:".CLIENT_BASE_URL."login.php?next=".\Base64Url\Base64Url::encode($actualLinkArray[count($actualLinkArray) - 1]));
     exit();
 }
 
 if(empty($user->default_module)){
     if($user->user_level == "Admin"){
diff --git a/core/login.com.inc.php b/core/login.com.inc.php
deleted file mode 100644
index acb6c354..00000000
--- a/core/login.com.inc.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-?>
diff --git a/core/login.php b/core/login.php
index f8e02609..dc999eae 100644
--- a/core/login.php
+++ b/core/login.php
@@ -7,23 +7,24 @@ include("server.includes.inc.php");
 if (isset($_REQUEST['logout'])) {
     \Utils\SessionUtils::unsetClientSession();
     $_COOKIE['icehrmLF'] = '';
     $user = null;
 }
-
-if (empty($user)) {
+$hashedPwd = null;
+if (empty($user) || empty($user->email)) {
 	if (!isset($_REQUEST['f']) && isset($_COOKIE['icehrmLF'])
 		&& $_REQUEST['login'] != 'no' && !isset($_REQUEST['username'])) {
 		$tempUser = new \Users\Common\Model\User();
 		$tempUser->Load("login_hash = ?", array($_COOKIE['icehrmLF']));
 
 		if (!empty($tempUser->id) &&
 			sha1($tempUser->email."_".$tempUser->password) == $_COOKIE['icehrmLF']) {
 			$_REQUEST['username'] = $tempUser->username;
 			$_REQUEST['password'] = $tempUser->password;
-			$_REQUEST['hashedPwd'] = $tempUser->password;
+			$hashedPwd = $tempUser->password;
 			$_REQUEST['remember'] = true;
+            $cookieLogin = true;
 		}
 	}
 
 	if (!empty($_REQUEST['username']) && !empty($_REQUEST['password'])) {
 		$suser = null;
@@ -45,26 +46,37 @@ if (empty($user)) {
 					$ssoUserLoaded = true;
 				}
 			}
 		}
 
-		if (!isset($_REQUEST['hashedPwd'])) {
-			$_REQUEST['hashedPwd'] = md5($_REQUEST['password']);
+		if (!isset($hashedPwd)) {
+			$hashedPwd = md5($_REQUEST['password']);
 		}
 
-
-		include 'login.com.inc.php';
-
 		if (empty($suser)) {
 			$suser = new \Users\Common\Model\User();
 			$suser->Load(
 				"(username = ? or email = ?) and password = ?",
-				array($_REQUEST['username'],$_REQUEST['username'],$_REQUEST['hashedPwd'])
+				array($_REQUEST['username'], $_REQUEST['username'], $hashedPwd)
 			);
 		}
 
-		if ($suser->password == $_REQUEST['hashedPwd'] || $ssoUserLoaded) {
+		if (empty($suser->username) || empty($suser->email)) {
+            $next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:'';
+            header("Location:".CLIENT_BASE_URL."login.php?f=1".$next);
+            exit();
+        }
+
+        $loginCsrf = \Utils\SessionUtils::getSessionObject('csrf-login');
+
+        if (!$cookieLogin && ($_REQUEST['csrf'] != $loginCsrf || empty($_REQUEST['csrf']))) {
+            $next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:'';
+            header("Location:".CLIENT_BASE_URL."login.php?f=1".$next);
+            exit();
+        }
+
+		if ($suser->password === $hashedPwd || $ssoUserLoaded) {
 			$user = $suser;
 			\Utils\SessionUtils::saveSessionObject('user', $user);
 			$suser->last_login = date("Y-m-d H:i:s");
 			$suser->Save();
 
@@ -86,11 +98,11 @@ if (empty($user)) {
 			if (!isset($_REQUEST['remember'])) {
 				setcookie('icehrmLF');
 			}
 
 			if (!empty($_REQUEST['next']) && !empty(($loginRedirect = \Base64Url\Base64Url::decode($_REQUEST['next'])))) {
-			    header("Location:" . $loginRedirect);
+			    header("Location:" . CLIENT_BASE_URL.$loginRedirect);
 			    exit();
             } else {
 				if ($user->user_level == "Admin") {
 					if (\Utils\SessionUtils::getSessionObject('account_locked') == "1") {
 						header("Location:".CLIENT_BASE_URL."?g=admin&n=billing&m=admin_System");
@@ -338,10 +350,11 @@ $logoFileUrl = \Classes\UIManager::getInstance()->getCompanyLogoUrl();
 			<div class="login-form">
 				<h2><img src="<?=$logoFileUrl?>"/></h2>
 				<?php if (!isset($_REQUEST['cp'])) {?>
 					<form id="loginForm" action="login.php" method="POST">
                         <input type="hidden" id="next" name="next" value="<?=$_REQUEST['next']?>"/>
+                        <input type="hidden" id="csrf" name="csrf" value="<?=$csrfToken?>"/>
 						<fieldset>
 							<div class="clearfix">
 								<div class="input-prepend">
 									<span class="add-on"><i class="icon-user"></i></span>
 									<input class="span2" type="text" id="username" name="username" placeholder="Username">
diff --git a/core/src/Utils/SessionUtils.php b/core/src/Utils/SessionUtils.php
index b3b81da1..0ac4162b 100644
--- a/core/src/Utils/SessionUtils.php
+++ b/core/src/Utils/SessionUtils.php
@@ -26,11 +26,12 @@ class SessionUtils
     public static function unsetClientSession()
     {
         $names = [
             "user",
             "modulePath",
-            "admin_current_profile"
+            "admin_current_profile",
+            "csrf-login"
         ];
         session_start();
         setcookie('icehrmLF', '');
         foreach ($names as $name) {
             unset($_SESSION[$name.CLIENT_NAME]);

Vulnerable code: if(empty($user)){
    $actualLink = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
    header("Location:".CLIENT_BASE_URL."login.php?next=".\Base64Url\Base64Url::encode($actualLink));
<?php
?>

if (empty($user)) {
			$_REQUEST['hashedPwd'] = $tempUser->password;
		if (!isset($_REQUEST['hashedPwd'])) {
			$_REQUEST['hashedPwd'] = md5($_REQUEST['password']);

		include 'login.com.inc.php';

				array($_REQUEST['username'],$_REQUEST['username'],$_REQUEST['hashedPwd'])
		if ($suser->password == $_REQUEST['hashedPwd'] || $ssoUserLoaded) {
			    header("Location:" . $loginRedirect);
            "admin_current_profile"
Fixed code: if(empty($user) || empty($user->email)){
    $actualLinkArray = explode('/',$_SERVER['REQUEST_URI']);
    header("Location:".CLIENT_BASE_URL."login.php?next=".\Base64Url\Base64Url::encode($actualLinkArray[count($actualLinkArray) - 1]));
$hashedPwd = null;
if (empty($user) || empty($user->email)) {
			$hashedPwd = $tempUser->password;
            $cookieLogin = true;
		if (!isset($hashedPwd)) {
			$hashedPwd = md5($_REQUEST['password']);
				array($_REQUEST['username'], $_REQUEST['username'], $hashedPwd)
		if (empty($suser->username) || empty($suser->email)) {
            $next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:'';
            header("Location:".CLIENT_BASE_URL."login.php?f=1".$next);
            exit();
        }

        $loginCsrf = \Utils\SessionUtils::getSessionObject('csrf-login');

        if (!$cookieLogin && ($_REQUEST['csrf'] != $loginCsrf || empty($_REQUEST['csrf']))) {
            $next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:'';
            header("Location:".CLIENT_BASE_URL."login.php?f=1".$next);
            exit();
        }

		if ($suser->password === $hashedPwd || $ssoUserLoaded) {
			    header("Location:" . CLIENT_BASE_URL.$loginRedirect);
                        <input type="hidden" id="csrf" name="csrf" value="<?=$csrfToken?>"/>
            "admin_current_profile",
            "csrf-login"