Full Report
ServiceNow is a business platform similar to Salesforce. It has data from HR, to employee management, to many other things. ServiceNow is mostly cloud hosted but there is a self-hosted version that's a 20GB jar file. ServiceNow has a ton of functionality. To better understand the vulnerability, the author puts out a list of things to know and goes through the routing of the app: Table: All service now data is stored in tables. From users to pages to configurations. There is a simple way to update tables thorugh the UI with an included ACL. Processors: Effectively, an API endpoint. A user can write code for their JavaScript engine Rhino to create custom endpoints. Since most setups are multi-tenent, there is a lot of sandboxing on it. UI Pages: UI pages come from XML templates by the Apache Jelly library. These allow custom UIs on the app. Executing custom code can be very hard to do. So, they started looking how this worked. They learned that there are multiple evaluations that occur - one for g and ${} then another for g2 and $[]. Double evaluation on templates is a known issue. In particular, if any content from stage 1 with the special tags gets into stage 2, then we have template injection. Within the system, there was also the tag. Within one of the default templates, they found that the title of the page was injectable! In particular, they had something similar to register_globals, which meant that it was controllable anywhere, including the login page. Sadly, a HTML santizier is ran over the page title, which could prevent the adding of arbitrary XML. While looking through the allowlist, they noticed that the style tag was allowed. From the context of the HTML parser, anything within the style is fine! But, this can still be processed in the rendering as XML later, allowing us to smuggle in payloads. Without mitigations for Jelly injection, this would have been game over. So, they took a deep dive into how the evaluation process worked. It works in two stages. First, the j: is bound to Jelly core and g: is bound to ServiceNow custom tags. Then,j2: and g2: are bound to the null namespace, making them passed over. Next, it changes j2 to use Jelly Core and g2 to us the custom tags from ServiceNow with the original ones set to null to make it run over only the second set of tags. With this, they tried creating their own namespace, which was rejected because Glide (Service Nows tags) can only be bound to g and g2. What about rebinding g from the null namespace TO the glide once again. Of course, another defense in depth measure was triggered to prevent this. However, it was a flimsy string match that was easy to bypass with using single quotes instead of double quotes! With that, OG glide tags are evaluated on the second pass, after our initial injection point. Arbitrary JavaScript execution from a user clicking on a malicious link is pretty hype! But, the tables that could be accessed from this was limited. So, they wanted a permission break on a hardened instance. They looked into the file reading process to see a denylist of locations that couldn't be accessed, such as database creds. The denylist was super solid and didn't seem possible to bypass by itself. However, this is when they had an idea something: "what if the processing for getBufferedReader() can mutate the path in some way?" It turned out that adding a .. into the middle of the path would be REMOVED when a clean up routine is done on the path. As a result, the denylist can be bypassed! Crazy that the normalization which is normally good for security actually caused the issue here. Once there, ServiceNow has a mechanism to run arbitrary code on the box, by design. With all of the permissions we now have, it's game over. I love the hurdles that were required to get over this! The mitigations were well thought out and strong but enough of a deep dive led to compromise with the double eval on the templates.
Analysis Summary
# Vulnerability: ServiceNow Template Injection and Path Traversal Chain
## CVE Details
- **CVE ID:** CVE-2024-4879, CVE-2024-5178, CVE-2024-5217
- **CVSS Score:** 9.8 (Critical)
- **CWE:** CWE-94 (Improper Control of Generation of Code - Template Injection), CWE-22 (Path Traversal)
## Affected Systems
- **Products:** ServiceNow Platform (Cloud-based and Self-hosted)
- **Versions:** Multiple versions across Vancouver and Utah releases. Specific patches address these; versions prior to the July 2024 security updates are vulnerable.
- **Configurations:** Systems utilizing UI Pages and Jelly templates; specifically those with publicly accessible login pages or instances connected to internal networks via MID Servers.
## Vulnerability Description
This exploit chain involves three distinct vulnerabilities:
1. **Jelly Template Injection (CVE-2024-4879):** The ServiceNow UI uses the Apache Jelly library for XML templates. The system performs "double evaluation" (two passes of rendering). By smuggling tags into a second pass via an injectable page title (which bypassed an HTML sanitizer using the `<style>` tag), attackers could rebind the "Glide" namespace using single quotes to bypass string-match defenses. This leads to arbitrary JavaScript execution in the Rhino engine.
2. **Path Traversal (CVE-2024-5178):** While exploring file access, researchers found that the `getBufferedReader()` function used a normalization routine that stripped `..` from paths. By strategically placing these characters, attackers could bypass a "solid" denylist of sensitive files (like database credentials).
3. **Administrative Command Injection (CVE-2024-5217):** Once database/administrative access is gained via the first two bugs, the platform's native ability to run code on MID Servers is leveraged to achieve full Remote Code Execution (RCE) on the underlying infrastructure.
## Exploitation
- **Status:** PoC available; exploited in the wild (reported via threat intelligence following the July 11 discovery).
- **Complexity:** High (requires chaining specific bypasses for double evaluation and path normalization).
- **Attack Vector:** Network (Unauthenticated)
## Impact
- **Confidentiality:** Total (Access to all ServiceNow data, including HR and employee records).
- **Integrity:** Total (Ability to modify any table or configuration).
- **Availability:** Total (Potential for full system takeover and execution of code on internal MID servers).
## Remediation
### Patches
ServiceNow has released patches for all supported versions. Users should update to at least:
- Vancouver Patch 6 Hotfix 11, Patch 7 Hotfix 3b, Patch 8 Hotfix 3, Patch 9, or Patch 10.
- Utah Patch 10f Hotfix 3.
- Washington DC Patch 1 Hotfix 2b, Patch 2 Hotfix 2, Patch 3 Hotfix 1, or Patch 4.
### Workarounds
- No official functional workaround is a substitute for patching.
- Restrict access to the ServiceNow instance via IP allowlisting where possible to mitigate external exposure.
## Detection
- **Indicators of Compromise:** Monitor logs for unauthorized access to `sys_users` or `sys_properties` tables. Check for unusual XML/Jelly tags within web logs, specifically those containing `j2:` or `g2:` namespaces or attempts to rebind namespaces using single quotes.
- **Detection methods and tools:** Review ServiceNow Transaction Logs for large exports of sensitive tables or unusual calls to `getBufferedReader`.
## References
- **Vendor Advisory:** hxxps://support.servicenow[.]com/kb?id=kb_article_view&sysparm_article=KB1644954
- **Researcher Original Post:** hxxps://www.assetnote[.]io/resources/research/chaining-three-bugs-to-access-all-your-servicenow-data
- **NVD:** hxxps://nvd.nist[.]gov/vuln/detail/CVE-2024-4879