Skip to content

Commit

Permalink
Merge pull request #4373 from nilsteampassnet/vulnerability-api
Browse files Browse the repository at this point in the history
Vulnerability using API authorization with SQL Injection
  • Loading branch information
nilsteampassnet authored Sep 28, 2024
2 parents 67da6b2 + 166094b commit 5a0744f
Show file tree
Hide file tree
Showing 261 changed files with 38,657 additions and 270 deletions.
124 changes: 48 additions & 76 deletions api/Model/AuthModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

require_once API_ROOT_PATH . "/Model/Database.php";


class AuthModel extends Database
class AuthModel
{


Expand Down Expand Up @@ -65,69 +62,26 @@ public function getUserAuth(string $login, string $password, string $apikey): ar
'apikey' => 'trim|escape|strip_tags',
]
);
if (empty($inputData['login']) === true || empty($inputData['apikey']) === true) {
return ["error" => "Login failed.", "info" => "Empty entry"];
}

// Check apikey
if (empty($inputData['password']) === true) {
// case where it is a generic key
$apiInfo = $this->select("SELECT * FROM " . prefixTable('api') . " WHERE value='".$inputData['apikey']."' AND label='".$inputData['login']."'");
$apiInfo = $apiInfo[0];
if (WIP === true) {
if (isset($apiInfo['increment_id']) === false) {
return ["error" => "Login failed.", "info" => "apikey : Not valid"];
}

// Check if user is enabled
if ((int) $apiInfo['enabled'] === 0) {
return ["error" => "Login failed.", "info" => "User not allowed to use API"];
}

// Load config
$configManager = new ConfigManager();
$SETTINGS = $configManager->getAllSettings();

// Log user
logEvents($SETTINGS, 'api', 'user_connection', (string) $apiInfo['increment_id'], stripslashes($inputData['login']));
// Check apikey and credentials
if (empty($inputData['login']) === true || empty($inputData['apikey']) === true || empty($inputData['password']) === true) {
// case where it is a generic key
// Not allowed to use this API

// create JWT
return $this->createUserJWT(
$apiInfo['increment_id'],
$inputData['login'],
0,
'',
'',
'',
'',
'',
0,
0,
1,
0,
'',
$apiInfo['allowed_folders'],
$apiInfo['allowed_to_create'],
$apiInfo['allowed_to_read'],
$apiInfo['allowed_to_update'],
$apiInfo['allowed_to_delete'],
);
} else {
return ["error" => "Login failed.", "info" => "Not managed."];
}
return ["error" => "Login failed.", "info" => "User password is requested"];
} else {
// case where it is a user api key
// Check if user exists
$userInfoRes = $this->select(
$userInfo = DB::queryfirstrow(
"SELECT u.id, u.pw, u.login, u.admin, u.gestionnaire, u.can_manage_all_users, u.fonction_id, u.can_create_root_folder, u.public_key, u.private_key, u.personal_folder, u.fonction_id, u.groupes_visibles, u.groupes_interdits, a.value AS user_api_key, a.allowed_folders as user_api_allowed_folders, a.enabled, a.allowed_to_create, a.allowed_to_read, a.allowed_to_update, a.allowed_to_delete
FROM " . prefixTable('users') . " AS u
INNER JOIN " . prefixTable('api') . " AS a ON (a.user_id=u.id)
WHERE login='".$inputData['login']."'");
if (count($userInfoRes) === 0) {
WHERE login = %s",
$inputData['login']
);
if (DB::count() === 0) {
return ["error" => "Login failed.", "info" => "apikey : Not valid"];
}
$userInfoRes[0]['special'] = '';
$userInfo = $userInfoRes[0];

// Check if user is enabled
if ((int) $userInfo['enabled'] === 0) {
Expand All @@ -148,10 +102,13 @@ public function getUserAuth(string $login, string $password, string $apikey): ar

// Update user's key_tempo
$keyTempo = bin2hex(random_bytes(16));
$this->update(
"UPDATE " . prefixTable('users') . "
SET key_tempo='".$keyTempo."'
WHERE id=".$userInfo['id']
DB::update(
prefixTable('users'),
[
'key_tempo' => $keyTempo,
],
'id = %i',
$userInfo['id']
);

// get user folders list
Expand Down Expand Up @@ -288,11 +245,16 @@ private function buildUserFoldersList(array $userInfo): array
$restrictedItems = [];
$personalFolders = [];

$userFunctionId = str_replace(";", ",", $userInfo['fonction_id']);
$userFunctionId = explode(";", $userInfo['fonction_id']);

// Get folders from the roles
if (empty($userFunctionId) === false) {
$rows = $this->select("SELECT * FROM " . prefixTable('roles_values') . " WHERE role_id IN (".$userFunctionId.") AND type IN ('W', 'ND', 'NE', 'NDNE', 'R')");
if (count($userFunctionId) > 0) {
$rows = DB::query(
'SELECT *
FROM ' . prefixTable('roles_values') . '
WHERE role_id IN %li AND type IN ("W", "ND", "NE", "NDNE", "R")',
$userFunctionId
);
foreach ($rows as $record) {
if ($record['type'] === 'R') {
array_push($readOnlyFolders, $record['folder_id']);
Expand All @@ -313,20 +275,29 @@ private function buildUserFoldersList(array $userInfo): array

// Does this user is allowed to see other items
$inc = 0;
$rows = $this->select("SELECT id, id_tree FROM " . prefixTable('items') . " WHERE restricted_to LIKE '".$userInfo['id']."'".
(empty($userFunctionId) === false ? ' AND id_tree NOT IN ('.$userFunctionId.')' : ''));
$rows = DB::query(
'SELECT id, id_tree
FROM ' . prefixTable('items') . '
WHERE restricted_to LIKE %s'.
(count($userFunctionId) > 0 ? ' AND id_tree NOT IN %li' : ''),
$userInfo['id'],
count($userFunctionId) > 0 ? $userFunctionId : DB::sqleval('0')
);
foreach ($rows as $record) {
// Exclude restriction on item if folder is fully accessible
$restrictedFoldersForItems[$inc] = $record['id_tree'];
++$inc;
}

// Check for the users roles if some specific rights exist on items
$rows = $this->select("SELECT i.id_tree, r.item_id
FROM " . prefixTable('items') . " as i
INNER JOIN " . prefixTable('restriction_to_roles') . " as r ON (r.item_id=i.id)
WHERE ".(empty($userFunctionId) === false ? ' id_tree NOT IN ('.$userFunctionId.') AND ' : '')." i.id_tree != ''
ORDER BY i.id_tree ASC");
$rows = DB::query(
'SELECT i.id_tree, r.item_id
FROM ' . prefixTable('items') . ' AS i
INNER JOIN ' . prefixTable('restriction_to_roles') . ' AS r ON (r.item_id=i.id)
WHERE '.(count($userFunctionId) > 0 ? ' id_tree NOT IN %li AND ' : '').' i.id_tree != ""
ORDER BY i.id_tree ASC',
count($userFunctionId) > 0 ? $userFunctionId : DB::sqleval('0')
);
foreach ($rows as $record) {
$foldersLimited[$record['id_tree']][$inc] = $record['item_id'];
//array_push($foldersLimitedFull, $record['item_id']);
Expand All @@ -336,12 +307,13 @@ private function buildUserFoldersList(array $userInfo): array
}

// Add all personal folders
$rows = $this->select(
'SELECT id
$rows = DB::queryFirstRow(
'SELECT id
FROM ' . prefixTable('nested_tree') . '
WHERE title = '.$userInfo['id'].' AND personal_folder = 1'.
(empty($userFunctionId) === false ? ' AND id NOT IN ('.$userFunctionId.')' : '').
' LIMIT 0,1'
WHERE title = %i AND personal_folder = 1'.
(count($userFunctionId) > 0 ? ' AND id NOT IN %li' : ''),
$userInfo['id'],
count($userFunctionId) > 0 ? $userFunctionId : DB::sqleval('0')
);
if (empty($rows['id']) === false) {
array_push($personalFolders, $rows['id']);
Expand Down
94 changes: 0 additions & 94 deletions api/Model/Database.php

This file was deleted.

40 changes: 14 additions & 26 deletions api/Model/FolderModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@

use TeampassClasses\Language\Language;

require_once API_ROOT_PATH . "/Model/Database.php";
class FolderModel extends Database
class FolderModel
{
public function getFoldersInfo(array $foldersId): array
{
$rows = $this->select( "SELECT id, title FROM " . prefixTable('nested_tree') . " WHERE nlevel=1" );
// Get folders
$rows = DB::query(
'SELECT id, title
FROM ' . prefixTable('nested_tree') . '
WHERE nlevel = %i',
1
);

$ret = [];

Expand All @@ -62,7 +67,12 @@ public function getFoldersInfo(array $foldersId): array
private function getFoldersChildren(int $parentId, array $foldersId): array
{
$ret = [];
$childrens = $this->select('SELECT id, title FROM ' . prefixTable('nested_tree') . ' WHERE parent_id=' . $parentId);
$childrens = DB::query(
'SELECT id, title
FROM ' . prefixTable('nested_tree') . '
WHERE parent_id = %i',
$parentId
);

if ( count($childrens) > 0) {
foreach ($childrens as $children) {
Expand Down Expand Up @@ -174,28 +184,6 @@ public function createFolder(
];}

// Create folder
/*
require_once TEAMPASS_ROOT_PATH.'/sources/folders.functions.php';
$creationStatus = createNewFolder(
(string) $title,
(int) $parent_id,
(int) $complexity,
(int) $duration,
(int) $create_auth_without,
(int) $edit_auth_without,
(string) $icon,
(string) $icon_selected,
(string) $access_rights,
(int) $is_admin,
(array) $foldersId,
(int) $is_manager,
(int) $user_can_create_root_folder,
(int) $user_can_manage_all_users,
(int) $user_id,
(string) $user_roles
);
*/

require_once TEAMPASS_ROOT_PATH.'/sources/folders.class.php';
$lang = new Language();
$folderManager = new FolderManager($lang);
Expand Down
Loading

0 comments on commit 5a0744f

Please sign in to comment.