In Savane v3.12 and prior, a lack of validation on the file_id
parameter when deleting a file from /bugs/index.php
leads to an Insecure Direct Object Reference (IDOR) vulnerability that can cause an authenticated administrator of a group with a bug tracker to arbitrarily delete file attachments of any bug tracker, leading to a lack of availability of these files. Since the file IDs increment with each new upload, it is possible to create a script that iteratively deletes all file attachments on the server by file_id
.
CWE Classification: CWE-639: Authorization Bypass Through User-Controlled Key
Reported By: Ally Petitt
Affected Product: Savane
Affected Versions: 3.12 and prior
The function responsible for deleting file attachments on bug trackers is trackers_data_delete_file()
, which is defined in the code block below.
frontend/php/include/trackers/data.php:2417
function trackers_data_delete_file ($group_id, $item_id, $file_id)
{
global $sys_trackers_attachments_dir;
# Make sure the attachment belongs to the group.
$res = db_execute ("
SELECT bug_id from " . ARTIFACT . " WHERE bug_id = ? AND group_id = ?",
[$item_id, $group_id]
);
if (db_numrows ($res) <= 0)
{
# TRANSLATORS: the argument is item id (a number).
$msg = sprintf (
_("Item #%s doesn't belong to project"), $item_id
);
fb ($msg, 1);
return;
}
$result = false;
# Delete the attachment.
if (unlink ("$sys_trackers_attachments_dir/$file_id"))
$result = db_execute ("
DELETE FROM trackers_file WHERE item_id = ? AND file_id = ?",
[$item_id, $file_id]
);
The function begins with a SQL query to verify that the group that the bug ID specified in item_id
is in the group that the attacker is a part of, known as the $group_id
. The function fails to check whether the file_id
is part of the group as well, meaning that as long as the item_id
cooresponds to a valid bug in the attacker's group, the attacker can modify the file_id
to point to any file within the upload directory /var/lib/savane/trackers_attachments
.
Additionally, this function is only reachable for bug tracker admins.
frontend/php/bugs/index.php:586
case 'delete_file':
# Remove an attached file.
if ($is_trackeradmin)
{
trackers_data_delete_file($group_id, $item_id, $item_file_id);
# Unset previous settings and return to the item.
$depends_search = $reassign_change_project_search = $add_cc
= $input_file = $changed = $vfl = $details = null;
include '../include/trackers_run/mod.php';
}
else
exit_permission_denied ();
break;
These steps demonstrate deleting one file that is unauthorized, however, note that an attacker could automate the deletion of all files by their ID since they are predictable.
- Have an account that is an admin of a group with a bugtracker (attacker account).
- With a separate user account (victim), upload a file attachment in a bug report to a group that the attacker is not an admin of. A sample of the subsequent upload directory is as follows where the file
40231
was uploaded by the victim:
root@60ae93fe131f:/var/lib/savane/trackers_attachments# ls
40226 40227 40230 40231
-
Visit the homepage of the group that the attacker is an admin of. Then, visit Bugs > Browse and note a valid Item ID on the leftmost column of the table. This ID will be used in the next step.
-
As the attacker, make a get request to the path /bugs/index.php?func=delete_file&item_id=<ATTACKER_ITEM_ID>&item_file_id=<FILE_ID_TO_DELETE>.
In my case, this looks like http://172.17.0.2:7890/bugs/index.php?func=delete_file&item_id=50697&item_file_id=40231.
-
Verify that the victim’s file (from a group the attacker doesn’t have privileges on) has been deleted. For example:
root@60ae93fe131f:/var/lib/savane/trackers_attachments# ls
40226 40227 40230
Upgrade to Savane version 3.13 or higher. The patch can be found here.